diff options
Diffstat (limited to 'src/components/channels.cpp')
-rw-r--r-- | src/components/channels.cpp | 212 |
1 files changed, 191 insertions, 21 deletions
diff --git a/src/components/channels.cpp b/src/components/channels.cpp index b691ab5..e45b5c0 100644 --- a/src/components/channels.cpp +++ b/src/components/channels.cpp @@ -19,8 +19,16 @@ ChannelList::ChannelList() , m_menu_channel_open_tab("Open in New _Tab", true) , m_menu_dm_open_tab("Open in New _Tab", true) #endif +#ifdef WITH_VOICE + , m_menu_voice_channel_join("_Join", true) + , m_menu_voice_channel_disconnect("_Disconnect", true) +#endif , m_menu_dm_copy_id("_Copy ID", true) , m_menu_dm_close("") // changes depending on if group or not +#ifdef WITH_VOICE + , m_menu_dm_join_voice("Join _Voice", true) + , m_menu_dm_disconnect_voice("_Disconnect Voice", true) +#endif , m_menu_thread_copy_id("_Copy ID", true) , m_menu_thread_leave("_Leave", true) , m_menu_thread_archive("_Archive", true) @@ -34,7 +42,11 @@ ChannelList::ChannelList() 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 +#ifdef WITH_VOICE + if (type != RenderType::TextChannel && type != RenderType::VoiceChannel) { +#else if (type != RenderType::TextChannel) { +#endif if (row[m_columns.m_expanded]) { m_view.collapse_row(path); row[m_columns.m_expanded] = false; @@ -44,7 +56,11 @@ ChannelList::ChannelList() } } +#ifdef WITH_VOICE + if (type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread || type == RenderType::VoiceChannel) { +#else if (type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread) { +#endif const auto id = static_cast<Snowflake>(row[m_columns.m_id]); m_signal_action_channel_item_select.emit(id); Abaddon::Get().GetDiscordClient().MarkChannelAsRead(id, [](...) {}); @@ -160,6 +176,21 @@ ChannelList::ChannelList() m_menu_channel.append(m_menu_channel_copy_id); m_menu_channel.show_all(); +#ifdef WITH_VOICE + m_menu_voice_channel_join.signal_activate().connect([this]() { + const auto id = static_cast<Snowflake>((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]); + m_signal_action_join_voice_channel.emit(id); + }); + + m_menu_voice_channel_disconnect.signal_activate().connect([this]() { + m_signal_action_disconnect_voice.emit(); + }); + + m_menu_voice_channel.append(m_menu_voice_channel_join); + m_menu_voice_channel.append(m_menu_voice_channel_disconnect); + m_menu_voice_channel.show_all(); +#endif + m_menu_dm_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])); }); @@ -191,6 +222,17 @@ ChannelList::ChannelList() #endif m_menu_dm.append(m_menu_dm_toggle_mute); m_menu_dm.append(m_menu_dm_close); +#ifdef WITH_VOICE + m_menu_dm_join_voice.signal_activate().connect([this]() { + const auto id = static_cast<Snowflake>((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]); + m_signal_action_join_voice_channel.emit(id); + }); + m_menu_dm_disconnect_voice.signal_activate().connect([this]() { + m_signal_action_disconnect_voice.emit(); + }); + m_menu_dm.append(m_menu_dm_join_voice); + m_menu_dm.append(m_menu_dm_disconnect_voice); +#endif m_menu_dm.append(m_menu_dm_copy_id); m_menu_dm.show_all(); @@ -244,6 +286,11 @@ ChannelList::ChannelList() discord.signal_channel_unmuted().connect(sigc::mem_fun(*this, &ChannelList::OnChannelUnmute)); discord.signal_guild_muted().connect(sigc::mem_fun(*this, &ChannelList::OnGuildMute)); discord.signal_guild_unmuted().connect(sigc::mem_fun(*this, &ChannelList::OnGuildUnmute)); + +#if WITH_VOICE + discord.signal_voice_user_connect().connect(sigc::mem_fun(*this, &ChannelList::OnVoiceUserConnect)); + discord.signal_voice_user_disconnect().connect(sigc::mem_fun(*this, &ChannelList::OnVoiceUserDisconnect)); +#endif } void ChannelList::UsePanedHack(Gtk::Paned &paned) { @@ -332,13 +379,13 @@ void ChannelList::UpdateRemoveGuild(Snowflake id) { } void ChannelList::UpdateRemoveChannel(Snowflake id) { - auto iter = GetIteratorForChannelFromID(id); + auto iter = GetIteratorForRowFromID(id); if (!iter) return; m_model->erase(iter); } void ChannelList::UpdateChannel(Snowflake id) { - auto iter = GetIteratorForChannelFromID(id); + auto iter = GetIteratorForRowFromID(id); auto channel = Abaddon::Get().GetDiscordClient().GetChannel(id); if (!iter || !channel.has_value()) return; if (channel->Type == ChannelType::GUILD_CATEGORY) return UpdateChannelCategory(*channel); @@ -353,7 +400,7 @@ void ChannelList::UpdateChannel(Snowflake id) { // check if the parent has changed Gtk::TreeModel::iterator new_parent; if (channel->ParentID.has_value()) - new_parent = GetIteratorForChannelFromID(*channel->ParentID); + new_parent = GetIteratorForRowFromID(*channel->ParentID); else if (channel->GuildID.has_value()) new_parent = GetIteratorForGuildFromID(*channel->GuildID); @@ -370,7 +417,7 @@ void ChannelList::UpdateCreateChannel(const ChannelData &channel) { bool orphan; if (channel.ParentID.has_value()) { orphan = false; - auto iter = GetIteratorForChannelFromID(*channel.ParentID); + auto iter = GetIteratorForRowFromID(*channel.ParentID); channel_row = *m_model->append(iter->children()); } else { orphan = true; @@ -412,10 +459,10 @@ void ChannelList::UpdateGuild(Snowflake id) { } void ChannelList::OnThreadJoined(Snowflake id) { - if (GetIteratorForChannelFromID(id)) return; + if (GetIteratorForRowFromID(id)) return; const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(id); if (!channel.has_value()) return; - const auto parent = GetIteratorForChannelFromID(*channel->ParentID); + const auto parent = GetIteratorForRowFromID(*channel->ParentID); if (parent) CreateThreadRow(parent->children(), *channel); } @@ -430,7 +477,7 @@ 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); + auto iter = GetIteratorForRowFromID(data.Thread.ID); if (iter) (*iter)[m_columns.m_name] = "- " + Glib::Markup::escape_text(*data.Thread.Name); @@ -459,7 +506,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()) { - auto iter = GetIteratorForChannelFromID(thread_id); + auto iter = GetIteratorForRowFromID(thread_id); m_model->erase(iter); } } @@ -467,25 +514,49 @@ void ChannelList::OnThreadListSync(const ThreadListSyncData &data) { // delete all archived threads for (auto thread : data.Threads) { if (thread.ThreadMetadata->IsArchived) { - if (auto iter = GetIteratorForChannelFromID(thread.ID)) + if (auto iter = GetIteratorForRowFromID(thread.ID)) m_model->erase(iter); } } } +#ifdef WITH_VOICE +void ChannelList::OnVoiceUserConnect(Snowflake user_id, Snowflake channel_id) { + auto parent_iter = GetIteratorForRowFromIDOfType(channel_id, RenderType::VoiceChannel); + if (!parent_iter) return; + const auto user = Abaddon::Get().GetDiscordClient().GetUser(user_id); + if (!user.has_value()) return; + + auto user_row = *m_model->append(parent_iter->children()); + user_row[m_columns.m_type] = RenderType::VoiceParticipant; + user_row[m_columns.m_id] = user_id; + if (user.has_value()) { + user_row[m_columns.m_name] = user->GetEscapedName(); + } else { + user_row[m_columns.m_name] = "<i>Unknown</i>"; + } +} + +void ChannelList::OnVoiceUserDisconnect(Snowflake user_id, Snowflake channel_id) { + if (auto iter = GetIteratorForRowFromIDOfType(user_id, RenderType::VoiceParticipant)) { + m_model->erase(iter); + } +} +#endif + void ChannelList::DeleteThreadRow(Snowflake id) { - auto iter = GetIteratorForChannelFromID(id); + auto iter = GetIteratorForRowFromID(id); if (iter) m_model->erase(iter); } void ChannelList::OnChannelMute(Snowflake id) { - if (auto iter = GetIteratorForChannelFromID(id)) + if (auto iter = GetIteratorForRowFromID(id)) m_model->row_changed(m_model->get_path(iter), iter); } void ChannelList::OnChannelUnmute(Snowflake id) { - if (auto iter = GetIteratorForChannelFromID(id)) + if (auto iter = GetIteratorForRowFromID(id)) m_model->row_changed(m_model->get_path(iter), iter); } @@ -516,7 +587,7 @@ void ChannelList::SetActiveChannel(Snowflake id, bool expand_to) { m_temporary_thread_row = {}; } - const auto channel_iter = GetIteratorForChannelFromID(id); + const auto channel_iter = GetIteratorForRowFromID(id); if (channel_iter) { if (expand_to) { m_view.expand_to_path(m_model->get_path(channel_iter)); @@ -526,7 +597,7 @@ void ChannelList::SetActiveChannel(Snowflake id, bool expand_to) { m_view.get_selection()->unselect_all(); const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(id); if (!channel.has_value() || !channel->IsThread()) return; - auto parent_iter = GetIteratorForChannelFromID(*channel->ParentID); + auto parent_iter = GetIteratorForRowFromID(*channel->ParentID); if (!parent_iter) return; m_temporary_thread_row = CreateThreadRow(parent_iter->children(), *channel); m_view.get_selection()->select(m_temporary_thread_row); @@ -662,7 +733,11 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild, const Gtk for (const auto &channel_ : *guild.Channels) { const auto channel = discord.GetChannel(channel_.ID); if (!channel.has_value()) continue; +#ifdef WITH_VOICE + if (channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::GUILD_NEWS || channel->Type == ChannelType::GUILD_VOICE) { +#else if (channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::GUILD_NEWS) { +#endif if (channel->ParentID.has_value()) categories[*channel->ParentID].push_back(*channel); else @@ -688,9 +763,33 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild, const Gtk m_tmp_row_map[thread.ID] = CreateThreadRow(row.children(), thread); }; +#ifdef WITH_VOICE + auto add_voice_participants = [this, &discord](const ChannelData &channel, const Gtk::TreeNodeChildren &root) { + for (auto user_id : discord.GetUsersInVoiceChannel(channel.ID)) { + const auto user = discord.GetUser(user_id); + + auto user_row = *m_model->append(root); + user_row[m_columns.m_type] = RenderType::VoiceParticipant; + user_row[m_columns.m_id] = user_id; + if (user.has_value()) { + user_row[m_columns.m_name] = user->GetEscapedName(); + } else { + user_row[m_columns.m_name] = "<i>Unknown</i>"; + } + } + }; +#endif + for (const auto &channel : orphan_channels) { auto channel_row = *m_model->append(guild_row.children()); - channel_row[m_columns.m_type] = RenderType::TextChannel; + if (IsTextChannel(channel.Type)) + channel_row[m_columns.m_type] = RenderType::TextChannel; +#ifdef WITH_VOICE + else { + channel_row[m_columns.m_type] = RenderType::VoiceChannel; + add_voice_participants(channel, channel_row->children()); + } +#endif 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_sort] = *channel.Position + OrphanChannelSortOffset; @@ -713,7 +812,14 @@ Gtk::TreeModel::iterator ChannelList::AddGuild(const GuildData &guild, const Gtk for (const auto &channel : channels) { auto channel_row = *m_model->append(cat_row.children()); - channel_row[m_columns.m_type] = RenderType::TextChannel; + if (IsTextChannel(channel.Type)) + channel_row[m_columns.m_type] = RenderType::TextChannel; +#ifdef WITH_VOICE + else { + channel_row[m_columns.m_type] = RenderType::VoiceChannel; + add_voice_participants(channel, channel_row->children()); + } +#endif 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_sort] = *channel.Position; @@ -753,7 +859,7 @@ Gtk::TreeModel::iterator ChannelList::CreateThreadRow(const Gtk::TreeNodeChildre } void ChannelList::UpdateChannelCategory(const ChannelData &channel) { - auto iter = GetIteratorForChannelFromID(channel.ID); + auto iter = GetIteratorForRowFromID(channel.ID); if (!iter) return; (*iter)[m_columns.m_sort] = *channel.Position; @@ -791,7 +897,7 @@ Gtk::TreeModel::iterator ChannelList::GetIteratorForGuildFromID(Snowflake id) { return {}; } -Gtk::TreeModel::iterator ChannelList::GetIteratorForChannelFromID(Snowflake id) { +Gtk::TreeModel::iterator ChannelList::GetIteratorForRowFromID(Snowflake id) { std::queue<Gtk::TreeModel::iterator> queue; for (const auto &child : m_model->children()) for (const auto &child2 : child.children()) @@ -808,6 +914,23 @@ Gtk::TreeModel::iterator ChannelList::GetIteratorForChannelFromID(Snowflake id) return {}; } +Gtk::TreeModel::iterator ChannelList::GetIteratorForRowFromIDOfType(Snowflake id, RenderType type) { + std::queue<Gtk::TreeModel::iterator> queue; + for (const auto &child : m_model->children()) + for (const auto &child2 : child.children()) + queue.push(child2); + + while (!queue.empty()) { + auto item = queue.front(); + if ((*item)[m_columns.m_type] == type && (*item)[m_columns.m_id] == id) return item; + for (const auto &child : item->children()) + queue.push(child); + queue.pop(); + } + + return {}; +} + bool ChannelList::IsTextChannel(ChannelType type) { return type == ChannelType::GUILD_TEXT || type == ChannelType::GUILD_NEWS; } @@ -838,7 +961,11 @@ bool ChannelList::SelectionFunc(const Glib::RefPtr<Gtk::TreeModel> &model, const m_last_selected = m_model->get_path(row); auto type = (*m_model->get_iter(path))[m_columns.m_type]; +#ifdef WITH_VOICE + return type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread || type == RenderType::VoiceChannel; +#else return type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread; +#endif } void ChannelList::AddPrivateChannels() { @@ -914,7 +1041,7 @@ void ChannelList::UpdateCreateDMChannel(const ChannelData &dm) { void ChannelList::OnMessageAck(const MessageAckData &data) { // trick renderer into redrawing m_model->row_changed(Gtk::TreeModel::Path("0"), m_model->get_iter("0")); // 0 is always path for dm header - auto iter = GetIteratorForChannelFromID(data.ChannelID); + auto iter = GetIteratorForRowFromID(data.ChannelID); if (iter) m_model->row_changed(m_model->get_path(iter), iter); auto channel = Abaddon::Get().GetDiscordClient().GetChannel(data.ChannelID); if (channel.has_value() && channel->GuildID.has_value()) { @@ -924,7 +1051,7 @@ void ChannelList::OnMessageAck(const MessageAckData &data) { } void ChannelList::OnMessageCreate(const Message &msg) { - auto iter = GetIteratorForChannelFromID(msg.ChannelID); + auto iter = GetIteratorForRowFromID(msg.ChannelID); if (iter) m_model->row_changed(m_model->get_path(iter), iter); // redraw const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(msg.ChannelID); if (!channel.has_value()) return; @@ -954,6 +1081,12 @@ bool ChannelList::OnButtonPressEvent(GdkEventButton *ev) { OnChannelSubmenuPopup(); m_menu_channel.popup_at_pointer(reinterpret_cast<GdkEvent *>(ev)); break; +#ifdef WITH_VOICE + case RenderType::VoiceChannel: + OnVoiceChannelSubmenuPopup(); + m_menu_voice_channel.popup_at_pointer(reinterpret_cast<GdkEvent *>(ev)); + break; +#endif case RenderType::DM: { OnDMSubmenuPopup(); const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(static_cast<Snowflake>(row[m_columns.m_id])); @@ -1046,14 +1179,41 @@ void ChannelList::OnChannelSubmenuPopup() { m_menu_channel_toggle_mute.set_label("Mute"); } +#ifdef WITH_VOICE +void ChannelList::OnVoiceChannelSubmenuPopup() { + const auto iter = m_model->get_iter(m_path_for_menu); + if (!iter) return; + const auto id = static_cast<Snowflake>((*iter)[m_columns.m_id]); + auto &discord = Abaddon::Get().GetDiscordClient(); + if (discord.IsVoiceConnected() || discord.IsVoiceConnecting()) { + m_menu_voice_channel_join.set_sensitive(false); + m_menu_voice_channel_disconnect.set_sensitive(discord.GetVoiceChannelID() == id); + } else { + m_menu_voice_channel_join.set_sensitive(true); + m_menu_voice_channel_disconnect.set_sensitive(false); + } +} +#endif + void ChannelList::OnDMSubmenuPopup() { auto iter = m_model->get_iter(m_path_for_menu); if (!iter) return; const auto id = static_cast<Snowflake>((*iter)[m_columns.m_id]); - if (Abaddon::Get().GetDiscordClient().IsChannelMuted(id)) + auto &discord = Abaddon::Get().GetDiscordClient(); + if (discord.IsChannelMuted(id)) m_menu_dm_toggle_mute.set_label("Unmute"); else m_menu_dm_toggle_mute.set_label("Mute"); + +#ifdef WITH_VOICE + if (discord.IsVoiceConnected() || discord.IsVoiceConnecting()) { + m_menu_dm_join_voice.set_sensitive(false); + m_menu_dm_disconnect_voice.set_sensitive(discord.GetVoiceChannelID() == id); + } else { + m_menu_dm_join_voice.set_sensitive(true); + m_menu_dm_disconnect_voice.set_sensitive(false); + } +#endif } void ChannelList::OnThreadSubmenuPopup() { @@ -1096,6 +1256,16 @@ ChannelList::type_signal_action_open_new_tab ChannelList::signal_action_open_new } #endif +#ifdef WITH_VOICE +ChannelList::type_signal_action_join_voice_channel ChannelList::signal_action_join_voice_channel() { + return m_signal_action_join_voice_channel; +} + +ChannelList::type_signal_action_disconnect_voice ChannelList::signal_action_disconnect_voice() { + return m_signal_action_disconnect_voice; +} +#endif + ChannelList::ModelColumns::ModelColumns() { add(m_type); add(m_id); |