summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2020-10-13 23:56:00 -0400
committerouwou <26526779+ouwou@users.noreply.github.com>2020-10-13 23:56:00 -0400
commit49a6e581375fdf0b5f5e82f981ca2d7cb419267f (patch)
treec40aa70216159b47a2747d0095020b2696d32684 /components
parentae85d7e4419a1dc6ab78cad9124f0febe1ff3259 (diff)
downloadabaddon-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.cpp271
-rw-r--r--components/channels.hpp29
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);