diff options
author | ouwou <26526779+ouwou@users.noreply.github.com> | 2020-10-13 23:56:00 -0400 |
---|---|---|
committer | ouwou <26526779+ouwou@users.noreply.github.com> | 2020-10-13 23:56:00 -0400 |
commit | 49a6e581375fdf0b5f5e82f981ca2d7cb419267f (patch) | |
tree | c40aa70216159b47a2747d0095020b2696d32684 /components | |
parent | ae85d7e4419a1dc6ab78cad9124f0febe1ff3259 (diff) | |
download | abaddon-portaudio-49a6e581375fdf0b5f5e82f981ca2d7cb419267f.tar.gz abaddon-portaudio-49a6e581375fdf0b5f5e82f981ca2d7cb419267f.zip |
join/leave guild updates without reloading entire channel list
Diffstat (limited to 'components')
-rw-r--r-- | components/channels.cpp | 271 | ||||
-rw-r--r-- | components/channels.hpp | 29 |
2 files changed, 183 insertions, 117 deletions
diff --git a/components/channels.cpp b/components/channels.cpp index 76519bf..30eed2c 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -5,13 +5,9 @@ #include "../abaddon.hpp" #include "../imgmanager.hpp" -ChannelListRow::type_signal_list_collapse ChannelListRow::signal_list_collapse() { - return m_signal_list_collapse; -} +void ChannelListRow::Collapse() {} -ChannelListRow::type_signal_list_uncollapse ChannelListRow::signal_list_uncollapse() { - return m_signal_list_uncollapse; -} +void ChannelListRow::Expand() {} ChannelListRowDMHeader::ChannelListRowDMHeader() { m_ev = Gtk::manage(new Gtk::EventBox); @@ -119,14 +115,6 @@ ChannelListRowCategory::ChannelListRowCategory(const Channel *data) { get_style_context()->add_class("channel-row-category"); m_lbl->get_style_context()->add_class("channel-row-label"); - m_signal_list_collapse.connect([this]() { - m_arrow->set(Gtk::ARROW_RIGHT, Gtk::SHADOW_NONE); - }); - - m_signal_list_uncollapse.connect([this]() { - m_arrow->set(Gtk::ARROW_DOWN, Gtk::SHADOW_NONE); - }); - m_lbl->set_text(data->Name); m_box->set_halign(Gtk::ALIGN_START); m_box->pack_start(*m_arrow); @@ -136,6 +124,14 @@ ChannelListRowCategory::ChannelListRowCategory(const Channel *data) { show_all_children(); } +void ChannelListRowCategory::Collapse() { + m_arrow->set(Gtk::ARROW_RIGHT, Gtk::SHADOW_NONE); +} + +void ChannelListRowCategory::Expand() { + m_arrow->set(Gtk::ARROW_DOWN, Gtk::SHADOW_NONE); +} + ChannelListRowChannel::ChannelListRowChannel(const Channel *data) { ID = data->ID; m_ev = Gtk::manage(new Gtk::EventBox); @@ -202,11 +198,79 @@ void ChannelList::UpdateListing() { m_update_dispatcher.emit(); } +void ChannelList::UpdateNewGuild(Snowflake id) { + auto sort = Abaddon::Get().GetDiscordClient().GetUserSortedGuilds(); + if (sort.size() == 1) { + UpdateListing(); + return; + } + + const auto insert_at = [this, id](int listpos) { + InsertGuildAt(id, listpos); + }; + + auto it = std::find(sort.begin(), sort.end(), id); + if (it == sort.end()) return; + // if the new guild pos is at the end use -1 + if (it + 1 == sort.end()) { + insert_at(-1); + return; + } + // find the position of the guild below it into the listbox + auto below_id = *(it + 1); + auto below_it = m_id_to_row.find(below_id); + if (below_it == m_id_to_row.end()) { + UpdateListing(); + return; + } + auto below_pos = below_it->second->get_index(); + // stick it just above + insert_at(below_pos - 1); +} + +void ChannelList::UpdateRemoveGuild(Snowflake id) { + auto it = m_guild_id_to_row.find(id); + if (it == m_guild_id_to_row.end()) return; + auto row = dynamic_cast<ChannelListRow *>(it->second); + if (row == nullptr) return; + DeleteRow(row); +} + void ChannelList::Clear() { //std::scoped_lock<std::mutex> guard(m_update_mutex); m_update_dispatcher.emit(); } +void ChannelList::CollapseRow(ChannelListRow *row) { + row->Collapse(); + for (auto child : row->Children) { + row->IsHidden = true; + child->hide(); + CollapseRow(child); + } +} + +void ChannelList::ExpandRow(ChannelListRow *row) { + row->Expand(); + row->show(); + row->IsHidden = false; + if (!row->IsUserCollapsed) + for (auto child : row->Children) + ExpandRow(child); +} + +void ChannelList::DeleteRow(ChannelListRow *row) { + for (auto child : row->Children) + DeleteRow(child); + if (row->Parent != nullptr) + row->Parent->Children.erase(row); + if (dynamic_cast<ChannelListRowGuild *>(row) != nullptr) + m_guild_id_to_row.erase(row->ID); + else + m_id_to_row.erase(row->ID); + delete row; +} + void ChannelList::on_row_activated(Gtk::ListBoxRow *tmprow) { auto row = dynamic_cast<ChannelListRow *>(tmprow); if (row == nullptr) return; @@ -217,26 +281,89 @@ void ChannelList::on_row_activated(Gtk::ListBoxRow *tmprow) { if (dynamic_cast<ChannelListRowChannel *>(row) != nullptr || dynamic_cast<ChannelListRowDMChannel *>(row) != nullptr) m_signal_action_channel_item_select.emit(row->ID); - if (new_collapsed) { - std::function<void(ChannelListRow *)> collapse_children = [&](ChannelListRow *row) { - row->signal_list_collapse().emit(); - for (auto child : row->Children) { - row->IsHidden = true; - child->hide(); - collapse_children(child); + if (new_collapsed) + CollapseRow(row); + else + ExpandRow(row); +} + +void ChannelList::InsertGuildAt(Snowflake id, int pos) { + const auto insert_and_adjust = [&](Gtk::Widget &widget) { + m_list->insert(widget, pos); + if (pos != -1) pos++; + }; + + const auto &discord = Abaddon::Get().GetDiscordClient(); + const auto *guild_data = discord.GetGuild(id); + if (guild_data == nullptr) return; + + std::map<int, const Channel *> orphan_channels; + std::unordered_map<Snowflake, std::vector<const Channel *>> cat_to_channels; + for (const auto &channel : guild_data->Channels) { + if (channel.Type != ChannelType::GUILD_TEXT) continue; + + if (channel.ParentID.IsValid()) + cat_to_channels[channel.ParentID].push_back(&channel); + else + orphan_channels[channel.Position] = &channel; + } + + auto *guild_row = Gtk::manage(new ChannelListRowGuild(guild_data)); + guild_row->show_all(); + guild_row->IsUserCollapsed = true; + guild_row->IsHidden = false; + guild_row->GuildIndex = m_guild_count++; + insert_and_adjust(*guild_row); + m_guild_id_to_row[guild_row->ID] = guild_row; + AttachGuildMenuHandler(guild_row); + + // add channels with no parent category + for (const auto &[pos, channel] : orphan_channels) { + auto *chan_row = Gtk::manage(new ChannelListRowChannel(channel)); + chan_row->IsUserCollapsed = false; + chan_row->IsHidden = true; + insert_and_adjust(*chan_row); + guild_row->Children.insert(chan_row); + chan_row->Parent = guild_row; + m_id_to_row[chan_row->ID] = chan_row; + } + + // categories + std::map<int, std::vector<const Channel *>> sorted_categories; + for (const auto &channel : guild_data->Channels) + if (channel.Type == ChannelType::GUILD_CATEGORY) + sorted_categories[channel.Position].push_back(&channel); + + for (auto &[pos, catvec] : sorted_categories) { + std::sort(catvec.begin(), catvec.end(), [](const Channel *a, const Channel *b) { return a->ID < b->ID; }); + for (const auto cat : catvec) { + auto *cat_row = Gtk::manage(new ChannelListRowCategory(cat)); + cat_row->IsUserCollapsed = false; + cat_row->IsHidden = true; + AttachChannelMenuHandler(cat_row); + insert_and_adjust(*cat_row); + guild_row->Children.insert(cat_row); + cat_row->Parent = guild_row; + m_id_to_row[cat_row->ID] = cat_row; + + // child channels + if (cat_to_channels.find(cat->ID) == cat_to_channels.end()) continue; + std::map<int, const Channel *> sorted_channels; + + for (const auto channel : cat_to_channels.at(cat->ID)) + sorted_channels[channel->Position] = channel; + + for (const auto &[pos, channel] : sorted_channels) { + auto *chan_row = Gtk::manage(new ChannelListRowChannel(channel)); + chan_row->IsHidden = false; + chan_row->IsUserCollapsed = false; + AttachChannelMenuHandler(chan_row); + insert_and_adjust(*chan_row); + cat_row->Children.insert(chan_row); + chan_row->Parent = cat_row; + m_id_to_row[chan_row->ID] = chan_row; } - }; - collapse_children(row); - } else { - std::function<void(ChannelListRow *)> restore_children = [&](ChannelListRow *row) { - row->signal_list_uncollapse().emit(); - row->show(); - row->IsHidden = false; - if (!row->IsUserCollapsed) - for (auto row : row->Children) - restore_children(row); - }; - restore_children(row); + } } } @@ -269,87 +396,15 @@ void ChannelList::UpdateListingInternal() { it++; } + m_id_to_row.clear(); + m_guild_count = 0; AddPrivateChannels(); - // map each category to its channels - - std::unordered_map<Snowflake, std::vector<const Channel *>> cat_to_channels; - std::unordered_map<Snowflake, std::map<Snowflake, const Channel *>> orphan_channels; - for (const auto gid : guilds) { - const auto *guild = Abaddon::Get().GetDiscordClient().GetGuild(gid); - for (const auto &chan : guild->Channels) { - switch (chan.Type) { - case ChannelType::GUILD_TEXT: { - if (chan.ParentID.IsValid()) - cat_to_channels[chan.ParentID].push_back(&chan); - else - orphan_channels[gid][chan.Position] = &chan; - } break; - default: - break; - } - } - } - - // idk why i even bother with the queue auto sorted_guilds = Abaddon::Get().GetDiscordClient().GetUserSortedGuilds(); for (auto gid : sorted_guilds) { - // add guild row - const auto *guild_data = Abaddon::Get().GetDiscordClient().GetGuild(gid); - auto *guild_row = Gtk::manage(new ChannelListRowGuild(guild_data)); - guild_row->show_all(); - guild_row->IsUserCollapsed = true; - guild_row->IsHidden = false; - guild_row->GuildIndex = m_guild_count++; - m_list->add(*guild_row); - AttachGuildMenuHandler(guild_row); - - // add channels with no parent category - if (orphan_channels.find(gid) != orphan_channels.end()) { - for (const auto &[pos, channel] : orphan_channels.at(gid)) { - auto *chan_row = Gtk::manage(new ChannelListRowChannel(channel)); - chan_row->IsUserCollapsed = false; - chan_row->IsHidden = true; - m_list->add(*chan_row); - guild_row->Children.insert(chan_row); - } - } - - // categories - std::map<int, std::vector<const Channel *>> sorted_categories; - for (const auto &channel : guild_data->Channels) - if (channel.Type == ChannelType::GUILD_CATEGORY) - sorted_categories[channel.Position].push_back(&channel); - - for (auto &[pos, catvec] : sorted_categories) { - std::sort(catvec.begin(), catvec.end(), [](const Channel *a, const Channel *b) { return a->ID < b->ID; }); - for (const auto cat : catvec) { - auto *cat_row = Gtk::manage(new ChannelListRowCategory(cat)); - cat_row->IsUserCollapsed = false; - cat_row->IsHidden = true; - AttachChannelMenuHandler(cat_row); - m_list->add(*cat_row); - guild_row->Children.insert(cat_row); - - // child channels - if (cat_to_channels.find(cat->ID) == cat_to_channels.end()) continue; - std::map<int, const Channel *> sorted_channels; - - for (const auto channel : cat_to_channels.at(cat->ID)) - sorted_channels[channel->Position] = channel; - - for (const auto &[pos, channel] : sorted_channels) { - auto *chan_row = Gtk::manage(new ChannelListRowChannel(channel)); - chan_row->IsHidden = false; - chan_row->IsUserCollapsed = false; - AttachChannelMenuHandler(chan_row); - m_list->add(*chan_row); - cat_row->Children.insert(chan_row); - } - } - } + InsertGuildAt(gid, -1); } } diff --git a/components/channels.hpp b/components/channels.hpp index 8215133..8989669 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -4,6 +4,7 @@ #include <queue> #include <mutex> #include <unordered_set> +#include <unordered_map> #include <sigc++/sigc++.h> #include "../discord/discord.hpp" @@ -13,16 +14,10 @@ public: bool IsHidden; Snowflake ID; std::unordered_set<ChannelListRow *> Children; + ChannelListRow *Parent = nullptr; - typedef sigc::signal<void> type_signal_list_collapse; - typedef sigc::signal<void> type_signal_list_uncollapse; - - type_signal_list_collapse signal_list_collapse(); - type_signal_list_uncollapse signal_list_uncollapse(); - -protected: - type_signal_list_collapse m_signal_list_collapse; - type_signal_list_uncollapse m_signal_list_uncollapse; + virtual void Collapse(); + virtual void Expand(); }; class ChannelListRowDMHeader : public ChannelListRow { @@ -67,6 +62,9 @@ class ChannelListRowCategory : public ChannelListRow { public: ChannelListRowCategory(const Channel *data); + virtual void Collapse(); + virtual void Expand(); + protected: Gtk::EventBox *m_ev; Gtk::Box *m_box; @@ -89,12 +87,18 @@ public: ChannelList(); Gtk::Widget *GetRoot() const; void UpdateListing(); + void UpdateNewGuild(Snowflake id); + void UpdateRemoveGuild(Snowflake id); void Clear(); protected: Gtk::ListBox *m_list; Gtk::ScrolledWindow *m_main; + void CollapseRow(ChannelListRow *row); + void ExpandRow(ChannelListRow *row); + void DeleteRow(ChannelListRow *row); + void on_row_activated(Gtk::ListBoxRow *row); int m_guild_count; @@ -115,6 +119,13 @@ protected: Glib::Dispatcher m_update_dispatcher; //mutable std::mutex m_update_mutex; //std::queue<std::unordered_set<Snowflake>> m_update_queue; + + // i would use one map but in really old guilds there can be a channel w/ same id as the guild so this hacky shit has to do + std::unordered_map<Snowflake, ChannelListRow *> m_guild_id_to_row; + std::unordered_map<Snowflake, ChannelListRow *> m_id_to_row; + + void InsertGuildAt(Snowflake id, int pos); + void AddPrivateChannels(); // retard moment void UpdateListingInternal(); void AttachGuildMenuHandler(Gtk::ListBoxRow *row); |