From 9d2d13a3898f05f9e8189f99087198726d476e1b Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Tue, 27 Jul 2021 22:54:17 -0400 Subject: very rudimentary thread support --- components/channels.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 8 deletions(-) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index 3e7862b..956fee1 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -22,15 +22,20 @@ ChannelList::ChannelList() const auto cb = [this](const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column) { auto row = *m_model->get_iter(path); - if (row[m_columns.m_expanded]) { - m_view.collapse_row(path); - row[m_columns.m_expanded] = false; - } else { - m_view.expand_row(path, false); - row[m_columns.m_expanded] = true; + const auto type = row[m_columns.m_type]; + // text channels should not be allowed to be collapsed + // maybe they should be but it seems a little difficult to handle expansion to permit this + if (type != RenderType::TextChannel) { + if (row[m_columns.m_expanded]) { + m_view.collapse_row(path); + row[m_columns.m_expanded] = false; + } else { + m_view.expand_row(path, false); + row[m_columns.m_expanded] = true; + } } - if (row[m_columns.m_type] == RenderType::TextChannel || row[m_columns.m_type] == RenderType::DM) { + if (type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread) { m_signal_action_channel_item_select.emit(static_cast(row[m_columns.m_id])); } }; @@ -313,6 +318,28 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild) { } } + std::map> threads; + for (const auto &tmp : *guild.Threads) { + const auto thread = discord.GetChannel(tmp.ID); + if (thread.has_value()) + threads[*thread->ParentID].push_back(*thread); + } + const auto add_threads = [&](const ChannelData &channel, Gtk::TreeRow row) { + row[m_columns.m_expanded] = true; + + const auto it = threads.find(channel.ID); + if (it == threads.end()) return; + + for (const auto &thread : it->second) { + auto thread_row = *m_model->append(row.children()); + thread_row[m_columns.m_type] = RenderType::Thread; + thread_row[m_columns.m_id] = thread.ID; + thread_row[m_columns.m_name] = "- " + Glib::Markup::escape_text(*thread.Name); + thread_row[m_columns.m_sort] = thread.ID; + thread_row[m_columns.m_nsfw] = false; + } + }; + for (const auto &channel : orphan_channels) { auto channel_row = *m_model->append(guild_row.children()); channel_row[m_columns.m_type] = RenderType::TextChannel; @@ -320,6 +347,7 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild) { channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel.Name); channel_row[m_columns.m_sort] = *channel.Position + OrphanChannelSortOffset; channel_row[m_columns.m_nsfw] = channel.NSFW(); + add_threads(channel, channel_row); } for (const auto &[category_id, channels] : categories) { @@ -340,6 +368,7 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild) { channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel.Name); channel_row[m_columns.m_sort] = *channel.Position; channel_row[m_columns.m_nsfw] = channel.NSFW(); + add_threads(channel, channel_row); } } @@ -423,7 +452,7 @@ bool ChannelList::SelectionFunc(const Glib::RefPtr &model, const m_last_selected = m_model->get_path(row); auto type = (*m_model->get_iter(path))[m_columns.m_type]; - return type == RenderType::TextChannel || type == RenderType::DM; + return type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread; } void ChannelList::AddPrivateChannels() { @@ -614,6 +643,8 @@ void CellRendererChannels::get_preferred_width_vfunc(Gtk::Widget &widget, int &m return get_preferred_width_vfunc_category(widget, minimum_width, natural_width); case RenderType::TextChannel: return get_preferred_width_vfunc_channel(widget, minimum_width, natural_width); + case RenderType::Thread: + return get_preferred_width_vfunc_thread(widget, minimum_width, natural_width); case RenderType::DMHeader: return get_preferred_width_vfunc_dmheader(widget, minimum_width, natural_width); case RenderType::DM: @@ -629,6 +660,8 @@ void CellRendererChannels::get_preferred_width_for_height_vfunc(Gtk::Widget &wid return get_preferred_width_for_height_vfunc_category(widget, height, minimum_width, natural_width); case RenderType::TextChannel: return get_preferred_width_for_height_vfunc_channel(widget, height, minimum_width, natural_width); + case RenderType::Thread: + return get_preferred_width_for_height_vfunc_thread(widget, height, minimum_width, natural_width); case RenderType::DMHeader: return get_preferred_width_for_height_vfunc_dmheader(widget, height, minimum_width, natural_width); case RenderType::DM: @@ -644,6 +677,8 @@ void CellRendererChannels::get_preferred_height_vfunc(Gtk::Widget &widget, int & return get_preferred_height_vfunc_category(widget, minimum_height, natural_height); case RenderType::TextChannel: return get_preferred_height_vfunc_channel(widget, minimum_height, natural_height); + case RenderType::Thread: + return get_preferred_height_vfunc_thread(widget, minimum_height, natural_height); case RenderType::DMHeader: return get_preferred_height_vfunc_dmheader(widget, minimum_height, natural_height); case RenderType::DM: @@ -659,6 +694,8 @@ void CellRendererChannels::get_preferred_height_for_width_vfunc(Gtk::Widget &wid return get_preferred_height_for_width_vfunc_category(widget, width, minimum_height, natural_height); case RenderType::TextChannel: return get_preferred_height_for_width_vfunc_channel(widget, width, minimum_height, natural_height); + case RenderType::Thread: + return get_preferred_height_for_width_vfunc_thread(widget, width, minimum_height, natural_height); case RenderType::DMHeader: return get_preferred_height_for_width_vfunc_dmheader(widget, width, minimum_height, natural_height); case RenderType::DM: @@ -674,6 +711,8 @@ void CellRendererChannels::render_vfunc(const Cairo::RefPtr &cr, return render_vfunc_category(cr, widget, background_area, cell_area, flags); case RenderType::TextChannel: return render_vfunc_channel(cr, widget, background_area, cell_area, flags); + case RenderType::Thread: + return render_vfunc_thread(cr, widget, background_area, cell_area, flags); case RenderType::DMHeader: return render_vfunc_dmheader(cr, widget, background_area, cell_area, flags); case RenderType::DM: @@ -883,6 +922,37 @@ void CellRendererChannels::render_vfunc_channel(const Cairo::RefPtr &cr, Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, Gtk::CellRendererState flags) { + Gtk::Requisition minimum_size, natural_size; + m_renderer_text.get_preferred_size(widget, minimum_size, natural_size); + + const int text_x = background_area.get_x() + 26; + const int text_y = background_area.get_y() + background_area.get_height() / 2 - natural_size.height / 2; + const int text_w = natural_size.width; + const int text_h = natural_size.height; + + Gdk::Rectangle text_cell_area(text_x, text_y, text_w, text_h); + m_renderer_text.render(cr, widget, background_area, text_cell_area, flags); +} + // dm header void CellRendererChannels::get_preferred_width_vfunc_dmheader(Gtk::Widget &widget, int &minimum_width, int &natural_width) const { -- cgit v1.2.3 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 --- components/channels.cpp | 56 ++++++++++++++++++++++++++++++------------------- components/channels.hpp | 4 +++- discord/channel.cpp | 10 ++++++++- discord/channel.hpp | 18 +++++++++++++--- discord/discord.cpp | 18 +++++++++++++++- discord/discord.hpp | 6 +++++- discord/objects.cpp | 4 ++++ discord/objects.hpp | 12 +++++++++++ 8 files changed, 99 insertions(+), 29 deletions(-) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index 956fee1..a80cfd8 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -128,6 +128,7 @@ ChannelList::ChannelList() discord.signal_channel_delete().connect(sigc::mem_fun(*this, &ChannelList::UpdateRemoveChannel)); 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_guild_update().connect(sigc::mem_fun(*this, &ChannelList::UpdateGuild)); } @@ -211,32 +212,31 @@ void ChannelList::UpdateChannel(Snowflake id) { channel_row[m_columns.m_sort] = *channel->Position; } -void ChannelList::UpdateCreateChannel(Snowflake id) { - const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(id); - if (!channel.has_value()) return; - if (channel->Type == ChannelType::GUILD_CATEGORY) return (void)UpdateCreateChannelCategory(*channel); - if (channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM) return UpdateCreateDMChannel(*channel); - if (channel->Type != ChannelType::GUILD_TEXT && channel->Type != ChannelType::GUILD_NEWS) return; +void ChannelList::UpdateCreateChannel(const ChannelData &channel) { + ; + if (channel.Type == ChannelType::GUILD_CATEGORY) return (void)UpdateCreateChannelCategory(channel); + if (channel.Type == ChannelType::DM || channel.Type == ChannelType::GROUP_DM) return UpdateCreateDMChannel(channel); + if (channel.Type != ChannelType::GUILD_TEXT && channel.Type != ChannelType::GUILD_NEWS) return; Gtk::TreeRow channel_row; bool orphan; - if (channel->ParentID.has_value()) { + if (channel.ParentID.has_value()) { orphan = false; - auto iter = GetIteratorForChannelFromID(*channel->ParentID); + auto iter = GetIteratorForChannelFromID(*channel.ParentID); channel_row = *m_model->append(iter->children()); } else { orphan = true; - auto iter = GetIteratorForGuildFromID(*channel->GuildID); + auto iter = GetIteratorForGuildFromID(*channel.GuildID); channel_row = *m_model->append(iter->children()); } channel_row[m_columns.m_type] = RenderType::TextChannel; - channel_row[m_columns.m_id] = channel->ID; - channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel->Name); - channel_row[m_columns.m_nsfw] = channel->NSFW(); + channel_row[m_columns.m_id] = channel.ID; + channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel.Name); + channel_row[m_columns.m_nsfw] = channel.NSFW(); if (orphan) - channel_row[m_columns.m_sort] = *channel->Position + OrphanChannelSortOffset; + channel_row[m_columns.m_sort] = *channel.Position + OrphanChannelSortOffset; else - channel_row[m_columns.m_sort] = *channel->Position; + channel_row[m_columns.m_sort] = *channel.Position; } void ChannelList::UpdateGuild(Snowflake id) { @@ -265,6 +265,12 @@ void ChannelList::UpdateGuild(Snowflake id) { } } +void ChannelList::UpdateCreateThread(const ChannelData &channel) { + auto parent_row = GetIteratorForChannelFromID(*channel.ParentID); + if (parent_row) + CreateThreadRow(parent_row->children(), channel); +} + void ChannelList::SetActiveChannel(Snowflake id) { const auto channel_iter = GetIteratorForChannelFromID(id); if (channel_iter) { @@ -330,14 +336,8 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild) { const auto it = threads.find(channel.ID); if (it == threads.end()) return; - for (const auto &thread : it->second) { - auto thread_row = *m_model->append(row.children()); - thread_row[m_columns.m_type] = RenderType::Thread; - thread_row[m_columns.m_id] = thread.ID; - thread_row[m_columns.m_name] = "- " + Glib::Markup::escape_text(*thread.Name); - thread_row[m_columns.m_sort] = thread.ID; - thread_row[m_columns.m_nsfw] = false; - } + for (const auto &thread : it->second) + CreateThreadRow(row.children(), thread); }; for (const auto &channel : orphan_channels) { @@ -389,6 +389,18 @@ Gtk::TreeModel::iterator ChannelList::UpdateCreateChannelCategory(const ChannelD return cat_row; } +Gtk::TreeModel::iterator ChannelList::CreateThreadRow(const Gtk::TreeNodeChildren &children, const ChannelData &channel) { + auto thread_iter = m_model->append(children); + auto thread_row = *thread_iter; + thread_row[m_columns.m_type] = RenderType::Thread; + thread_row[m_columns.m_id] = channel.ID; + thread_row[m_columns.m_name] = "- " + Glib::Markup::escape_text(*channel.Name); + thread_row[m_columns.m_sort] = channel.ID; + thread_row[m_columns.m_nsfw] = false; + + return thread_iter; +} + void ChannelList::UpdateChannelCategory(const ChannelData &channel) { auto iter = GetIteratorForChannelFromID(channel.ID); if (!iter) return; diff --git a/components/channels.hpp b/components/channels.hpp index 3b81cab..bdc3e84 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -139,7 +139,8 @@ protected: void UpdateRemoveGuild(Snowflake id); void UpdateRemoveChannel(Snowflake id); void UpdateChannel(Snowflake id); - void UpdateCreateChannel(Snowflake id); + void UpdateCreateChannel(const ChannelData &channel); + void UpdateCreateThread(const ChannelData &channel); void UpdateGuild(Snowflake id); Gtk::TreeView m_view; @@ -168,6 +169,7 @@ protected: Gtk::TreeModel::iterator AddGuild(const GuildData &guild); Gtk::TreeModel::iterator UpdateCreateChannelCategory(const ChannelData &channel); + Gtk::TreeModel::iterator CreateThreadRow(const Gtk::TreeNodeChildren &children, const ChannelData &channel); void UpdateChannelCategory(const ChannelData &channel); diff --git a/discord/channel.cpp b/discord/channel.cpp index e5dfb06..685cc72 100644 --- a/discord/channel.cpp +++ b/discord/channel.cpp @@ -1,13 +1,20 @@ #include "../abaddon.hpp" #include "channel.hpp" -void from_json(const nlohmann::json &j, ThreadMetadata &m) { +void from_json(const nlohmann::json &j, ThreadMetadataData &m) { JS_D("archived", m.IsArchived); JS_D("auto_archive_duration", m.AutoArchiveDuration); JS_D("archive_timestamp", m.ArchiveTimestamp); JS_O("locked", m.IsLocked); } +void from_json(const nlohmann::json &j, ThreadMemberObject &m) { + JS_O("id", m.ThreadID); + JS_O("user_id", m.ThreadID); + JS_D("join_timestamp", m.JoinTimestamp); + JS_D("flags", m.Flags); +} + void from_json(const nlohmann::json &j, ChannelData &m) { JS_D("id", m.ID); JS_D("type", m.Type); @@ -29,6 +36,7 @@ void from_json(const nlohmann::json &j, ChannelData &m) { JS_ON("parent_id", m.ParentID); JS_ON("last_pin_timestamp", m.LastPinTimestamp); JS_O("thread_metadata", m.ThreadMetadata); + JS_O("member", m.ThreadMember); } void ChannelData::update_from_json(const nlohmann::json &j) { diff --git a/discord/channel.hpp b/discord/channel.hpp index d262ddf..606686d 100644 --- a/discord/channel.hpp +++ b/discord/channel.hpp @@ -38,13 +38,24 @@ constexpr const char *GetStagePrivacyDisplayString(StagePrivacy e) { } } -struct ThreadMetadata { +// should be moved somewhere? + +struct ThreadMetadataData { bool IsArchived; int AutoArchiveDuration; std::string ArchiveTimestamp; std::optional IsLocked; - friend void from_json(const nlohmann::json &j, ThreadMetadata &m); + friend void from_json(const nlohmann::json &j, ThreadMetadataData &m); +}; + +struct ThreadMemberObject { + std::optional ThreadID; + std::optional UserID; + std::string JoinTimestamp; + int Flags; + + friend void from_json(const nlohmann::json &j, ThreadMemberObject &m); }; struct ChannelData { @@ -67,7 +78,8 @@ struct ChannelData { std::optional ApplicationID; std::optional ParentID; // null std::optional LastPinTimestamp; // null - std::optional ThreadMetadata; + std::optional ThreadMetadata; + std::optional ThreadMember; friend void from_json(const nlohmann::json &j, ChannelData &m); void update_from_json(const nlohmann::json &j); diff --git a/discord/discord.cpp b/discord/discord.cpp index 2c0c7d7..18b4212 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -1155,6 +1155,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) { case GatewayEvent::RELATIONSHIP_ADD: { HandleGatewayRelationshipAdd(m); } break; + case GatewayEvent::THREAD_CREATE: { + HandleGatewayThreadCreate(m); + } break; } } break; default: @@ -1381,7 +1384,7 @@ void DiscordClient::HandleGatewayChannelCreate(const GatewayMessage &msg) { for (const auto &p : *data.PermissionOverwrites) m_store.SetPermissionOverwrite(data.ID, p.ID, p); m_store.EndTransaction(); - m_signal_channel_create.emit(data.ID); + m_signal_channel_create.emit(data); } void DiscordClient::HandleGatewayGuildUpdate(const GatewayMessage &msg) { @@ -1635,6 +1638,14 @@ void DiscordClient::HandleGatewayRelationshipAdd(const GatewayMessage &msg) { m_signal_relationship_add.emit(std::move(data)); } +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::HandleGatewayReadySupplemental(const GatewayMessage &msg) { ReadySupplementalData data = msg.Data; for (const auto &p : data.MergedPresences.Friends) { @@ -1997,6 +2008,7 @@ void DiscordClient::LoadEventMap() { m_event_map["GUILD_JOIN_REQUEST_DELETE"] = GatewayEvent::GUILD_JOIN_REQUEST_DELETE; m_event_map["RELATIONSHIP_REMOVE"] = GatewayEvent::RELATIONSHIP_REMOVE; m_event_map["RELATIONSHIP_ADD"] = GatewayEvent::RELATIONSHIP_ADD; + m_event_map["THREAD_CREATE"] = GatewayEvent::THREAD_CREATE; } DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() { @@ -2135,6 +2147,10 @@ DiscordClient::type_signal_message_pinned DiscordClient::signal_message_pinned() return m_signal_message_pinned; } +DiscordClient::type_signal_thread_create DiscordClient::signal_thread_create() { + return m_signal_thread_create; +} + 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 918b1cb..93825af 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -236,6 +236,7 @@ private: void HandleGatewayGuildJoinRequestDelete(const GatewayMessage &msg); void HandleGatewayRelationshipRemove(const GatewayMessage &msg); void HandleGatewayRelationshipAdd(const GatewayMessage &msg); + void HandleGatewayThreadCreate(const GatewayMessage &msg); void HandleGatewayReadySupplemental(const GatewayMessage &msg); void HandleGatewayReconnect(const GatewayMessage &msg); void HandleGatewayInvalidSession(const GatewayMessage &msg); @@ -308,7 +309,7 @@ public: typedef sigc::signal type_signal_guild_delete; typedef sigc::signal type_signal_channel_delete; typedef sigc::signal type_signal_channel_update; - typedef sigc::signal type_signal_channel_create; + typedef sigc::signal type_signal_channel_create; typedef sigc::signal type_signal_guild_update; typedef sigc::signal type_signal_role_update; // guild id, role id typedef sigc::signal type_signal_role_create; // guild id, role id @@ -329,6 +330,7 @@ public: typedef sigc::signal type_signal_guild_join_request_delete; 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_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; @@ -368,6 +370,7 @@ public: type_signal_relationship_add signal_relationship_add(); type_signal_message_unpinned signal_message_unpinned(); type_signal_message_pinned signal_message_pinned(); + type_signal_thread_create signal_thread_create(); type_signal_message_sent signal_message_sent(); type_signal_message_send_fail signal_message_send_fail(); type_signal_disconnected signal_disconnected(); @@ -406,6 +409,7 @@ protected: type_signal_relationship_add m_signal_relationship_add; 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_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 8588b30..c4b1517 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -472,3 +472,7 @@ void to_json(nlohmann::json &j, const FriendRequestObject &m) { void to_json(nlohmann::json &j, const PutRelationshipObject &m) { JS_IF("type", m.Type); } + +void from_json(const nlohmann::json &j, ThreadCreateData &m) { + j.get_to(m.Channel); +} 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 'components/channels.cpp') 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 6c77e89bbe18a2f03d4f00072dc3afe6b97c8866 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Mon, 2 Aug 2021 00:52:37 -0400 Subject: leave thread via menu --- components/channels.cpp | 19 ++++++++++++++++++- components/channels.hpp | 4 ++++ discord/discord.cpp | 11 +++++++++++ discord/discord.hpp | 1 + 4 files changed, 34 insertions(+), 1 deletion(-) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index e175e8c..ed5de62 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -17,7 +17,9 @@ ChannelList::ChannelList() , m_menu_category_copy_id("_Copy ID", true) , m_menu_channel_copy_id("_Copy ID", true) , m_menu_dm_close("") // changes depending on if group or not - , m_menu_dm_copy_id("_Copy ID", true) { + , m_menu_dm_copy_id("_Copy ID", true) + , m_menu_thread_copy_id("_Copy ID", true) + , m_menu_thread_leave("_Leave", true) { get_style_context()->add_class("channel-list"); const auto cb = [this](const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column) { @@ -121,6 +123,17 @@ ChannelList::ChannelList() m_menu_dm.append(m_menu_dm_close); m_menu_dm.show_all(); + m_menu_thread_copy_id.signal_activate().connect([this] { + Gtk::Clipboard::get()->set_text(std::to_string((*m_model->get_iter(m_path_for_menu))[m_columns.m_id])); + }); + m_menu_thread_leave.signal_activate().connect([this] { + 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.append(m_menu_thread_copy_id); + m_menu_thread.append(m_menu_thread_leave); + m_menu_thread.show_all(); + 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)); @@ -578,6 +591,10 @@ bool ChannelList::OnButtonPressEvent(GdkEventButton *ev) { m_menu_dm_close.hide(); m_menu_dm.popup_at_pointer(reinterpret_cast(ev)); } break; + case RenderType::Thread: { + m_menu_thread.popup_at_pointer(reinterpret_cast(ev)); + break; + } break; default: break; } diff --git a/components/channels.hpp b/components/channels.hpp index ed87b57..c131a07 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -209,6 +209,10 @@ protected: Gtk::MenuItem m_menu_dm_copy_id; Gtk::MenuItem m_menu_dm_close; + Gtk::Menu m_menu_thread; + Gtk::MenuItem m_menu_thread_copy_id; + Gtk::MenuItem m_menu_thread_leave; + bool m_updating_listing = false; public: diff --git a/discord/discord.cpp b/discord/discord.cpp index 99ffb0b..6ac2223 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -761,6 +761,17 @@ 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) { + if (CheckCode(response, 204)) + 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 28c719c..156ab45 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -137,6 +137,7 @@ public: void PutRelationship(Snowflake id, sigc::slot callback); // send fr by id, accept incoming 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); bool CanModifyRole(Snowflake guild_id, Snowflake role_id) const; bool CanModifyRole(Snowflake guild_id, Snowflake role_id, Snowflake user_id) const; -- 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 'components/channels.cpp') 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 40897ece3ced8bfc051708a8d85f413f330631a9 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Wed, 4 Aug 2021 21:30:24 -0400 Subject: basic window to view threads --- abaddon.cpp | 10 ++++++++++ abaddon.hpp | 1 + components/channels.cpp | 3 ++- discord/discord.cpp | 4 ++++ discord/discord.hpp | 1 + discord/store.cpp | 32 +++++++++++++++++++++++++++++++- discord/store.hpp | 2 ++ windows/mainwindow.cpp | 18 ++++++++++++++++-- windows/mainwindow.hpp | 5 +++++ 9 files changed, 72 insertions(+), 4 deletions(-) (limited to 'components/channels.cpp') diff --git a/abaddon.cpp b/abaddon.cpp index ad33e45..22ca576 100644 --- a/abaddon.cpp +++ b/abaddon.cpp @@ -15,6 +15,7 @@ #include "windows/guildsettingswindow.hpp" #include "windows/profilewindow.hpp" #include "windows/pinnedwindow.hpp" +#include "windows/threadswindow.hpp" #ifdef _WIN32 #pragma comment(lib, "crypt32.lib") @@ -94,6 +95,7 @@ int Abaddon::StartGTK() { m_main_window->signal_action_set_status().connect(sigc::mem_fun(*this, &Abaddon::ActionSetStatus)); m_main_window->signal_action_add_recipient().connect(sigc::mem_fun(*this, &Abaddon::ActionAddRecipient)); m_main_window->signal_action_view_pins().connect(sigc::mem_fun(*this, &Abaddon::ActionViewPins)); + m_main_window->signal_action_view_threads().connect(sigc::mem_fun(*this, &Abaddon::ActionViewThreads)); m_main_window->GetChannelList()->signal_action_channel_item_select().connect(sigc::mem_fun(*this, &Abaddon::ActionChannelOpened)); m_main_window->GetChannelList()->signal_action_guild_leave().connect(sigc::mem_fun(*this, &Abaddon::ActionLeaveGuild)); @@ -616,6 +618,14 @@ void Abaddon::ActionViewPins(Snowflake channel_id) { window->show(); } +void Abaddon::ActionViewThreads(Snowflake channel_id) { + const auto data = m_discord.GetChannel(channel_id); + if (!data.has_value()) return; + auto window = new ThreadsWindow(*data); + ManageHeapWindow(window); + window->show(); +} + bool Abaddon::ShowConfirm(const Glib::ustring &prompt, Gtk::Window *window) { ConfirmDialog dlg(window != nullptr ? *window : *m_main_window); dlg.SetConfirmText(prompt); diff --git a/abaddon.hpp b/abaddon.hpp index 320f621..0bd5d97 100644 --- a/abaddon.hpp +++ b/abaddon.hpp @@ -47,6 +47,7 @@ public: void ActionGuildSettings(Snowflake id); void ActionAddRecipient(Snowflake channel_id); void ActionViewPins(Snowflake channel_id); + void ActionViewThreads(Snowflake channel_id); bool ShowConfirm(const Glib::ustring &prompt, Gtk::Window *window = nullptr); diff --git a/components/channels.cpp b/components/channels.cpp index 644e090..f12d56a 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -308,7 +308,8 @@ void ChannelList::SetActiveChannel(Snowflake id) { if (channel_iter) { m_view.expand_to_path(m_model->get_path(channel_iter)); m_view.get_selection()->select(channel_iter); - } + } else + m_view.get_selection()->unselect_all(); } Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild) { diff --git a/discord/discord.cpp b/discord/discord.cpp index 82d2131..49684ae 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -249,6 +249,10 @@ std::set DiscordClient::GetChannelsInGuild(Snowflake id) const { return {}; } +std::vector DiscordClient::GetPublicThreads(Snowflake channel_id) const { + return m_store.GetThreads(channel_id); +} + bool DiscordClient::HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const { const auto base = ComputePermissions(user_id, guild_id); return (base & perm) == perm; diff --git a/discord/discord.hpp b/discord/discord.hpp index 619a898..fa4b4c3 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 GetPublicThreads(Snowflake channel_id) const; bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const; diff --git a/discord/store.cpp b/discord/store.cpp index 3cac46e..ba8e59a 100644 --- a/discord/store.cpp +++ b/discord/store.cpp @@ -499,6 +499,25 @@ std::vector Store::GetPinnedMessages(Snowflake channel_id) const { return ret; } +std::vector Store::GetThreads(Snowflake channel_id) const { + std::vector ret; + + Bind(m_get_threads_stmt, 1, channel_id); + while (FetchOne(m_get_threads_stmt)) { + Snowflake x; + Get(m_get_threads_stmt, 0, x); + auto chan = GetChannel(x); + if (chan.has_value()) + ret.push_back(*chan); + } + + Reset(m_get_threads_stmt); + + if (m_db_err != SQLITE_DONE) + fprintf(stderr, "error while fetching threads: %s\n", sqlite3_errstr(m_db_err)); + return ret; +} + std::optional Store::GetChannel(Snowflake id) const { Bind(m_get_chan_stmt, 1, id); if (!FetchOne(m_get_chan_stmt)) { @@ -1186,6 +1205,10 @@ bool Store::CreateStatements() { SELECT id FROM messages WHERE channel_id = ? AND pinned = 1 ORDER BY id ASC )"; + const char *get_threads = R"( + SELECT id FROM channels WHERE parent_id = ? AND type = 11 + )"; + m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr); if (m_db_err != SQLITE_OK) { fprintf(stderr, "failed to prepare set user statement: %s\n", sqlite3_errstr(m_db_err)); @@ -1326,7 +1349,13 @@ bool Store::CreateStatements() { m_db_err = sqlite3_prepare_v2(m_db, get_pins, -1, &m_get_pins_stmt, nullptr); if (m_db_err != SQLITE_OK) { - fprintf(stderr, "failed to prepare getp ins statement: %s\n", sqlite3_errstr(m_db_err)); + fprintf(stderr, "failed to prepare get pins statement: %s\n", sqlite3_errstr(m_db_err)); + return false; + } + + m_db_err = sqlite3_prepare_v2(m_db, get_threads, -1, &m_get_threads_stmt, nullptr); + if (m_db_err != SQLITE_OK) { + fprintf(stderr, "failed to prepare get threads statement: %s\n", sqlite3_errstr(m_db_err)); return false; } @@ -1358,6 +1387,7 @@ void Store::Cleanup() { sqlite3_finalize(m_get_last_msgs_stmt); sqlite3_finalize(m_get_msg_ids_stmt); sqlite3_finalize(m_get_pins_stmt); + sqlite3_finalize(m_get_threads_stmt); } void Store::Bind(sqlite3_stmt *stmt, int index, int num) const { diff --git a/discord/store.hpp b/discord/store.hpp index 7e7d6ea..76c8a8e 100644 --- a/discord/store.hpp +++ b/discord/store.hpp @@ -44,6 +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 void ClearGuild(Snowflake id); void ClearChannel(Snowflake id); @@ -135,6 +136,7 @@ private: mutable sqlite3_stmt *m_get_last_msgs_stmt; mutable sqlite3_stmt *m_get_msg_ids_stmt; mutable sqlite3_stmt *m_get_pins_stmt; + mutable sqlite3_stmt *m_get_threads_stmt; }; template diff --git a/windows/mainwindow.cpp b/windows/mainwindow.cpp index 0d77e96..7ddaaf2 100644 --- a/windows/mainwindow.cpp +++ b/windows/mainwindow.cpp @@ -41,8 +41,10 @@ MainWindow::MainWindow() m_menu_view.set_submenu(m_menu_view_sub); m_menu_view_friends.set_label("Friends"); m_menu_view_pins.set_label("Pins"); + m_menu_view_threads.set_label("Threads"); m_menu_view_sub.append(m_menu_view_friends); m_menu_view_sub.append(m_menu_view_pins); + m_menu_view_sub.append(m_menu_view_threads); m_menu_view_sub.signal_popped_up().connect(sigc::mem_fun(*this, &MainWindow::OnViewSubmenuPopup)); m_menu_bar.append(m_menu_file); @@ -92,6 +94,10 @@ MainWindow::MainWindow() m_signal_action_view_pins.emit(GetChatActiveChannel()); }); + m_menu_view_threads.signal_activate().connect([this] { + m_signal_action_view_threads.emit(GetChatActiveChannel()); + }); + m_content_box.set_hexpand(true); m_content_box.set_vexpand(true); m_content_box.show(); @@ -243,8 +249,12 @@ void MainWindow::OnViewSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gd auto channel_id = GetChatActiveChannel(); auto channel = Abaddon::Get().GetDiscordClient().GetChannel(channel_id); m_menu_view_pins.set_sensitive(false); - if (channel.has_value()) - m_menu_view_pins.set_sensitive(channel->Type == ChannelType::GUILD_TEXT); + m_menu_view_threads.set_sensitive(false); + if (channel.has_value()) { + const bool b = channel->Type == ChannelType::GUILD_TEXT; + m_menu_view_pins.set_sensitive(b); + m_menu_view_threads.set_sensitive(b); + } } ChannelList *MainWindow::GetChannelList() { @@ -290,3 +300,7 @@ MainWindow::type_signal_action_add_recipient MainWindow::signal_action_add_recip MainWindow::type_signal_action_view_pins MainWindow::signal_action_view_pins() { return m_signal_action_view_pins; } + +MainWindow::type_signal_action_view_threads MainWindow::signal_action_view_threads() { + return m_signal_action_view_threads; +} diff --git a/windows/mainwindow.hpp b/windows/mainwindow.hpp index d037796..3b41d16 100644 --- a/windows/mainwindow.hpp +++ b/windows/mainwindow.hpp @@ -35,8 +35,10 @@ public: typedef sigc::signal type_signal_action_reload_css; typedef sigc::signal type_signal_action_join_guild; typedef sigc::signal type_signal_action_set_status; + // this should probably be removed typedef sigc::signal type_signal_action_add_recipient; // channel id typedef sigc::signal type_signal_action_view_pins; // channel id + typedef sigc::signal type_signal_action_view_threads; // channel id type_signal_action_connect signal_action_connect(); type_signal_action_disconnect signal_action_disconnect(); @@ -46,6 +48,7 @@ public: type_signal_action_set_status signal_action_set_status(); type_signal_action_add_recipient signal_action_add_recipient(); type_signal_action_view_pins signal_action_view_pins(); + type_signal_action_view_threads signal_action_view_threads(); protected: type_signal_action_connect m_signal_action_connect; @@ -56,6 +59,7 @@ protected: type_signal_action_set_status m_signal_action_set_status; type_signal_action_add_recipient m_signal_action_add_recipient; type_signal_action_view_pins m_signal_action_view_pins; + type_signal_action_view_threads m_signal_action_view_threads; protected: Gtk::Box m_main_box; @@ -90,5 +94,6 @@ protected: Gtk::Menu m_menu_view_sub; Gtk::MenuItem m_menu_view_friends; Gtk::MenuItem m_menu_view_pins; + Gtk::MenuItem m_menu_view_threads; void OnViewSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y); }; -- cgit v1.2.3 From 41a63df1b108a9520a8dfcb862f108b42f9a1bb1 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Thu, 5 Aug 2021 03:32:53 -0400 Subject: add temporary row for non-joined threads --- components/channels.cpp | 21 ++++++++++++++++++++- components/channels.hpp | 3 +++ discord/channel.cpp | 10 ++++++++++ discord/channel.hpp | 2 ++ discord/discord.cpp | 6 ++++++ discord/discord.hpp | 5 ++--- 6 files changed, 43 insertions(+), 4 deletions(-) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index f12d56a..b96b2e6 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -292,6 +292,7 @@ void ChannelList::OnThreadMembersUpdate(const ThreadMembersUpdateData &data) { } void ChannelList::UpdateCreateThread(const ChannelData &channel) { + if (GetIteratorForChannelFromID(channel.ID)) return; // dont do anything if already exists auto parent_row = GetIteratorForChannelFromID(*channel.ParentID); if (parent_row) CreateThreadRow(parent_row->children(), channel); @@ -303,13 +304,31 @@ void ChannelList::UpdateDeleteThread(Snowflake id) { m_model->erase(iter); } +// create a temporary channel row for non-joined threads +// and delete them when the active channel switches off of them if still not joined 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()) + m_model->erase(m_temporary_thread_row); + m_temporary_thread_row = {}; + } + const auto channel_iter = GetIteratorForChannelFromID(id); if (channel_iter) { m_view.expand_to_path(m_model->get_path(channel_iter)); m_view.get_selection()->select(channel_iter); - } else + } else { m_view.get_selection()->unselect_all(); + // SetActiveChannel should probably just take the channel object + const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(id); + if (!channel.has_value() || !channel->IsThread()) return; + auto parent_iter = GetIteratorForChannelFromID(*channel->ParentID); + if (!parent_iter) return; + m_temporary_thread_row = CreateThreadRow(parent_iter->children(), *channel); + m_view.get_selection()->select(m_temporary_thread_row); + } } Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild) { diff --git a/components/channels.hpp b/components/channels.hpp index 24c7170..fce3546 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -197,6 +197,9 @@ protected: void OnMessageCreate(const Message &msg); Gtk::TreeModel::Path m_path_for_menu; + // cant be recovered through selection + Gtk::TreeModel::iterator m_temporary_thread_row; + Gtk::Menu m_menu_guild; Gtk::MenuItem m_menu_guild_copy_id; Gtk::MenuItem m_menu_guild_settings; diff --git a/discord/channel.cpp b/discord/channel.cpp index 685cc72..f78e0cd 100644 --- a/discord/channel.cpp +++ b/discord/channel.cpp @@ -63,6 +63,16 @@ bool ChannelData::NSFW() const { return IsNSFW.has_value() && *IsNSFW; } +bool ChannelData::IsThread() const noexcept { + return Type == ChannelType::GUILD_PUBLIC_THREAD || + Type == ChannelType::GUILD_PRIVATE_THREAD || + Type == ChannelType::GUILD_NEWS_THREAD; +} + +bool ChannelData::IsJoinedThread() const { + return Abaddon::Get().GetDiscordClient().IsThreadJoined(ID); +} + std::optional ChannelData::GetOverwrite(Snowflake id) const { return Abaddon::Get().GetDiscordClient().GetPermissionOverwrite(ID, id); } diff --git a/discord/channel.hpp b/discord/channel.hpp index 606686d..942d555 100644 --- a/discord/channel.hpp +++ b/discord/channel.hpp @@ -85,6 +85,8 @@ struct ChannelData { void update_from_json(const nlohmann::json &j); bool NSFW() const; + bool IsThread() const noexcept; + bool IsJoinedThread() const; std::optional GetOverwrite(Snowflake id) const; std::vector GetDMRecipients() const; }; diff --git a/discord/discord.cpp b/discord/discord.cpp index 49684ae..5a7c07e 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -253,6 +253,10 @@ std::vector DiscordClient::GetPublicThreads(Snowflake channel_id) c return m_store.GetThreads(channel_id); } +bool DiscordClient::IsThreadJoined(Snowflake thread_id) const { + return std::find(m_joined_threads.begin(), m_joined_threads.end(), thread_id) != m_joined_threads.end(); +} + bool DiscordClient::HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const { const auto base = ComputePermissions(user_id, guild_id); return (base & perm) == perm; @@ -1250,6 +1254,7 @@ void DiscordClient::ProcessNewGuild(GuildData &guild) { if (guild.Threads.has_value()) { for (auto &c : *guild.Threads) { + m_joined_threads.push_back(c.ID); c.GuildID = guild.ID; m_store.SetChannel(c.ID, c); } @@ -1668,6 +1673,7 @@ 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_joined_threads.push_back(data.Channel.ID); m_signal_thread_create.emit(data.Channel); } diff --git a/discord/discord.hpp b/discord/discord.hpp index fa4b4c3..a589702 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -88,6 +88,7 @@ public: std::set GetChannelsInGuild(Snowflake id) const; std::vector GetPublicThreads(Snowflake channel_id) const; + bool IsThreadJoined(Snowflake thread_id) const; bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const; bool HasAnyChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const; @@ -261,13 +262,11 @@ private: void AddUserToGuild(Snowflake user_id, Snowflake guild_id); std::map> m_guild_to_users; - std::map> m_guild_to_channels; std::map m_guild_join_requests; - std::map m_user_to_status; - std::map m_user_relationships; + std::vector m_joined_threads; UserData m_user_data; UserSettings m_user_settings; -- cgit v1.2.3 From 856674506c064ba94396752664aede5167c3ec4b Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Thu, 5 Aug 2021 04:02:47 -0400 Subject: better join/leave thread logic --- components/channels.cpp | 30 +++++++++++++++--------------- components/channels.hpp | 6 +++--- discord/channel.cpp | 2 +- discord/discord.cpp | 23 +++++++++++++++++++++-- discord/discord.hpp | 15 ++++++++++++--- 5 files changed, 52 insertions(+), 24 deletions(-) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index b96b2e6..71a4cd9 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -141,9 +141,9 @@ ChannelList::ChannelList() discord.signal_channel_delete().connect(sigc::mem_fun(*this, &ChannelList::UpdateRemoveChannel)); 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::OnThreadDelete)); - discord.signal_thread_members_update().connect(sigc::mem_fun(*this, &ChannelList::OnThreadMembersUpdate)); + discord.signal_added_to_thread().connect(sigc::mem_fun(*this, &ChannelList::OnThreadJoined)); + discord.signal_removed_from_thread().connect(sigc::mem_fun(*this, &ChannelList::OnThreadRemoved)); discord.signal_guild_update().connect(sigc::mem_fun(*this, &ChannelList::UpdateGuild)); } @@ -280,25 +280,25 @@ void ChannelList::UpdateGuild(Snowflake id) { } } -void ChannelList::OnThreadDelete(const ThreadDeleteData &data) { - UpdateDeleteThread(data.ID); +void ChannelList::OnThreadJoined(Snowflake id) { + if (GetIteratorForChannelFromID(id)) return; + const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(id); + if (!channel.has_value()) return; + const auto parent = GetIteratorForChannelFromID(*channel->ParentID); + if (parent) + CreateThreadRow(parent->children(), *channel); } -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::OnThreadRemoved(Snowflake id) { + if (GetIteratorForChannelFromID(id)) + DeleteThreadRow(id); } -void ChannelList::UpdateCreateThread(const ChannelData &channel) { - if (GetIteratorForChannelFromID(channel.ID)) return; // dont do anything if already exists - auto parent_row = GetIteratorForChannelFromID(*channel.ParentID); - if (parent_row) - CreateThreadRow(parent_row->children(), channel); +void ChannelList::OnThreadDelete(const ThreadDeleteData &data) { + DeleteThreadRow(data.ID); } -void ChannelList::UpdateDeleteThread(Snowflake id) { +void ChannelList::DeleteThreadRow(Snowflake id) { auto iter = GetIteratorForChannelFromID(id); if (iter) m_model->erase(iter); diff --git a/components/channels.hpp b/components/channels.hpp index fce3546..c1c74a4 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -140,12 +140,12 @@ protected: void UpdateRemoveChannel(Snowflake id); void UpdateChannel(Snowflake id); void UpdateCreateChannel(const ChannelData &channel); - void UpdateCreateThread(const ChannelData &channel); - void UpdateDeleteThread(Snowflake id); void UpdateGuild(Snowflake id); + void DeleteThreadRow(Snowflake id); + void OnThreadJoined(Snowflake id); + void OnThreadRemoved(Snowflake id); void OnThreadDelete(const ThreadDeleteData &data); - void OnThreadMembersUpdate(const ThreadMembersUpdateData &data); Gtk::TreeView m_view; diff --git a/discord/channel.cpp b/discord/channel.cpp index f78e0cd..60f481b 100644 --- a/discord/channel.cpp +++ b/discord/channel.cpp @@ -10,7 +10,7 @@ void from_json(const nlohmann::json &j, ThreadMetadataData &m) { void from_json(const nlohmann::json &j, ThreadMemberObject &m) { JS_O("id", m.ThreadID); - JS_O("user_id", m.ThreadID); + JS_O("user_id", m.UserID); JS_D("join_timestamp", m.JoinTimestamp); JS_D("flags", m.Flags); } diff --git a/discord/discord.cpp b/discord/discord.cpp index 5a7c07e..aa363f5 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -1254,7 +1254,7 @@ void DiscordClient::ProcessNewGuild(GuildData &guild) { if (guild.Threads.has_value()) { for (auto &c : *guild.Threads) { - m_joined_threads.push_back(c.ID); + m_joined_threads.insert(c.ID); c.GuildID = guild.ID; m_store.SetChannel(c.ID, c); } @@ -1670,10 +1670,10 @@ void DiscordClient::HandleGatewayRelationshipAdd(const GatewayMessage &msg) { // remarkably this doesnt actually mean a thread was created // it can also mean you gained access to a thread. yay ... +// except sometimes it doesnt??? i dont know whats going on void DiscordClient::HandleGatewayThreadCreate(const GatewayMessage &msg) { ThreadCreateData data = msg.Data; m_store.SetChannel(data.Channel.ID, data.Channel); - m_joined_threads.push_back(data.Channel.ID); m_signal_thread_create.emit(data.Channel); } @@ -1695,6 +1695,17 @@ void DiscordClient::HandleGatewayThreadListSync(const GatewayMessage &msg) { void DiscordClient::HandleGatewayThreadMembersUpdate(const GatewayMessage &msg) { ThreadMembersUpdateData data = msg.Data; + if (data.AddedMembers.has_value() && + std::find_if(data.AddedMembers->begin(), data.AddedMembers->end(), [this](const auto &x) { + return *x.UserID == m_user_data.ID; // safe to assume UserID is present here + }) != data.AddedMembers->end()) { + m_joined_threads.insert(data.ID); + m_signal_added_to_thread.emit(data.ID); + } else if (data.RemovedMemberIDs.has_value() && + std::find(data.RemovedMemberIDs->begin(), data.RemovedMemberIDs->end(), m_user_data.ID) != data.RemovedMemberIDs->end()) { + m_joined_threads.erase(data.ID); + m_signal_removed_from_thread.emit(data.ID); + } m_signal_thread_members_update.emit(data); } @@ -2218,6 +2229,14 @@ DiscordClient::type_signal_thread_members_update DiscordClient::signal_thread_me return m_signal_thread_members_update; } +DiscordClient::type_signal_added_to_thread DiscordClient::signal_added_to_thread() { + return m_signal_added_to_thread; +} + +DiscordClient::type_signal_removed_from_thread DiscordClient::signal_removed_from_thread() { + return m_signal_removed_from_thread; +} + 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 a589702..11b8cbd 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -266,7 +266,7 @@ private: std::map m_guild_join_requests; std::map m_user_to_status; std::map m_user_relationships; - std::vector m_joined_threads; + std::set m_joined_threads; UserData m_user_data; UserSettings m_user_settings; @@ -338,9 +338,14 @@ 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_message_unpinned; // not a real event - typedef sigc::signal type_signal_message_pinned; // not a real event either + + // not discord dispatch events + typedef sigc::signal type_signal_added_to_thread; + typedef sigc::signal type_signal_removed_from_thread; + typedef sigc::signal type_signal_message_unpinned; + typedef sigc::signal type_signal_message_pinned; typedef sigc::signal type_signal_message_sent; + typedef sigc::signal type_signal_message_send_fail; // retry after param will be 0 if it failed for a reason that isnt slowmode typedef sigc::signal type_signal_disconnected; // bool true if reconnecting typedef sigc::signal type_signal_connected; @@ -381,6 +386,8 @@ 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_added_to_thread signal_added_to_thread(); + type_signal_removed_from_thread signal_removed_from_thread(); type_signal_message_sent signal_message_sent(); type_signal_message_send_fail signal_message_send_fail(); type_signal_disconnected signal_disconnected(); @@ -423,6 +430,8 @@ 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_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; type_signal_message_send_fail m_signal_message_send_fail; type_signal_disconnected m_signal_disconnected; -- cgit v1.2.3 From e0db238cf011605048c3ac605730edc54a9f3b16 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 15 Aug 2021 01:36:57 -0400 Subject: removed deleted threads on sync --- components/channels.cpp | 26 ++++++++++++++++++++++++++ components/channels.hpp | 1 + 2 files changed, 27 insertions(+) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index 71a4cd9..f8d0fb6 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_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)); discord.signal_guild_update().connect(sigc::mem_fun(*this, &ChannelList::UpdateGuild)); @@ -298,6 +299,31 @@ void ChannelList::OnThreadDelete(const ThreadDeleteData &data) { DeleteThreadRow(data.ID); } +void ChannelList::OnThreadListSync(const ThreadListSyncData &data) { + // get the threads in the guild + std::vector threads; + auto guild_iter = GetIteratorForGuildFromID(data.GuildID); + std::queue queue; + queue.push(guild_iter); + + while (!queue.empty()) { + auto item = queue.front(); + queue.pop(); + if ((*item)[m_columns.m_type] == RenderType::Thread) + threads.push_back(static_cast((*item)[m_columns.m_id])); + for (auto child : item->children()) + queue.push(child); + } + + // 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()) { + auto iter = GetIteratorForChannelFromID(thread_id); + m_model->erase(iter); + } + } +} + void ChannelList::DeleteThreadRow(Snowflake id) { auto iter = GetIteratorForChannelFromID(id); if (iter) diff --git a/components/channels.hpp b/components/channels.hpp index c1c74a4..31857ec 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 OnThreadListSync(const ThreadListSyncData &data); Gtk::TreeView m_view; -- 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 'components/channels.cpp') 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 2a2f96f9b6e7c8e7b490cc70525de571bbecc360 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Mon, 16 Aug 2021 02:58:18 -0400 Subject: update channel name in THREAD_UPDATE --- components/channels.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index 117e5a6..b36eb4e 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -301,6 +301,10 @@ void ChannelList::OnThreadDelete(const ThreadDeleteData &data) { // todo probably make the row stick around if its selected until the selection changes void ChannelList::OnThreadUpdate(const ThreadUpdateData &data) { + auto iter = GetIteratorForChannelFromID(data.Thread.ID); + if (iter) + (*iter)[m_columns.m_name] = "- " + Glib::Markup::escape_text(*data.Thread.Name); + if (data.Thread.ThreadMetadata->IsArchived) DeleteThreadRow(data.Thread.ID); } -- cgit v1.2.3 From 04ebd069b4b1a1f54148f0f303e5f98cf018c1ae Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Mon, 23 Aug 2021 19:15:38 -0400 Subject: ad-hoc MoveRow for channel list so threads no longer disappear when a channel is moved --- components/channels.cpp | 55 ++++++++++++++++++++++++++++++------------------- components/channels.hpp | 2 ++ 2 files changed, 36 insertions(+), 21 deletions(-) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index b36eb4e..1fc1a92 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -205,28 +205,17 @@ void ChannelList::UpdateChannel(Snowflake id) { if (channel->Type == ChannelType::GUILD_CATEGORY) return UpdateChannelCategory(*channel); if (!IsTextChannel(channel->Type)) return; - // delete and recreate - m_model->erase(iter); + // refresh stuff that might have changed + const bool is_orphan_TMP = !channel->ParentID.has_value(); + (*iter)[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel->Name); + (*iter)[m_columns.m_nsfw] = channel->NSFW(); + (*iter)[m_columns.m_sort] = *channel->Position + (is_orphan_TMP ? OrphanChannelSortOffset : 0); - Gtk::TreeStore::iterator parent; - bool is_orphan; - if (channel->ParentID.has_value()) { - is_orphan = false; - parent = GetIteratorForChannelFromID(*channel->ParentID); - } else { - is_orphan = true; - parent = GetIteratorForGuildFromID(*channel->GuildID); - } - if (!parent) return; - auto channel_row = *m_model->append(parent->children()); - channel_row[m_columns.m_type] = RenderType::TextChannel; - channel_row[m_columns.m_id] = channel->ID; - channel_row[m_columns.m_name] = "#" + Glib::Markup::escape_text(*channel->Name); - channel_row[m_columns.m_nsfw] = channel->NSFW(); - if (is_orphan) - channel_row[m_columns.m_sort] = *channel->Position + OrphanChannelSortOffset; - else - channel_row[m_columns.m_sort] = *channel->Position; + // check if the parent has changed + const auto new_parent = GetIteratorForChannelFromID(*channel->ParentID); + const bool parent_has_changed = iter->parent() != new_parent; + if (parent_has_changed) + MoveRow(iter, new_parent); } void ChannelList::UpdateCreateChannel(const ChannelData &channel) { @@ -672,6 +661,30 @@ bool ChannelList::OnButtonPressEvent(GdkEventButton *ev) { return false; } +void ChannelList::MoveRow(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::iterator &new_parent) { + // duplicate the row data under the new parent and then delete the old row + auto row = *m_model->append(new_parent->children()); + // would be nice to be able to get all columns out at runtime so i dont need this +#define M(name) \ + row[m_columns.name] = static_cast((*iter)[m_columns.name]); + M(m_type); + M(m_id); + M(m_name); + M(m_icon); + M(m_icon_anim); + M(m_sort); + M(m_nsfw); + M(m_expanded); +#undef M + + // recursively move children + for (const auto &child : iter->children()) + MoveRow(child, row); + + // delete original + m_model->erase(iter); +} + 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 506ad93..37a3254 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -190,6 +190,8 @@ protected: bool SelectionFunc(const Glib::RefPtr &model, const Gtk::TreeModel::Path &path, bool is_currently_selected); bool OnButtonPressEvent(GdkEventButton *ev); + void MoveRow(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::iterator &new_parent); + Gtk::TreeModel::Path m_last_selected; Gtk::TreeModel::Path m_dm_header; -- cgit v1.2.3 From ab948c29b7cb136430bab6b3f6eb9b174aef7d3f Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Tue, 24 Aug 2021 01:51:49 -0400 Subject: fix moving rows --- components/channels.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index 1fc1a92..41935b9 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -212,9 +212,13 @@ void ChannelList::UpdateChannel(Snowflake id) { (*iter)[m_columns.m_sort] = *channel->Position + (is_orphan_TMP ? OrphanChannelSortOffset : 0); // check if the parent has changed - const auto new_parent = GetIteratorForChannelFromID(*channel->ParentID); - const bool parent_has_changed = iter->parent() != new_parent; - if (parent_has_changed) + Gtk::TreeModel::iterator new_parent; + if (channel->ParentID.has_value()) + new_parent = GetIteratorForChannelFromID(*channel->ParentID); + else + new_parent = GetIteratorForGuildFromID(*channel->GuildID); + + if (new_parent && iter->parent() != new_parent) MoveRow(iter, new_parent); } @@ -678,8 +682,11 @@ void ChannelList::MoveRow(const Gtk::TreeModel::iterator &iter, const Gtk::TreeM #undef M // recursively move children - for (const auto &child : iter->children()) - MoveRow(child, row); + // weird construct to work around iterator invalidation (at least i think thats what the problem was) + const auto tmp = iter->children(); + const auto children = std::vector(tmp.begin(), tmp.end()); + for (size_t i = 0; i < children.size(); i++) + MoveRow(children[i], row); // delete original m_model->erase(iter); -- 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 'components/channels.cpp') 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 From 66747ec753c5f9a617d8bd342fbf015f7137cf49 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sat, 28 Aug 2021 02:43:02 -0400 Subject: permissions check on archive/unarchive (oops) --- components/channels.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index 0a60fd6..4a3a8f1 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -708,10 +708,12 @@ void ChannelList::OnThreadSubmenuPopup(const Gdk::Rectangle *flipped_rect, const m_menu_thread_archive.set_visible(false); m_menu_thread_unarchive.set_visible(false); + auto &discord = Abaddon::Get().GetDiscordClient(); 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])); + auto channel = discord.GetChannel(static_cast((*iter)[m_columns.m_id])); if (!channel.has_value() || !channel->ThreadMetadata.has_value()) return; + if (!discord.HasGuildPermission(discord.GetUserData().ID, *channel->GuildID, Permission::MANAGE_THREADS)) return; m_menu_thread_archive.set_visible(!channel->ThreadMetadata->IsArchived); m_menu_thread_unarchive.set_visible(channel->ThreadMetadata->IsArchived); -- cgit v1.2.3 From f3769ca30164b28538294c27dd3fdec672638631 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Fri, 3 Sep 2021 03:49:25 -0400 Subject: remove archived threads from channel list on sync this probably doesnt do anything but i added it while trying to fix something and it might work sometime i dont know --- components/channels.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'components/channels.cpp') diff --git a/components/channels.cpp b/components/channels.cpp index 4a3a8f1..98604d7 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -337,6 +337,14 @@ void ChannelList::OnThreadListSync(const ThreadListSyncData &data) { m_model->erase(iter); } } + + // delete all archived threads + for (auto thread : data.Threads) { + if (thread.ThreadMetadata->IsArchived) { + if (auto iter = GetIteratorForChannelFromID(thread.ID)) + m_model->erase(iter); + } + } } void ChannelList::DeleteThreadRow(Snowflake id) { -- cgit v1.2.3