From 40106ddeb11a755864e446920b74739f1ec21c57 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Wed, 5 Jan 2022 03:52:20 -0500 Subject: handle mutable categories --- src/components/channels.cpp | 21 ++++++++++++++++++++- src/components/channels.hpp | 2 ++ src/components/channelscellrenderer.cpp | 4 ++++ src/discord/channel.cpp | 8 ++++++++ src/discord/channel.hpp | 2 ++ src/discord/discord.cpp | 33 +++++++++++++++++++++++++++++++-- src/discord/discord.hpp | 2 ++ src/discord/store.cpp | 23 +++++++++++++++++++++++ src/discord/store.hpp | 2 ++ 9 files changed, 94 insertions(+), 3 deletions(-) diff --git a/src/components/channels.cpp b/src/components/channels.cpp index 7ad2dd0..c4ba2c0 100644 --- a/src/components/channels.cpp +++ b/src/components/channels.cpp @@ -116,7 +116,15 @@ ChannelList::ChannelList() m_menu_category_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_category_toggle_mute.signal_activate().connect([this] { + const auto id = static_cast((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]); + auto &discord = Abaddon::Get().GetDiscordClient(); + if (discord.IsChannelMuted(id)) + discord.UnmuteChannel(id, NOOP_CALLBACK); + else + discord.MuteChannel(id, NOOP_CALLBACK); + }); + m_menu_category.append(m_menu_category_toggle_mute); m_menu_category.append(m_menu_category_copy_id); m_menu_category.show_all(); @@ -177,6 +185,7 @@ ChannelList::ChannelList() m_menu_thread.show_all(); m_menu_guild.signal_popped_up().connect(sigc::mem_fun(*this, &ChannelList::OnGuildSubmenuPopup)); + m_menu_category.signal_popped_up().connect(sigc::mem_fun(*this, &ChannelList::OnCategorySubmenuPopup)); m_menu_channel.signal_popped_up().connect(sigc::mem_fun(*this, &ChannelList::OnChannelSubmenuPopup)); m_menu_thread.signal_popped_up().connect(sigc::mem_fun(*this, &ChannelList::OnThreadSubmenuPopup)); @@ -857,6 +866,16 @@ void ChannelList::OnGuildSubmenuPopup(const Gdk::Rectangle *flipped_rect, const m_menu_guild_toggle_mute.set_label("Mute"); } +void ChannelList::OnCategorySubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y) { + const auto iter = m_model->get_iter(m_path_for_menu); + if (!iter) return; + const auto id = static_cast((*iter)[m_columns.m_id]); + if (Abaddon::Get().GetDiscordClient().IsChannelMuted(id)) + m_menu_category_toggle_mute.set_label("Unmute"); + else + m_menu_category_toggle_mute.set_label("Mute"); +} + void ChannelList::OnChannelSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y) { const auto iter = m_model->get_iter(m_path_for_menu); if (!iter) return; diff --git a/src/components/channels.hpp b/src/components/channels.hpp index 6970729..ba75be8 100644 --- a/src/components/channels.hpp +++ b/src/components/channels.hpp @@ -114,6 +114,7 @@ protected: Gtk::Menu m_menu_category; Gtk::MenuItem m_menu_category_copy_id; + Gtk::MenuItem m_menu_category_toggle_mute; Gtk::Menu m_menu_channel; Gtk::MenuItem m_menu_channel_copy_id; @@ -131,6 +132,7 @@ protected: Gtk::MenuItem m_menu_thread_unarchive; void OnGuildSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y); + void OnCategorySubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y); void OnChannelSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y); void OnThreadSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y); diff --git a/src/components/channelscellrenderer.cpp b/src/components/channelscellrenderer.cpp index 325d45a..b998442 100644 --- a/src/components/channelscellrenderer.cpp +++ b/src/components/channelscellrenderer.cpp @@ -327,7 +327,11 @@ void CellRendererChannels::render_vfunc_category(const Cairo::RefPtr ChannelData::GetChildIDs() const { + return Abaddon::Get().GetDiscordClient().GetChildChannelIDs(ID); +} + std::optional ChannelData::GetOverwrite(Snowflake id) const { return Abaddon::Get().GetDiscordClient().GetPermissionOverwrite(ID, id); } diff --git a/src/discord/channel.hpp b/src/discord/channel.hpp index fd76d3a..195a09a 100644 --- a/src/discord/channel.hpp +++ b/src/discord/channel.hpp @@ -88,6 +88,8 @@ struct ChannelData { bool IsDM() const noexcept; bool IsThread() const noexcept; bool IsJoinedThread() const; + bool IsCategory() const noexcept; + std::vector GetChildIDs() const; std::optional GetOverwrite(Snowflake id) const; std::vector GetDMRecipients() const; }; diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp index 6819375..529da0b 100644 --- a/src/discord/discord.cpp +++ b/src/discord/discord.cpp @@ -307,6 +307,10 @@ void DiscordClient::GetArchivedPrivateThreads(Snowflake channel_id, sigc::slot DiscordClient::GetChildChannelIDs(Snowflake parent_id) const { + return m_store.GetChannelIDsWithParentID(parent_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(); } @@ -1184,10 +1188,15 @@ bool DiscordClient::GetUnreadStateForGuild(Snowflake id, int &total_mentions) co const auto channels = GetChannelsInGuild(id); for (const auto channel_id : channels) { const auto channel_unread = GetUnreadStateForChannel(channel_id); - if (!has_any_unread && channel_unread > -1 && !IsChannelMuted(channel_id)) - has_any_unread = true; if (channel_unread > -1) total_mentions += channel_unread; + + // channels under muted categories wont contribute to unread state + if (const auto iter = m_channel_muted_parent.find(channel_id); iter != m_channel_muted_parent.end()) + continue; + + if (!has_any_unread && channel_unread > -1 && !IsChannelMuted(channel_id)) + has_any_unread = true; } return has_any_unread; } @@ -1974,11 +1983,19 @@ void DiscordClient::HandleGatewayUserGuildSettingsUpdate(const GatewayMessage &m if (now_muted) { m_muted_channels.insert(channel_id); if (!was_muted) { + if (const auto chan = GetChannel(channel_id); chan.has_value() && chan->IsCategory()) + for (const auto child_id : chan->GetChildIDs()) + m_channel_muted_parent.insert(child_id); + m_signal_channel_muted.emit(channel_id); } } else { m_muted_channels.erase(channel_id); if (was_muted) { + if (const auto chan = GetChannel(channel_id); chan.has_value() && chan->IsCategory()) + for (const auto child_id : chan->GetChildIDs()) + m_channel_muted_parent.erase(child_id); + m_signal_channel_unmuted.emit(channel_id); } } @@ -2357,6 +2374,14 @@ void DiscordClient::HandleReadyReadState(const ReadyEventData &data) { } void DiscordClient::HandleReadyGuildSettings(const ReadyEventData &data) { + // i dont like this implementation for muted categories but its rather simple and doesnt use a horriiible amount of ram + + std::unordered_map> category_children; + for (const auto &guild : data.Guilds) + for (const auto &channel : *guild.Channels) + if (channel.ParentID.has_value() && !channel.IsThread()) + category_children[*channel.ParentID].push_back(channel.ID); + const auto now = Snowflake::FromNow(); for (const auto &entry : data.GuildSettings.Entries) { // even if muted is true a guild/channel can be unmuted if the current time passes mute_config.end_time @@ -2371,6 +2396,10 @@ void DiscordClient::HandleReadyGuildSettings(const ReadyEventData &data) { } for (const auto &override : entry.ChannelOverrides) { if (override.Muted) { + if (const auto iter = category_children.find(override.ChannelID); iter != category_children.end()) + for (const auto child : iter->second) + m_channel_muted_parent.insert(child); + if (override.MuteConfig.EndTime.has_value()) { const auto end = Snowflake::FromISO8601(*override.MuteConfig.EndTime); if (end.IsValid() && end > now) diff --git a/src/discord/discord.hpp b/src/discord/discord.hpp index 44f02bb..69cfcf7 100644 --- a/src/discord/discord.hpp +++ b/src/discord/discord.hpp @@ -82,6 +82,7 @@ public: std::vector GetActiveThreads(Snowflake channel_id) const; void GetArchivedPublicThreads(Snowflake channel_id, sigc::slot callback); void GetArchivedPrivateThreads(Snowflake channel_id, sigc::slot callback); + std::vector GetChildChannelIDs(Snowflake parent_id) const; bool IsThreadJoined(Snowflake thread_id) const; bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const; @@ -290,6 +291,7 @@ private: std::unordered_set m_muted_guilds; std::unordered_set m_muted_channels; std::unordered_map m_unread; + std::unordered_set m_channel_muted_parent; UserData m_user_data; UserSettings m_user_settings; diff --git a/src/discord/store.cpp b/src/discord/store.cpp index 5e4e3b3..aa97178 100644 --- a/src/discord/store.cpp +++ b/src/discord/store.cpp @@ -571,6 +571,21 @@ std::vector Store::GetActiveThreads(Snowflake channel_id) const { return ret; } +std::vector Store::GetChannelIDsWithParentID(Snowflake channel_id) const { + auto &s = m_stmt_get_chan_ids_parent; + + s->Bind(1, channel_id); + + std::vector ret; + while (s->FetchOne()) { + Snowflake x; + s->Get(0, x); + ret.push_back(x); + } + + return ret; +} + void Store::AddReaction(const MessageReactionAddObject &data, bool byself) { auto &s = m_stmt_add_reaction; @@ -2120,6 +2135,14 @@ bool Store::CreateStatements() { return false; } + m_stmt_get_chan_ids_parent = std::make_unique(m_db, R"( + SELECT id FROM channels WHERE parent_id = ? + )"); + if (!m_stmt_get_chan_ids_parent->OK()) { + fprintf(stderr, "failed to prepare get channel ids for parent statement: %s\n", m_db.ErrStr()); + return false; + } + return true; } diff --git a/src/discord/store.hpp b/src/discord/store.hpp index 715f280..4320807 100644 --- a/src/discord/store.hpp +++ b/src/discord/store.hpp @@ -43,6 +43,7 @@ public: std::vector GetMessagesBefore(Snowflake channel_id, Snowflake message_id, size_t limit) const; std::vector GetPinnedMessages(Snowflake channel_id) const; std::vector GetActiveThreads(Snowflake channel_id) const; // public + std::vector GetChannelIDsWithParentID(Snowflake channel_id) const; void AddReaction(const MessageReactionAddObject &data, bool byself); void RemoveReaction(const MessageReactionRemoveObject &data, bool byself); @@ -300,5 +301,6 @@ private: STMT(add_reaction); STMT(sub_reaction); STMT(get_reactions); + STMT(get_chan_ids_parent); #undef STMT }; -- cgit v1.2.3