summaryrefslogtreecommitdiff
path: root/windows
diff options
context:
space:
mode:
Diffstat (limited to 'windows')
-rw-r--r--windows/guildsettings/auditlogpane.cpp636
-rw-r--r--windows/guildsettings/auditlogpane.hpp19
-rw-r--r--windows/guildsettings/banspane.cpp161
-rw-r--r--windows/guildsettings/banspane.hpp45
-rw-r--r--windows/guildsettings/emojispane.cpp257
-rw-r--r--windows/guildsettings/emojispane.hpp53
-rw-r--r--windows/guildsettings/infopane.cpp220
-rw-r--r--windows/guildsettings/infopane.hpp26
-rw-r--r--windows/guildsettings/invitespane.cpp136
-rw-r--r--windows/guildsettings/invitespane.hpp43
-rw-r--r--windows/guildsettings/memberspane.cpp410
-rw-r--r--windows/guildsettings/memberspane.hpp135
-rw-r--r--windows/guildsettings/rolespane.cpp419
-rw-r--r--windows/guildsettings/rolespane.hpp102
-rw-r--r--windows/guildsettingswindow.cpp76
-rw-r--r--windows/guildsettingswindow.hpp30
-rw-r--r--windows/mainwindow.cpp308
-rw-r--r--windows/mainwindow.hpp99
-rw-r--r--windows/pinnedwindow.cpp47
-rw-r--r--windows/pinnedwindow.hpp22
-rw-r--r--windows/profile/mutualfriendspane.cpp58
-rw-r--r--windows/profile/mutualfriendspane.hpp28
-rw-r--r--windows/profile/mutualguildspane.cpp73
-rw-r--r--windows/profile/mutualguildspane.hpp26
-rw-r--r--windows/profile/userinfopane.cpp236
-rw-r--r--windows/profile/userinfopane.hpp65
-rw-r--r--windows/profilewindow.cpp127
-rw-r--r--windows/profilewindow.hpp31
-rw-r--r--windows/threadswindow.cpp149
-rw-r--r--windows/threadswindow.hpp79
30 files changed, 0 insertions, 4116 deletions
diff --git a/windows/guildsettings/auditlogpane.cpp b/windows/guildsettings/auditlogpane.cpp
deleted file mode 100644
index 08f99da..0000000
--- a/windows/guildsettings/auditlogpane.cpp
+++ /dev/null
@@ -1,636 +0,0 @@
-#include "auditlogpane.hpp"
-#include "abaddon.hpp"
-
-using namespace std::string_literals;
-
-GuildSettingsAuditLogPane::GuildSettingsAuditLogPane(Snowflake id)
- : GuildID(id) {
- signal_map().connect(sigc::mem_fun(*this, &GuildSettingsAuditLogPane::OnMap));
- set_name("guild-audit-log-pane");
- set_hexpand(true);
- set_vexpand(true);
-
- m_list.set_selection_mode(Gtk::SELECTION_NONE);
- m_list.show();
- add(m_list);
-}
-
-void GuildSettingsAuditLogPane::OnMap() {
- if (m_requested) return;
- m_requested = true;
-
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto self_id = discord.GetUserData().ID;
-
- if (discord.HasGuildPermission(self_id, GuildID, Permission::VIEW_AUDIT_LOG))
- discord.FetchAuditLog(GuildID, sigc::mem_fun(*this, &GuildSettingsAuditLogPane::OnAuditLogFetch));
-}
-
-void GuildSettingsAuditLogPane::OnAuditLogFetch(const AuditLogData &data) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- auto guild = *discord.GetGuild(GuildID);
- for (const auto &entry : data.Entries) {
- if (entry.TargetID == "") continue;
-
- auto expander = Gtk::manage(new Gtk::Expander);
- auto label = Gtk::manage(new Gtk::Label);
- label->set_ellipsize(Pango::ELLIPSIZE_END);
-
- Glib::ustring user_markup = "<b>Unknown User</b>";
- if (entry.UserID.has_value()) {
- if (auto user = discord.GetUser(*entry.UserID); user.has_value())
- user_markup = discord.GetUser(*entry.UserID)->GetEscapedBoldString<false>();
- }
-
- // spaghetti moment
- Glib::ustring markup;
- std::vector<Glib::ustring> extra_markup;
- switch (entry.Type) {
- case AuditLogActionType::GUILD_UPDATE: {
- markup =
- user_markup +
- " made changes to <b>" +
- Glib::Markup::escape_text(guild.Name) +
- "</b>";
-
- if (entry.Changes.has_value())
- for (const auto &change : *entry.Changes) {
- if (change.Key == "icon_hash") {
- extra_markup.push_back("Set the server icon");
- } else if (change.Key == "name") {
- auto new_name = change.NewValue;
- if (new_name.has_value())
- extra_markup.push_back("Set the server name to <b>" +
- Glib::Markup::escape_text(new_name->get<std::string>()) +
- "</b>");
- else
- extra_markup.push_back("Set the server name");
- }
- }
- } break;
- case AuditLogActionType::CHANNEL_CREATE: {
- const auto type = *entry.GetNewFromKey<ChannelType>("type");
- markup = user_markup +
- " created a " + (type == ChannelType::GUILD_VOICE ? "voice" : "text") +
- " channel <b>#" +
- Glib::Markup::escape_text(*entry.GetNewFromKey<std::string>("name")) +
- "</b>";
- if (entry.Changes.has_value())
- for (const auto &change : *entry.Changes) {
- if (change.Key == "name" && change.NewValue.has_value())
- extra_markup.push_back("Set the name to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- else if (change.Key == "nsfw" && change.NewValue.has_value())
- extra_markup.push_back((*change.NewValue ? "Marked" : "Unmarked") +
- " the channel as NSFW"s);
- }
-
- } break;
- case AuditLogActionType::CHANNEL_UPDATE: {
- const auto target_channel = discord.GetChannel(entry.TargetID);
- if (target_channel.has_value()) {
- markup = user_markup +
- " made changes to <b>#" +
- Glib::Markup::escape_text(*target_channel->Name) +
- "</b>";
- } else {
- markup = user_markup +
- " made changes to <b>&lt;#" +
- entry.TargetID +
- "&gt;</b>";
- }
- if (entry.Changes.has_value())
- for (const auto &change : *entry.Changes) {
- if (change.Key == "name" && change.NewValue.has_value()) {
- if (change.OldValue.has_value())
- extra_markup.push_back("Changed the name from <b>" +
- Glib::Markup::escape_text(change.OldValue->get<std::string>()) +
- "</b> to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- else
- extra_markup.push_back("Changed the name to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- } else if (change.Key == "topic") {
- if (change.NewValue.has_value())
- extra_markup.push_back("Changed the topic to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- else
- extra_markup.push_back("Cleared the topic");
- } else if (change.Key == "nsfw" && change.NewValue.has_value()) {
- extra_markup.push_back((*change.NewValue ? "Marked" : "Unmarked") + " the channel as NSFW"s);
- } else if (change.Key == "rate_limit_per_user" && change.NewValue.has_value()) {
- const int secs = change.NewValue->get<int>();
- if (secs == 0)
- extra_markup.push_back("Disabled slowmode");
- else
- extra_markup.push_back("Set slowmode to <b>" +
- std::to_string(secs) + " seconds</b>");
- }
- }
- } break;
- case AuditLogActionType::CHANNEL_DELETE: {
- markup = user_markup +
- " removed <b>#" +
- Glib::Markup::escape_text(*entry.GetOldFromKey<std::string>("name")) +
- "</b>";
- } break;
- case AuditLogActionType::CHANNEL_OVERWRITE_CREATE: {
- const auto channel = discord.GetChannel(entry.TargetID);
- if (channel.has_value()) {
- markup = user_markup +
- " created channel overrides for <b>#" +
- Glib::Markup::escape_text(*channel->Name) + "</b>";
- } else {
- markup = user_markup +
- " created channel overrides for <b>&lt;#" +
- entry.TargetID + "&gt;</b>";
- }
- } break;
- case AuditLogActionType::CHANNEL_OVERWRITE_UPDATE: {
- const auto channel = discord.GetChannel(entry.TargetID);
- if (channel.has_value()) {
- markup = user_markup +
- " updated channel overrides for <b>#" +
- Glib::Markup::escape_text(*channel->Name) + "</b>";
- } else {
- markup = user_markup +
- " updated channel overrides for <b>&lt;#" +
- entry.TargetID + "&gt;</b>";
- }
- } break;
- case AuditLogActionType::CHANNEL_OVERWRITE_DELETE: {
- const auto channel = discord.GetChannel(entry.TargetID);
- if (channel.has_value()) {
- markup = user_markup +
- " removed channel overrides for <b>#" +
- Glib::Markup::escape_text(*channel->Name) + "</b>";
- } else {
- markup = user_markup +
- " removed channel overrides for <b>&lt;#" +
- entry.TargetID + "&gt;</b>";
- }
- } break;
- case AuditLogActionType::MEMBER_KICK: {
- const auto target_user = discord.GetUser(entry.TargetID);
- markup = user_markup +
- " kicked <b>" +
- target_user->GetEscapedString() +
- "</b>";
- } break;
- case AuditLogActionType::MEMBER_PRUNE: {
- markup = user_markup +
- " pruned <b>" +
- *entry.Options->MembersRemoved +
- "</b> members";
- extra_markup.push_back("For <b>" +
- *entry.Options->DeleteMemberDays +
- " days</b> of inactivity");
- } break;
- case AuditLogActionType::MEMBER_BAN_ADD: {
- const auto target_user = discord.GetUser(entry.TargetID);
- markup = user_markup +
- " banned <b>" +
- target_user->GetEscapedString() +
- "</b>";
- } break;
- case AuditLogActionType::MEMBER_BAN_REMOVE: {
- const auto target_user = discord.GetUser(entry.TargetID);
- markup = user_markup +
- " removed the ban for <b>" +
- target_user->GetEscapedString() +
- "</b>";
- } break;
- case AuditLogActionType::MEMBER_UPDATE: {
- const auto target_user = discord.GetUser(entry.TargetID);
- markup = user_markup +
- " updated <b>" +
- target_user->GetEscapedString() +
- "</b>";
- if (entry.Changes.has_value())
- for (const auto &change : *entry.Changes) {
- if (change.Key == "deaf" && change.NewValue.has_value())
- extra_markup.push_back(
- (change.NewValue->get<bool>() ? "<b>Deafened</b>"s : "<b>Undeafened</b>"s) +
- " them");
- else if (change.Key == "mute" && change.NewValue.has_value())
- extra_markup.push_back(
- (change.NewValue->get<bool>() ? "<b>Muted</b>"s : "<b>Unmuted</b>"s) +
- " them");
- else if (change.Key == "nick" && change.NewValue.has_value())
- extra_markup.push_back("Set their nickname to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- }
- } break;
- case AuditLogActionType::MEMBER_ROLE_UPDATE: {
- const auto target_user = discord.GetUser(entry.TargetID);
- markup = user_markup +
- " updated roles for <b>" +
- target_user->GetEscapedString() + "</b>";
- if (entry.Changes.has_value())
- for (const auto &change : *entry.Changes) {
- if (change.Key == "$remove" && change.NewValue.has_value()) {
- extra_markup.push_back("<b>Removed</b> a role <b>" +
- Glib::Markup::escape_text(change.NewValue.value()[0].at("name").get<std::string>()) +
- "</b>");
- } else if (change.Key == "$add" && change.NewValue.has_value()) {
- extra_markup.push_back("<b>Added</b> a role <b>" +
- Glib::Markup::escape_text(change.NewValue.value()[0].at("name").get<std::string>()) +
- "</b>");
- }
- }
- } break;
- case AuditLogActionType::MEMBER_MOVE: {
- const auto channel = discord.GetChannel(*entry.Options->ChannelID);
- markup = user_markup +
- " moved <b>" +
- *entry.Options->Count +
- " user" +
- (*entry.Options->Count == "1" ? ""s : "s"s) +
- "</b> to <b>" +
- Glib::Markup::escape_text(*channel->Name) +
- "</b>";
- } break;
- case AuditLogActionType::MEMBER_DISCONNECT: {
- markup = user_markup +
- " disconnected <b>" +
- *entry.Options->Count +
- "</b> users from voice";
- } break;
- case AuditLogActionType::BOT_ADD: {
- const auto target_user = discord.GetUser(entry.TargetID);
- markup = user_markup +
- " added <b>" +
- target_user->GetEscapedString() +
- "</b> to the server";
- } break;
- case AuditLogActionType::ROLE_CREATE: {
- markup = user_markup +
- " created the role <b>" +
- *entry.GetNewFromKey<std::string>("name") +
- "</b>";
- } break;
- case AuditLogActionType::ROLE_UPDATE: {
- const auto role = discord.GetRole(entry.TargetID);
- markup = user_markup +
- " updated the role <b>" +
- (role.has_value() ? Glib::Markup::escape_text(role->Name) : Glib::ustring(entry.TargetID)) +
- "</b>";
- if (entry.Changes.has_value())
- for (const auto &change : *entry.Changes) {
- if (change.Key == "name" && change.NewValue.has_value()) {
- extra_markup.push_back("Changed the name to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- } else if (change.Key == "color" && change.NewValue.has_value()) {
- const auto col = change.NewValue->get<int>();
- if (col == 0)
- extra_markup.push_back("Removed the color");
- else
- extra_markup.push_back("Set the color to <b>" +
- IntToCSSColor(col) +
- "</b>");
- } else if (change.Key == "permissions") {
- extra_markup.push_back("Updated the permissions");
- } else if (change.Key == "mentionable" && change.NewValue.has_value()) {
- extra_markup.push_back(change.NewValue->get<bool>() ? "Mentionable" : "Not mentionable");
- } else if (change.Key == "hoist" && change.NewValue.has_value()) {
- extra_markup.push_back(change.NewValue->get<bool>() ? "Not hoisted" : "Hoisted");
- }
- }
- } break;
- case AuditLogActionType::ROLE_DELETE: {
- markup = user_markup +
- " deleted the role <b>" +
- *entry.GetOldFromKey<std::string>("name") +
- "</b>";
- } break;
- case AuditLogActionType::INVITE_CREATE: {
- const auto code = *entry.GetNewFromKey<std::string>("code");
- markup = user_markup +
- " created an invite <b>" + code + "</b>";
- if (entry.Changes.has_value())
- for (const auto &change : *entry.Changes) {
- if (change.Key == "channel_id" && change.NewValue.has_value()) {
- const auto channel = discord.GetChannel(change.NewValue->get<Snowflake>());
- if (!channel.has_value()) continue;
- extra_markup.push_back("For channel <b>#" +
- Glib::Markup::escape_text(*channel->Name) +
- "</b>");
- } else if (change.Key == "max_uses" && change.NewValue.has_value()) {
- const auto uses = change.NewValue->get<int>();
- if (uses == 0)
- extra_markup.push_back("Which has <b>unlimited</b> uses");
- else
- extra_markup.push_back("Which has <b>" + std::to_string(uses) + "</b> uses");
- } else if (change.Key == "temporary" && change.NewValue.has_value()) {
- extra_markup.push_back("With temporary <b>"s +
- (change.NewValue->get<bool>() ? "on" : "off") +
- "</b>");
- } // no max_age cuz fuck time
- }
- } break;
- case AuditLogActionType::INVITE_DELETE: {
- markup = user_markup +
- " deleted an invite <b>" +
- *entry.GetOldFromKey<std::string>("code") +
- "</b>";
- } break;
- case AuditLogActionType::WEBHOOK_CREATE: {
- markup = user_markup +
- " created the webhook <b>" +
- Glib::Markup::escape_text(*entry.GetNewFromKey<std::string>("name")) +
- "</b>";
- for (const auto &change : *entry.Changes) {
- if (change.Key == "channel_id" && change.NewValue.has_value()) {
- const auto channel = discord.GetChannel(change.NewValue->get<Snowflake>());
- if (channel.has_value()) {
- extra_markup.push_back("With channel <b>#" +
- Glib::Markup::escape_text(*channel->Name) +
- "</b>");
- }
- }
- }
- } break;
- case AuditLogActionType::WEBHOOK_UPDATE: {
- const WebhookData *webhookptr = nullptr;
- for (const auto &webhook : data.Webhooks) {
- if (webhook.ID == entry.TargetID)
- webhookptr = &webhook;
- }
- if (webhookptr != nullptr) {
- markup = user_markup +
- " updated the webhook <b>" +
- Glib::Markup::escape_text(webhookptr->Name) +
- "</b>";
- } else {
- markup = user_markup +
- " updated a webhook";
- }
- if (entry.Changes.has_value())
- for (const auto &change : *entry.Changes) {
- if (change.Key == "name" && change.NewValue.has_value()) {
- extra_markup.push_back("Changed the name to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- } else if (change.Key == "avatar_hash") {
- extra_markup.push_back("Changed the avatar");
- } else if (change.Key == "channel_id" && change.NewValue.has_value()) {
- const auto channel = discord.GetChannel(change.NewValue->get<Snowflake>());
- if (channel.has_value()) {
- extra_markup.push_back("Changed the channel to <b>#" +
- Glib::Markup::escape_text(*channel->Name) +
- "</b>");
- } else {
- extra_markup.push_back("Changed the channel");
- }
- }
- }
- } break;
- case AuditLogActionType::WEBHOOK_DELETE: {
- markup = user_markup +
- " deleted the webhook <b>" +
- Glib::Markup::escape_text(*entry.GetOldFromKey<std::string>("name")) +
- "</b>";
- } break;
- case AuditLogActionType::EMOJI_CREATE: {
- markup = user_markup +
- " created the emoji <b>" +
- Glib::Markup::escape_text(*entry.GetNewFromKey<std::string>("name")) +
- "</b>";
- } break;
- case AuditLogActionType::EMOJI_UPDATE: {
- markup = user_markup +
- " updated the emoji <b>" +
- Glib::Markup::escape_text(*entry.GetOldFromKey<std::string>("name")) +
- "</b>";
- extra_markup.push_back("Changed the name from <b>" +
- Glib::Markup::escape_text(*entry.GetOldFromKey<std::string>("name")) +
- "</b> to <b>" +
- Glib::Markup::escape_text(*entry.GetNewFromKey<std::string>("name")) +
- "</b>");
- } break;
- case AuditLogActionType::EMOJI_DELETE: {
- markup = user_markup +
- " deleted the emoji <b>" +
- Glib::Markup::escape_text(*entry.GetOldFromKey<std::string>("name")) +
- "</b>";
- } break;
- case AuditLogActionType::MESSAGE_DELETE: {
- const auto channel = discord.GetChannel(*entry.Options->ChannelID);
- const auto count = *entry.Options->Count;
- if (channel.has_value()) {
- markup = user_markup +
- " deleted <b>" + count + "</b> messages in <b>#" +
- Glib::Markup::escape_text(*channel->Name) +
- "</b>";
- } else {
- markup = user_markup +
- " deleted <b>" + count + "</b> messages";
- }
- } break;
- case AuditLogActionType::MESSAGE_BULK_DELETE: {
- const auto channel = discord.GetChannel(entry.TargetID);
- if (channel.has_value()) {
- markup = user_markup +
- " deleted <b>" +
- *entry.Options->Count +
- "</b> messages in <b>#" +
- Glib::Markup::escape_text(*channel->Name) +
- "</b>";
- } else {
- markup = user_markup +
- " deleted <b>" +
- *entry.Options->Count +
- "</b> messages";
- }
- } break;
- case AuditLogActionType::MESSAGE_PIN: {
- const auto target_user = discord.GetUser(entry.TargetID);
- markup = user_markup +
- " pinned a message by <b>" +
- target_user->GetEscapedString() +
- "</b>";
- } break;
- case AuditLogActionType::MESSAGE_UNPIN: {
- const auto target_user = discord.GetUser(entry.TargetID);
- markup = user_markup +
- " unpinned a message by <b>" +
- target_user->GetEscapedString() +
- "</b>";
- } break;
- case AuditLogActionType::STAGE_INSTANCE_CREATE: {
- const auto channel = discord.GetChannel(*entry.Options->ChannelID);
- if (channel.has_value()) {
- markup = user_markup +
- " started the stage for <b>" +
- Glib::Markup::escape_text(*channel->Name) +
- "</b>";
- } else {
- markup = user_markup +
- " started the stage for <b>" +
- std::to_string(*entry.Options->ChannelID) +
- "</b>";
- }
-
- if (entry.Changes.has_value()) {
- for (const auto &change : *entry.Changes) {
- if (change.Key == "topic" && change.NewValue.has_value()) {
- extra_markup.push_back(
- "Set the topic to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- } else if (change.Key == "privacy_level" && change.NewValue.has_value()) {
- Glib::ustring str = Glib::Markup::escape_text(GetStagePrivacyDisplayString(change.NewValue->get<StagePrivacy>()));
- extra_markup.push_back(
- "Set the privacy level to <b>" +
- str +
- "</b>");
- }
- }
- }
- } break;
- case AuditLogActionType::STAGE_INSTANCE_UPDATE: {
- const auto channel = discord.GetChannel(*entry.Options->ChannelID);
- if (channel.has_value()) {
- markup = user_markup +
- " updated the stage for <b>" +
- Glib::Markup::escape_text(*channel->Name) +
- "</b>";
- } else {
- markup = user_markup +
- " updated the stage for <b>" +
- std::to_string(*entry.Options->ChannelID) +
- "</b>";
- }
-
- if (entry.Changes.has_value()) {
- for (const auto &change : *entry.Changes) {
- if (change.Key == "topic" && change.NewValue.has_value()) {
- extra_markup.push_back(
- "Set the topic to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- } else if (change.Key == "privacy_level" && change.NewValue.has_value()) {
- Glib::ustring str = Glib::Markup::escape_text(GetStagePrivacyDisplayString(change.NewValue->get<StagePrivacy>()));
- extra_markup.push_back(
- "Set the privacy level to <b>" +
- str +
- "</b>");
- }
- }
- }
- } break;
- case AuditLogActionType::STAGE_INSTANCE_DELETE: {
- const auto channel = discord.GetChannel(*entry.Options->ChannelID);
- if (channel.has_value()) {
- markup = user_markup +
- " ended the stage for <b>" +
- Glib::Markup::escape_text(*channel->Name) +
- "</b>";
- } else {
- markup = user_markup +
- " ended the stage for <b>" +
- std::to_string(*entry.Options->ChannelID) +
- "</b>";
- }
- } break;
- case AuditLogActionType::THREAD_CREATE: {
- const auto channel = discord.GetChannel(entry.TargetID);
- markup = user_markup +
- " created a thread <b>" +
- (channel.has_value()
- ? Glib::Markup::escape_text(*channel->Name)
- : Glib::ustring(*entry.GetNewFromKey<std::string>("name"))) +
- "</b>";
- if (entry.Changes.has_value()) {
- for (const auto &change : *entry.Changes) {
- if (change.Key == "name")
- extra_markup.push_back("Set the name to <b>" + Glib::Markup::escape_text(change.NewValue->get<std::string>()) + "</b>");
- else if (change.Key == "archived")
- extra_markup.push_back(change.NewValue->get<bool>() ? "Archived the thread" : "Unarchived the thread");
- else if (change.Key == "auto_archive_duration")
- extra_markup.push_back("Set auto archive duration to <b>"s + std::to_string(change.NewValue->get<int>()) + " minutes</b>"s);
- else if (change.Key == "rate_limit_per_user" && change.NewValue.has_value()) {
- const int secs = change.NewValue->get<int>();
- if (secs == 0)
- extra_markup.push_back("Disabled slowmode");
- else
- extra_markup.push_back("Set slowmode to <b>" +
- std::to_string(secs) + " seconds</b>");
- } else if (change.Key == "locked")
- extra_markup.push_back(change.NewValue->get<bool>() ? "Locked the thread, restricting it to only be unarchived by moderators" : "Unlocked the thread, allowing it to be unarchived by non-moderators");
- }
- }
- } break;
- case AuditLogActionType::THREAD_UPDATE: {
- const auto channel = discord.GetChannel(entry.TargetID);
- markup = user_markup +
- " made changes to the thread <b>" +
- (channel.has_value()
- ? Glib::Markup::escape_text(*channel->Name)
- : Glib::ustring(entry.TargetID)) +
- "</b>";
- for (const auto &change : *entry.Changes) {
- if (change.Key == "name")
- extra_markup.push_back(
- "Changed the name from <b>" +
- Glib::Markup::escape_text(change.OldValue->get<std::string>()) +
- "</b> to <b>" +
- Glib::Markup::escape_text(change.NewValue->get<std::string>()) +
- "</b>");
- else if (change.Key == "auto_archive_duration")
- extra_markup.push_back("Set auto archive duration to <b>"s + std::to_string(change.NewValue->get<int>()) + " minutes</b>"s);
- else if (change.Key == "rate_limit_per_user" && change.NewValue.has_value()) {
- const int secs = change.NewValue->get<int>();
- if (secs == 0)
- extra_markup.push_back("Disabled slowmode");
- else
- extra_markup.push_back("Set slowmode to <b>" +
- std::to_string(secs) +
- " seconds</b>");
- } else if (change.Key == "locked")
- extra_markup.push_back(change.NewValue->get<bool>() ? "Locked the thread, restricting it to only be unarchived by moderators" : "Unlocked the thread, allowing it to be unarchived by non-moderators");
- else if (change.Key == "archived")
- extra_markup.push_back(change.NewValue->get<bool>() ? "Archived the thread" : "Unarchived the thread");
- }
- } break;
- case AuditLogActionType::THREAD_DELETE: {
- markup = user_markup +
- " deleted the thread <b>" + Glib::Markup::escape_text(*entry.GetOldFromKey<std::string>("name")) + "</b>";
- } break;
- default:
- markup = "<i>Unknown action</i>";
- break;
- }
-
- label->set_markup(markup);
- expander->set_label_widget(*label);
-
- if (entry.Reason.has_value()) {
- extra_markup.push_back("With reason <b>" +
- Glib::Markup::escape_text(*entry.Reason) +
- "</b>");
- }
-
- expander->set_expanded(true);
-
- auto contents = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
- for (const auto &extra : extra_markup) {
- auto extra_label = Gtk::manage(new Gtk::Label);
- extra_label->set_markup(extra);
- extra_label->set_halign(Gtk::ALIGN_START);
- extra_label->set_margin_start(25);
- extra_label->set_ellipsize(Pango::ELLIPSIZE_END);
- contents->add(*extra_label);
- }
- expander->add(*contents);
- expander->set_margin_bottom(5);
- expander->show_all();
- m_list.add(*expander);
- }
-}
diff --git a/windows/guildsettings/auditlogpane.hpp b/windows/guildsettings/auditlogpane.hpp
deleted file mode 100644
index ac12321..0000000
--- a/windows/guildsettings/auditlogpane.hpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/objects.hpp"
-
-class GuildSettingsAuditLogPane : public Gtk::ScrolledWindow {
-public:
- GuildSettingsAuditLogPane(Snowflake id);
-
-private:
- void OnMap();
-
- bool m_requested = false;
-
- Gtk::ListBox m_list;
-
- void OnAuditLogFetch(const AuditLogData &data);
-
- Snowflake GuildID;
-};
diff --git a/windows/guildsettings/banspane.cpp b/windows/guildsettings/banspane.cpp
deleted file mode 100644
index 97a70c4..0000000
--- a/windows/guildsettings/banspane.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-#include "banspane.hpp"
-#include "abaddon.hpp"
-
-// gtk_list_store_set_value: assertion 'column >= 0 && column < priv->n_columns' failed
-// dont care to figure out why this happens cuz it doesnt seem to break anything
-
-GuildSettingsBansPane::GuildSettingsBansPane(Snowflake id)
- : Gtk::Box(Gtk::ORIENTATION_VERTICAL)
- , GuildID(id)
- , m_model(Gtk::ListStore::create(m_columns))
- , m_menu_unban("Unban")
- , m_menu_copy_id("Copy ID") {
- signal_map().connect(sigc::mem_fun(*this, &GuildSettingsBansPane::OnMap));
- set_name("guild-bans-pane");
- set_hexpand(true);
- set_vexpand(true);
-
- auto &discord = Abaddon::Get().GetDiscordClient();
-
- discord.signal_guild_ban_add().connect(sigc::mem_fun(*this, &GuildSettingsBansPane::OnBanAdd));
- discord.signal_guild_ban_remove().connect(sigc::mem_fun(*this, &GuildSettingsBansPane::OnBanRemove));
-
- const auto self_id = discord.GetUserData().ID;
- const auto can_ban = discord.HasGuildPermission(self_id, GuildID, Permission::BAN_MEMBERS);
-
- if (!can_ban) {
- for (const auto &ban : discord.GetBansInGuild(id))
- OnGuildBanFetch(ban);
-
- m_no_perms_note = Gtk::manage(new Gtk::Label("You do not have permission to see bans. However, bans made while you are connected will appear here"));
- m_no_perms_note->set_single_line_mode(true);
- m_no_perms_note->set_ellipsize(Pango::ELLIPSIZE_END);
- m_no_perms_note->set_halign(Gtk::ALIGN_START);
- add(*m_no_perms_note);
- }
-
- m_menu_unban.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsBansPane::OnMenuUnban));
- m_menu_copy_id.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsBansPane::OnMenuCopyID));
- m_menu_unban.show();
- m_menu_copy_id.show();
- m_menu.append(m_menu_unban);
- m_menu.append(m_menu_copy_id);
-
- m_view.signal_button_press_event().connect(sigc::mem_fun(*this, &GuildSettingsBansPane::OnTreeButtonPress), false);
- m_view.show();
-
- m_scroll.set_propagate_natural_height(true);
- m_scroll.add(m_view);
- add(m_scroll);
- show_all_children();
-
- m_view.set_enable_search(false);
- m_view.set_model(m_model);
- m_view.append_column("User", m_columns.m_col_user);
- m_view.append_column("Reason", m_columns.m_col_reason);
-}
-
-void GuildSettingsBansPane::OnMap() {
- if (m_requested) return;
- m_requested = true;
-
- auto &discord = Abaddon::Get().GetDiscordClient();
-
- const auto self_id = discord.GetUserData().ID;
- const auto can_ban = discord.HasGuildPermission(self_id, GuildID, Permission::BAN_MEMBERS);
-
- if (can_ban)
- discord.FetchGuildBans(GuildID, sigc::mem_fun(*this, &GuildSettingsBansPane::OnGuildBansFetch));
-}
-
-void GuildSettingsBansPane::OnGuildBanFetch(const BanData &ban) {
- const auto user = Abaddon::Get().GetDiscordClient().GetUser(ban.User.ID);
- auto row = *m_model->append();
- row[m_columns.m_col_id] = ban.User.ID;
- if (user.has_value())
- row[m_columns.m_col_user] = user->Username + "#" + user->Discriminator;
- else
- row[m_columns.m_col_user] = "<@" + std::to_string(ban.User.ID) + ">";
-
- row[m_columns.m_col_reason] = ban.Reason;
-}
-
-void GuildSettingsBansPane::OnGuildBansFetch(const std::vector<BanData> &bans) {
- for (const auto &ban : bans) {
- const auto user = Abaddon::Get().GetDiscordClient().GetUser(ban.User.ID);
- auto row = *m_model->append();
- row[m_columns.m_col_id] = user->ID;
- row[m_columns.m_col_user] = user->Username + "#" + user->Discriminator;
- row[m_columns.m_col_reason] = ban.Reason;
- }
-}
-
-void GuildSettingsBansPane::OnMenuUnban() {
- auto selected_row = *m_view.get_selection()->get_selected();
- if (selected_row) {
- Snowflake id = selected_row[m_columns.m_col_id];
- auto cb = [this](DiscordError code) {
- if (code != DiscordError::NONE) {
- Gtk::MessageDialog dlg("Failed to unban user", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- dlg.set_position(Gtk::WIN_POS_CENTER);
- dlg.run();
- }
- };
- Abaddon::Get().GetDiscordClient().UnbanUser(GuildID, id, sigc::track_obj(cb, *this));
- }
-}
-
-void GuildSettingsBansPane::OnMenuCopyID() {
- auto selected_row = *m_view.get_selection()->get_selected();
- if (selected_row)
- Gtk::Clipboard::get()->set_text(std::to_string(static_cast<Snowflake>(selected_row[m_columns.m_col_id])));
-}
-
-bool GuildSettingsBansPane::OnTreeButtonPress(GdkEventButton *event) {
- if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_SECONDARY) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto self_id = discord.GetUserData().ID;
- const auto can_ban = discord.HasGuildPermission(self_id, GuildID, Permission::BAN_MEMBERS);
- m_menu_unban.set_sensitive(can_ban);
- auto selection = m_view.get_selection();
- Gtk::TreeModel::Path path;
- if (m_view.get_path_at_pos(event->x, event->y, path)) {
- m_view.get_selection()->select(path);
- m_menu.popup_at_pointer(reinterpret_cast<GdkEvent *>(event));
- }
-
- return true;
- }
-
- return false;
-}
-
-void GuildSettingsBansPane::OnBanRemove(Snowflake guild_id, Snowflake user_id) {
- if (guild_id != GuildID) return;
- for (auto &child : m_model->children()) {
- if (static_cast<Snowflake>(child[m_columns.m_col_id]) == user_id) {
- m_model->erase(child);
- break;
- }
- }
-}
-
-void GuildSettingsBansPane::OnBanAdd(Snowflake guild_id, Snowflake user_id) {
- if (guild_id != GuildID) return;
- auto &discord = Abaddon::Get().GetDiscordClient();
- if (discord.HasGuildPermission(discord.GetUserData().ID, guild_id, Permission::BAN_MEMBERS)) {
- discord.FetchGuildBan(guild_id, user_id, sigc::mem_fun(*this, &GuildSettingsBansPane::OnGuildBanFetch));
- } else {
- auto user = *discord.GetUser(user_id);
- auto row = *m_model->append();
- row[m_columns.m_col_id] = user_id;
- row[m_columns.m_col_user] = user.Username + "#" + user.Discriminator;
- row[m_columns.m_col_reason] = "";
- }
-}
-
-GuildSettingsBansPane::ModelColumns::ModelColumns() {
- add(m_col_id);
- add(m_col_user);
- add(m_col_reason);
-}
diff --git a/windows/guildsettings/banspane.hpp b/windows/guildsettings/banspane.hpp
deleted file mode 100644
index b2420a9..0000000
--- a/windows/guildsettings/banspane.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/snowflake.hpp"
-#include "discord/ban.hpp"
-
-class GuildSettingsBansPane : public Gtk::Box {
-public:
- GuildSettingsBansPane(Snowflake id);
-
-private:
- void OnMap();
-
- bool m_requested = false;
-
- void OnGuildBanFetch(const BanData &ban);
- void OnGuildBansFetch(const std::vector<BanData> &bans);
- void OnMenuUnban();
- void OnMenuCopyID();
- bool OnTreeButtonPress(GdkEventButton *event);
- void OnBanRemove(Snowflake guild_id, Snowflake user_id);
- void OnBanAdd(Snowflake guild_id, Snowflake user_id);
-
- Gtk::Label *m_no_perms_note = nullptr;
-
- Gtk::ScrolledWindow m_scroll;
- Gtk::TreeView m_view;
-
- Snowflake GuildID;
-
- class ModelColumns : public Gtk::TreeModel::ColumnRecord {
- public:
- ModelColumns();
-
- Gtk::TreeModelColumn<Glib::ustring> m_col_user;
- Gtk::TreeModelColumn<Glib::ustring> m_col_reason;
- Gtk::TreeModelColumn<Snowflake> m_col_id;
- };
-
- ModelColumns m_columns;
- Glib::RefPtr<Gtk::ListStore> m_model;
-
- Gtk::Menu m_menu;
- Gtk::MenuItem m_menu_unban;
- Gtk::MenuItem m_menu_copy_id;
-};
diff --git a/windows/guildsettings/emojispane.cpp b/windows/guildsettings/emojispane.cpp
deleted file mode 100644
index 1f4bfa9..0000000
--- a/windows/guildsettings/emojispane.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-#include "emojispane.hpp"
-#include "abaddon.hpp"
-#include "components/cellrendererpixbufanimation.hpp"
-
-GuildSettingsEmojisPane::GuildSettingsEmojisPane(Snowflake guild_id)
- : Gtk::Box(Gtk::ORIENTATION_VERTICAL)
- , GuildID(guild_id)
- , m_model(Gtk::ListStore::create(m_columns))
- , m_filter(Gtk::TreeModelFilter::create(m_model))
- , m_menu_delete("Delete")
- , m_menu_copy_id("Copy ID")
- , m_menu_copy_emoji_url("Copy Emoji URL")
- , m_menu_show_emoji("Open in Browser") {
- signal_map().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMap));
- set_name("guild-emojis-pane");
-
- m_view_scroll.set_hexpand(true);
- m_view_scroll.set_vexpand(true);
-
- m_view.signal_button_press_event().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnTreeButtonPress), false);
-
- m_menu_copy_id.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMenuCopyID));
- m_menu_delete.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMenuDelete));
- m_menu_copy_emoji_url.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMenuCopyEmojiURL));
- m_menu_show_emoji.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnMenuShowEmoji));
-
- m_menu.append(m_menu_delete);
- m_menu.append(m_menu_copy_id);
- m_menu.append(m_menu_copy_emoji_url);
- m_menu.append(m_menu_show_emoji);
- m_menu.show_all();
-
- auto &discord = Abaddon::Get().GetDiscordClient();
-
- discord.signal_guild_emojis_update().connect(sigc::hide<0>(sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnFetchEmojis)));
-
- const auto self_id = discord.GetUserData().ID;
- const bool can_manage = discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_EMOJIS);
- m_menu_delete.set_sensitive(can_manage);
-
- m_search.set_placeholder_text("Filter");
- m_search.signal_changed().connect([this]() {
- m_filter->refilter();
- });
-
- m_view_scroll.add(m_view);
- add(m_search);
- add(m_view_scroll);
- m_search.show();
- m_view.show();
- m_view_scroll.show();
-
- m_filter->set_visible_func([this](const Gtk::TreeModel::const_iterator &iter) -> bool {
- const auto text = m_search.get_text();
- if (text == "") return true;
- return StringContainsCaseless((*iter)[m_columns.m_col_name], text);
- });
- m_view.set_enable_search(false);
- m_view.set_model(m_filter);
-
- auto *column = Gtk::manage(new Gtk::TreeView::Column("Emoji"));
- auto *renderer = Gtk::manage(new CellRendererPixbufAnimation);
- column->pack_start(*renderer);
- column->add_attribute(renderer->property_pixbuf(), m_columns.m_col_pixbuf);
- column->add_attribute(renderer->property_pixbuf_animation(), m_columns.m_col_pixbuf_animation);
- m_view.append_column(*column);
-
- if (can_manage) {
- auto *column = Gtk::manage(new Gtk::TreeView::Column("Name"));
- auto *renderer = Gtk::manage(new Gtk::CellRendererText);
- column->pack_start(*renderer);
- column->add_attribute(renderer->property_text(), m_columns.m_col_name);
- renderer->property_editable() = true;
- renderer->signal_edited().connect([this, renderer, column](const Glib::ustring &path, const Glib::ustring &text) {
- std::string new_str;
- int size = 0;
- for (const auto ch : text) {
- if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_')
- new_str += ch;
- else if (ch == ' ')
- new_str += '_';
- if (++size == 32) break;
- }
- if (auto row = *m_model->get_iter(path)) {
- row[m_columns.m_col_name] = new_str;
- OnEditName(row[m_columns.m_col_id], new_str);
- }
- });
- m_view.append_column(*column);
- } else
- m_view.append_column("Name", m_columns.m_col_name);
- if (can_manage)
- m_view.append_column("Creator", m_columns.m_col_creator);
- m_view.append_column("Is Animated?", m_columns.m_col_animated);
-
- for (const auto column : m_view.get_columns())
- column->set_resizable(true);
-}
-
-void GuildSettingsEmojisPane::OnMap() {
- m_view.grab_focus();
-
- if (m_requested) return;
- m_requested = true;
-
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto self_id = discord.GetUserData().ID;
- const bool can_manage = discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_EMOJIS);
- m_menu_delete.set_sensitive(can_manage);
-
- discord.FetchGuildEmojis(GuildID, sigc::mem_fun(*this, &GuildSettingsEmojisPane::OnFetchEmojis));
-}
-
-void GuildSettingsEmojisPane::AddEmojiRow(const EmojiData &emoji) {
- auto &img = Abaddon::Get().GetImageManager();
-
- auto row = *m_model->append();
-
- row[m_columns.m_col_id] = emoji.ID;
- row[m_columns.m_col_pixbuf] = img.GetPlaceholder(32);
- row[m_columns.m_col_name] = emoji.Name;
- if (emoji.Creator.has_value())
- row[m_columns.m_col_creator] = emoji.Creator->Username + "#" + emoji.Creator->Discriminator;
- if (emoji.IsAnimated.has_value())
- row[m_columns.m_col_animated] = *emoji.IsAnimated ? "Yes" : "No";
- else
- row[m_columns.m_col_animated] = "No";
- if (emoji.IsAvailable.has_value())
- row[m_columns.m_col_available] = *emoji.IsAvailable ? "Yes" : "No";
- else
- row[m_columns.m_col_available] = "Yes";
-
- static bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
- if (show_animations && emoji.IsAnimated.has_value() && *emoji.IsAnimated) {
- const auto cb = [this, id = emoji.ID](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
- for (auto &row : m_model->children()) {
- if (static_cast<Snowflake>(row[m_columns.m_col_id]) == id) {
- row[m_columns.m_col_pixbuf_animation] = pb;
- return;
- }
- }
- };
- img.LoadAnimationFromURL(emoji.GetURL("gif"), 32, 32, sigc::track_obj(cb, *this));
- } else {
- const auto cb = [this, id = emoji.ID](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
- for (auto &row : m_model->children()) {
- if (static_cast<Snowflake>(row[m_columns.m_col_id]) == id) {
- row[m_columns.m_col_pixbuf] = pb->scale_simple(32, 32, Gdk::INTERP_BILINEAR);
- return;
- }
- }
- };
- img.LoadFromURL(emoji.GetURL(), sigc::track_obj(cb, *this));
- }
-}
-
-void GuildSettingsEmojisPane::OnFetchEmojis(std::vector<EmojiData> emojis) {
- m_model->clear();
-
- // put animated emojis at the end then sort alphabetically
- std::sort(emojis.begin(), emojis.end(), [&](const EmojiData &a, const EmojiData &b) {
- const bool a_is_animated = a.IsAnimated.has_value() && *a.IsAnimated;
- const bool b_is_animated = b.IsAnimated.has_value() && *b.IsAnimated;
- if (a_is_animated == b_is_animated)
- return a.Name < b.Name;
- else if (a_is_animated && !b_is_animated)
- return false;
- else if (!a_is_animated && b_is_animated)
- return true;
- return false; // this wont happen please be quiet compiler
- });
-
- for (const auto &emoji : emojis)
- AddEmojiRow(emoji);
-}
-
-void GuildSettingsEmojisPane::OnEditName(Snowflake id, const std::string &name) {
- const auto cb = [this](DiscordError code) {
- if (code != DiscordError::NONE) {
- Gtk::MessageDialog dlg("Failed to set emoji name", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
- dlg.set_position(Gtk::WIN_POS_CENTER);
- dlg.run();
- }
- };
- Abaddon::Get().GetDiscordClient().ModifyEmojiName(GuildID, id, name, cb);
-}
-
-void GuildSettingsEmojisPane::OnMenuCopyID() {
- if (auto selected_row = *m_view.get_selection()->get_selected()) {
- const auto id = static_cast<Snowflake>(selected_row[m_columns.m_col_id]);
- Gtk::Clipboard::get()->set_text(std::to_string(id));
- }
-}
-
-void GuildSettingsEmojisPane::OnMenuDelete() {
- if (auto selected_row = *m_view.get_selection()->get_selected()) {
- const auto name = static_cast<Glib::ustring>(selected_row[m_columns.m_col_name]);
- const auto id = static_cast<Snowflake>(selected_row[m_columns.m_col_id]);
- if (auto *window = dynamic_cast<Gtk::Window *>(get_toplevel()))
- if (Abaddon::Get().ShowConfirm("Are you sure you want to delete " + name + "?", window)) {
- const auto cb = [this](DiscordError code) {
- if (code != DiscordError::NONE) {
- Gtk::MessageDialog dlg("Failed to delete emoji", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK);
- dlg.set_position(Gtk::WIN_POS_CENTER);
- dlg.run();
- }
- };
- Abaddon::Get().GetDiscordClient().DeleteEmoji(GuildID, id, cb);
- }
- }
-}
-
-void GuildSettingsEmojisPane::OnMenuCopyEmojiURL() {
- if (auto selected_row = *m_view.get_selection()->get_selected()) {
- const auto id = static_cast<Snowflake>(selected_row[m_columns.m_col_id]);
- const bool is_animated = static_cast<Glib::ustring>(selected_row[m_columns.m_col_animated]) == "Yes";
- Gtk::Clipboard::get()->set_text(EmojiData::URLFromID(id, is_animated ? "gif" : "png", "256"));
- }
-}
-
-void GuildSettingsEmojisPane::OnMenuShowEmoji() {
- if (auto selected_row = *m_view.get_selection()->get_selected()) {
- const auto id = static_cast<Snowflake>(selected_row[m_columns.m_col_id]);
- const bool is_animated = static_cast<Glib::ustring>(selected_row[m_columns.m_col_animated]) == "Yes";
- LaunchBrowser(EmojiData::URLFromID(id, is_animated ? "gif" : "png", "256"));
- }
-}
-
-bool GuildSettingsEmojisPane::OnTreeButtonPress(GdkEventButton *event) {
- if (event->button == GDK_BUTTON_SECONDARY) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto self_id = discord.GetUserData().ID;
- const bool can_manage = discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_EMOJIS);
- m_menu_delete.set_sensitive(can_manage);
-
- auto selection = m_view.get_selection();
- Gtk::TreeModel::Path path;
- if (m_view.get_path_at_pos(event->x, event->y, path)) {
- m_view.get_selection()->select(path);
- m_menu.popup_at_pointer(reinterpret_cast<GdkEvent *>(event));
- }
-
- return true;
- }
-
- return false;
-}
-
-GuildSettingsEmojisPane::ModelColumns::ModelColumns() {
- add(m_col_id);
- add(m_col_pixbuf);
- add(m_col_pixbuf_animation);
- add(m_col_name);
- add(m_col_creator);
- add(m_col_animated);
- add(m_col_available);
-}
diff --git a/windows/guildsettings/emojispane.hpp b/windows/guildsettings/emojispane.hpp
deleted file mode 100644
index 1c0edd1..0000000
--- a/windows/guildsettings/emojispane.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/emoji.hpp"
-
-class GuildSettingsEmojisPane : public Gtk::Box {
-public:
- GuildSettingsEmojisPane(Snowflake guild_id);
-
-private:
- void OnMap();
-
- bool m_requested = false;
-
- void AddEmojiRow(const EmojiData &emoji);
-
- void OnFetchEmojis(std::vector<EmojiData> emojis);
-
- void OnEditName(Snowflake id, const std::string &name);
- void OnMenuCopyID();
- void OnMenuDelete();
- void OnMenuCopyEmojiURL();
- void OnMenuShowEmoji();
- bool OnTreeButtonPress(GdkEventButton *event);
-
- Snowflake GuildID;
-
- Gtk::Entry m_search;
- Gtk::ScrolledWindow m_view_scroll;
- Gtk::TreeView m_view;
-
- class ModelColumns : public Gtk::TreeModel::ColumnRecord {
- public:
- ModelColumns();
-
- Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf>> m_col_pixbuf;
- Gtk::TreeModelColumn<Glib::RefPtr<Gdk::PixbufAnimation>> m_col_pixbuf_animation;
- Gtk::TreeModelColumn<Glib::ustring> m_col_name;
- Gtk::TreeModelColumn<Glib::ustring> m_col_creator;
- Gtk::TreeModelColumn<Glib::ustring> m_col_animated;
- Gtk::TreeModelColumn<Glib::ustring> m_col_available;
- Gtk::TreeModelColumn<Snowflake> m_col_id;
- };
-
- ModelColumns m_columns;
- Glib::RefPtr<Gtk::ListStore> m_model;
- Glib::RefPtr<Gtk::TreeModelFilter> m_filter;
-
- Gtk::Menu m_menu;
- Gtk::MenuItem m_menu_delete;
- Gtk::MenuItem m_menu_copy_id;
- Gtk::MenuItem m_menu_copy_emoji_url;
- Gtk::MenuItem m_menu_show_emoji;
-};
diff --git a/windows/guildsettings/infopane.cpp b/windows/guildsettings/infopane.cpp
deleted file mode 100644
index b4f75f3..0000000
--- a/windows/guildsettings/infopane.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-#include "infopane.hpp"
-#include "abaddon.hpp"
-#include <filesystem>
-
-GuildSettingsInfoPane::GuildSettingsInfoPane(Snowflake id)
- : m_guild_icon_label("Guild icon")
- , m_guild_name_label("Guild name")
- , GuildID(id) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto guild = *discord.GetGuild(id);
- const auto self_id = discord.GetUserData().ID;
- const auto can_modify = discord.HasGuildPermission(self_id, id, Permission::MANAGE_GUILD);
-
- set_name("guild-info-pane");
-
- m_guild_name.set_sensitive(can_modify);
- m_guild_name.set_text(guild.Name);
- m_guild_name.signal_focus_out_event().connect([this](GdkEventFocus *e) -> bool {
- UpdateGuildName();
- return false;
- });
- m_guild_name.signal_key_press_event().connect([this](GdkEventKey *e) -> bool {
- if (e->keyval == GDK_KEY_Return)
- UpdateGuildName();
- return false;
- // clang-format off
- }, false);
- // clang-format on
- m_guild_name.set_tooltip_text("Press enter or lose focus to submit");
- m_guild_name.show();
- m_guild_name_label.show();
-
- auto guild_update_cb = [this](Snowflake id) {
- if (id != GuildID) return;
- const auto guild = *Abaddon::Get().GetDiscordClient().GetGuild(id);
- FetchGuildIcon(guild);
- };
- discord.signal_guild_update().connect(sigc::track_obj(guild_update_cb, *this));
- FetchGuildIcon(guild);
-
- AddPointerCursor(m_guild_icon_ev);
-
- m_guild_icon.set_margin_bottom(10);
- if (can_modify) {
- m_guild_icon_ev.set_tooltip_text("Click to choose a file, right click to paste");
-
- m_guild_icon_ev.signal_button_press_event().connect([this](GdkEventButton *event) -> bool {
- if (event->type == GDK_BUTTON_PRESS) {
- if (event->button == GDK_BUTTON_PRIMARY)
- UpdateGuildIconPicker();
- else if (event->button == GDK_BUTTON_SECONDARY)
- UpdateGuildIconClipboard();
- }
-
- return false;
- });
- } else if (guild.HasIcon()) {
- std::string guild_icon_url;
- if (guild.HasAnimatedIcon())
- guild_icon_url = guild.GetIconURL("gif", "512");
- else
- guild_icon_url = guild.GetIconURL("png", "512");
- m_guild_icon_ev.signal_button_press_event().connect([this, guild_icon_url](GdkEventButton *event) -> bool {
- if (event->type == GDK_BUTTON_PRESS)
- if (event->button == GDK_BUTTON_PRIMARY)
- LaunchBrowser(guild_icon_url);
-
- return false;
- });
- }
-
- m_guild_icon.show();
- m_guild_icon_ev.show();
-
- m_guild_icon_ev.add(m_guild_icon);
- attach(m_guild_icon_ev, 0, 0, 1, 1);
- attach(m_guild_name_label, 0, 1, 1, 1);
- attach_next_to(m_guild_name, m_guild_name_label, Gtk::POS_RIGHT, 1, 1);
-}
-
-void GuildSettingsInfoPane::FetchGuildIcon(const GuildData &guild) {
- m_guild_icon.property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(32);
- if (guild.HasIcon()) {
- if (Abaddon::Get().GetSettings().GetShowAnimations() && guild.HasAnimatedIcon()) {
- auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pixbuf) {
- m_guild_icon.property_pixbuf_animation() = pixbuf;
- };
- Abaddon::Get().GetImageManager().LoadAnimationFromURL(guild.GetIconURL("gif", "64"), 64, 64, sigc::track_obj(cb, *this));
- }
-
- auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pixbuf) {
- m_guild_icon.property_pixbuf() = pixbuf->scale_simple(64, 64, Gdk::INTERP_BILINEAR);
- };
- Abaddon::Get().GetImageManager().LoadFromURL(guild.GetIconURL("png", "64"), sigc::track_obj(cb, *this));
- }
-}
-
-void GuildSettingsInfoPane::UpdateGuildName() {
- auto &discord = Abaddon::Get().GetDiscordClient();
- if (discord.GetGuild(GuildID)->Name == m_guild_name.get_text()) return;
-
- auto cb = [this](DiscordError code) {
- if (code != DiscordError::NONE) {
- m_guild_name.set_text(Abaddon::Get().GetDiscordClient().GetGuild(GuildID)->Name);
- Gtk::MessageDialog dlg("Failed to set guild name", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- dlg.set_position(Gtk::WIN_POS_CENTER);
- dlg.run();
- }
- };
- discord.SetGuildName(GuildID, m_guild_name.get_text(), sigc::track_obj(cb, *this));
-}
-
-void GuildSettingsInfoPane::UpdateGuildIconFromData(const std::vector<uint8_t> &data, const std::string &mime) {
- auto encoded = "data:" + mime + ";base64," + Glib::Base64::encode(std::string(data.begin(), data.end()));
- auto &discord = Abaddon::Get().GetDiscordClient();
-
- auto cb = [this](DiscordError code) {
- if (code != DiscordError::NONE) {
- Gtk::MessageDialog dlg("Failed to set guild icon", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- dlg.set_position(Gtk::WIN_POS_CENTER);
- dlg.run();
- }
- };
- discord.SetGuildIcon(GuildID, encoded, sigc::track_obj(cb, *this));
-}
-
-void GuildSettingsInfoPane::UpdateGuildIconFromPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf) {
- int w = pixbuf->get_width();
- int h = pixbuf->get_height();
- if (w > 1024 || h > 1024) {
- GetImageDimensions(w, h, w, h, 1024, 1024);
- pixbuf = pixbuf->scale_simple(w, h, Gdk::INTERP_BILINEAR);
- }
- gchar *buffer;
- gsize buffer_size;
- pixbuf->save_to_buffer(buffer, buffer_size, "png");
- std::vector<uint8_t> data(buffer_size);
- std::memcpy(data.data(), buffer, buffer_size);
- UpdateGuildIconFromData(data, "image/png");
-}
-
-void GuildSettingsInfoPane::UpdateGuildIconPicker() {
- // this picker fucking sucks
- Gtk::FileChooserDialog dlg("Choose new guild icon", Gtk::FILE_CHOOSER_ACTION_OPEN);
- dlg.get_style_context()->remove_provider(Abaddon::Get().GetStyleProvider());
- dlg.set_modal(true);
- dlg.signal_response().connect([this, &dlg](int response) {
- if (response == Gtk::RESPONSE_OK) {
- auto data = ReadWholeFile(dlg.get_filename());
- if (GetExtension(dlg.get_filename()) == ".gif")
- UpdateGuildIconFromData(data, "image/gif");
- else
- try {
- auto loader = Gdk::PixbufLoader::create();
- loader->signal_size_prepared().connect([&loader](int inw, int inh) {
- int w, h;
- GetImageDimensions(inw, inh, w, h, 1024, 1024);
- loader->set_size(w, h);
- });
- loader->write(data.data(), data.size());
- loader->close();
- UpdateGuildIconFromPixbuf(loader->get_pixbuf());
- } catch (const std::exception &) {};
- }
- });
-
- dlg.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
- dlg.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
-
- auto filter_images = Gtk::FileFilter::create();
- if (Abaddon::Get().GetDiscordClient().GetGuild(GuildID)->HasFeature("ANIMATED_ICON")) {
- filter_images->set_name("Supported images (*.jpg, *.jpeg, *.png, *.gif)");
- filter_images->add_pattern("*.gif");
- } else {
- filter_images->set_name("Supported images (*.jpg, *.jpeg, *.png)");
- }
- filter_images->add_pattern("*.jpg");
- filter_images->add_pattern("*.jpeg");
- filter_images->add_pattern("*.png");
- dlg.add_filter(filter_images);
-
- auto filter_all = Gtk::FileFilter::create();
- filter_all->set_name("All files (*.*)");
- filter_all->add_pattern("*.*");
- dlg.add_filter(filter_all);
-
- dlg.run();
-}
-
-void GuildSettingsInfoPane::UpdateGuildIconClipboard() {
- std::vector<uint8_t> icon_data;
-
- auto cb = Gtk::Clipboard::get();
- // query for file path then for actual image
- if (cb->wait_is_text_available()) {
- auto path = cb->wait_for_text();
- if (!std::filesystem::exists(path.c_str())) return;
- auto data = ReadWholeFile(path);
- try {
- auto loader = Gdk::PixbufLoader::create();
- loader->signal_size_prepared().connect([&loader](int inw, int inh) {
- int w, h;
- GetImageDimensions(inw, inh, w, h, 1024, 1024);
- loader->set_size(w, h);
- });
- loader->write(data.data(), data.size());
- loader->close();
- auto pb = loader->get_pixbuf();
- UpdateGuildIconFromPixbuf(pb);
-
- return;
- } catch (const std::exception &) {};
- }
-
- if (cb->wait_is_image_available()) {
- auto pb = cb->wait_for_image();
- UpdateGuildIconFromPixbuf(pb);
- return;
- }
-}
diff --git a/windows/guildsettings/infopane.hpp b/windows/guildsettings/infopane.hpp
deleted file mode 100644
index 8a7e6a2..0000000
--- a/windows/guildsettings/infopane.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/guild.hpp"
-
-class GuildSettingsInfoPane : public Gtk::Grid {
-public:
- GuildSettingsInfoPane(Snowflake id);
-
-private:
- void FetchGuildIcon(const GuildData &guild);
-
- void UpdateGuildName();
- void UpdateGuildIconFromData(const std::vector<uint8_t> &data, const std::string &mime);
- void UpdateGuildIconFromPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf);
- void UpdateGuildIconPicker();
- void UpdateGuildIconClipboard();
-
- Gtk::Label m_guild_icon_label;
- Gtk::EventBox m_guild_icon_ev; // necessary to make custom cursor behave properly
- Gtk::Image m_guild_icon;
-
- Gtk::Label m_guild_name_label;
- Gtk::Entry m_guild_name;
-
- Snowflake GuildID;
-};
diff --git a/windows/guildsettings/invitespane.cpp b/windows/guildsettings/invitespane.cpp
deleted file mode 100644
index bec4784..0000000
--- a/windows/guildsettings/invitespane.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-#include "invitespane.hpp"
-#include "abaddon.hpp"
-
-GuildSettingsInvitesPane::GuildSettingsInvitesPane(Snowflake id)
- : GuildID(id)
- , m_model(Gtk::ListStore::create(m_columns))
- , m_menu_delete("Delete") {
- signal_map().connect(sigc::mem_fun(*this, &GuildSettingsInvitesPane::OnMap));
- set_name("guild-invites-pane");
- set_hexpand(true);
- set_vexpand(true);
-
- m_view.signal_button_press_event().connect(sigc::mem_fun(*this, &GuildSettingsInvitesPane::OnTreeButtonPress), false);
-
- m_menu_delete.signal_activate().connect(sigc::mem_fun(*this, &GuildSettingsInvitesPane::OnMenuDelete));
- m_menu.append(m_menu_delete);
- m_menu.show_all();
-
- auto &discord = Abaddon::Get().GetDiscordClient();
-
- discord.signal_invite_create().connect(sigc::mem_fun(*this, &GuildSettingsInvitesPane::OnInviteCreate));
- discord.signal_invite_delete().connect(sigc::mem_fun(*this, &GuildSettingsInvitesPane::OnInviteDelete));
-
- m_view.show();
- add(m_view);
-
- m_view.set_enable_search(false);
- m_view.set_model(m_model);
- m_view.append_column("Code", m_columns.m_col_code);
- m_view.append_column("Expires", m_columns.m_col_expires);
- m_view.append_column("Created by", m_columns.m_col_inviter);
- m_view.append_column("Uses", m_columns.m_col_uses);
- m_view.append_column("Max uses", m_columns.m_col_max_uses);
- m_view.append_column("Grants temporary membership", m_columns.m_col_temporary);
-
- for (const auto column : m_view.get_columns())
- column->set_resizable(true);
-}
-
-void GuildSettingsInvitesPane::OnMap() {
- if (m_requested) return;
- m_requested = true;
-
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto self_id = discord.GetUserData().ID;
-
- if (discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_GUILD))
- discord.FetchGuildInvites(GuildID, sigc::mem_fun(*this, &GuildSettingsInvitesPane::OnInvitesFetch));
-}
-
-void GuildSettingsInvitesPane::AppendInvite(const InviteData &invite) {
- auto row = *m_model->append();
- row[m_columns.m_col_code] = invite.Code;
- if (invite.Inviter.has_value())
- row[m_columns.m_col_inviter] = invite.Inviter->Username + "#" + invite.Inviter->Discriminator;
-
- if (invite.MaxAge.has_value()) {
- if (*invite.MaxAge == 0)
- row[m_columns.m_col_expires] = "Never";
- else
- row[m_columns.m_col_expires] = FormatISO8601(*invite.CreatedAt, *invite.MaxAge);
- }
-
- row[m_columns.m_col_uses] = *invite.Uses;
- if (*invite.MaxUses == 0)
- row[m_columns.m_col_max_uses] = "Unlimited";
- else
- row[m_columns.m_col_max_uses] = std::to_string(*invite.MaxUses);
-
- row[m_columns.m_col_temporary] = *invite.IsTemporary ? "Yes" : "No";
-}
-
-void GuildSettingsInvitesPane::OnInviteFetch(const std::optional<InviteData> &invite) {
- if (!invite.has_value()) return;
- AppendInvite(*invite);
-}
-
-void GuildSettingsInvitesPane::OnInvitesFetch(const std::vector<InviteData> &invites) {
- for (const auto &invite : invites)
- AppendInvite(invite);
-}
-
-void GuildSettingsInvitesPane::OnInviteCreate(const InviteData &invite) {
- if (invite.Guild->ID == GuildID)
- OnInviteFetch(std::make_optional(invite));
-}
-
-void GuildSettingsInvitesPane::OnInviteDelete(const InviteDeleteObject &data) {
- if (*data.GuildID == GuildID)
- for (auto &row : m_model->children())
- if (row[m_columns.m_col_code] == data.Code)
- m_model->erase(row);
-}
-
-void GuildSettingsInvitesPane::OnMenuDelete() {
- auto selected_row = *m_view.get_selection()->get_selected();
- if (selected_row) {
- auto code = static_cast<Glib::ustring>(selected_row[m_columns.m_col_code]);
- auto cb = [this](DiscordError code) {
- if (code != DiscordError::NONE) {
- Gtk::MessageDialog dlg("Failed to delete invite", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- dlg.set_position(Gtk::WIN_POS_CENTER);
- dlg.run();
- }
- };
- Abaddon::Get().GetDiscordClient().DeleteInvite(code, sigc::track_obj(cb, *this));
- }
-}
-
-bool GuildSettingsInvitesPane::OnTreeButtonPress(GdkEventButton *event) {
- if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_SECONDARY) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto self_id = discord.GetUserData().ID;
- const auto can_manage = discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_GUILD);
- m_menu_delete.set_sensitive(can_manage);
- auto selection = m_view.get_selection();
- Gtk::TreeModel::Path path;
- if (m_view.get_path_at_pos(event->x, event->y, path)) {
- m_view.get_selection()->select(path);
- m_menu.popup_at_pointer(reinterpret_cast<GdkEvent *>(event));
- }
-
- return true;
- }
-
- return false;
-}
-
-GuildSettingsInvitesPane::ModelColumns::ModelColumns() {
- add(m_col_code);
- add(m_col_expires);
- add(m_col_inviter);
- add(m_col_temporary);
- add(m_col_uses);
- add(m_col_max_uses);
-}
diff --git a/windows/guildsettings/invitespane.hpp b/windows/guildsettings/invitespane.hpp
deleted file mode 100644
index 5268d68..0000000
--- a/windows/guildsettings/invitespane.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/objects.hpp"
-
-class GuildSettingsInvitesPane : public Gtk::ScrolledWindow {
-public:
- GuildSettingsInvitesPane(Snowflake id);
-
-private:
- void OnMap();
-
- bool m_requested = false;
-
- void AppendInvite(const InviteData &invite);
- void OnInviteFetch(const std::optional<InviteData> &invite);
- void OnInvitesFetch(const std::vector<InviteData> &invites);
- void OnInviteCreate(const InviteData &invite);
- void OnInviteDelete(const InviteDeleteObject &data);
- void OnMenuDelete();
- bool OnTreeButtonPress(GdkEventButton *event);
-
- Gtk::TreeView m_view;
-
- Snowflake GuildID;
-
- class ModelColumns : public Gtk::TreeModel::ColumnRecord {
- public:
- ModelColumns();
-
- Gtk::TreeModelColumn<Glib::ustring> m_col_code;
- Gtk::TreeModelColumn<Glib::ustring> m_col_expires;
- Gtk::TreeModelColumn<Glib::ustring> m_col_inviter;
- Gtk::TreeModelColumn<Glib::ustring> m_col_temporary;
- Gtk::TreeModelColumn<int> m_col_uses;
- Gtk::TreeModelColumn<Glib::ustring> m_col_max_uses;
- };
-
- ModelColumns m_columns;
- Glib::RefPtr<Gtk::ListStore> m_model;
-
- Gtk::Menu m_menu;
- Gtk::MenuItem m_menu_delete;
-};
diff --git a/windows/guildsettings/memberspane.cpp b/windows/guildsettings/memberspane.cpp
deleted file mode 100644
index 36c5c0b..0000000
--- a/windows/guildsettings/memberspane.cpp
+++ /dev/null
@@ -1,410 +0,0 @@
-#include "memberspane.hpp"
-#include "abaddon.hpp"
-
-GuildSettingsMembersPane::GuildSettingsMembersPane(Snowflake id)
- : Gtk::Box(Gtk::ORIENTATION_VERTICAL)
- , GuildID(id)
- , m_layout(Gtk::ORIENTATION_HORIZONTAL)
- , m_member_list(id)
- , m_member_info(id) {
- set_name("guild-members-pane");
- set_hexpand(true);
- set_vexpand(true);
-
- m_member_list.signal_member_select().connect(sigc::mem_fun(m_member_info, &GuildSettingsMembersPaneInfo::SetUser));
-
- m_note.set_label("Some members may not be shown if the client is not aware of them");
- m_note.set_single_line_mode(true);
- m_note.set_ellipsize(Pango::ELLIPSIZE_END);
-
- m_layout.set_homogeneous(true);
- m_layout.add(m_member_list);
- m_layout.add(m_member_info);
- add(m_note);
- add(m_layout);
-
- m_member_list.show();
- m_member_info.show();
- m_note.show();
- m_layout.show();
-}
-
-GuildSettingsMembersPaneMembers::GuildSettingsMembersPaneMembers(Snowflake id)
- : Gtk::Box(Gtk::ORIENTATION_VERTICAL)
- , GuildID(id) {
- m_list_scroll.get_style_context()->add_class("guild-members-pane-list");
-
- m_list_scroll.set_hexpand(true);
- m_list_scroll.set_vexpand(true);
- m_list_scroll.set_propagate_natural_height(true);
-
- auto &discord = Abaddon::Get().GetDiscordClient();
- auto members = discord.GetUsersInGuild(id);
- const auto guild = *discord.GetGuild(GuildID);
- for (const auto member_id : members) {
- auto member = discord.GetMember(member_id, GuildID);
- if (!member.has_value()) continue; // fixme this should not be necessary
- member->User = discord.GetUser(member_id);
- if (member->User->IsDeleted()) continue;
- auto *row = Gtk::manage(new GuildSettingsMembersListItem(guild, *member));
- row->show();
- m_list.add(*row);
- }
-
- m_list.set_selection_mode(Gtk::SELECTION_SINGLE);
- m_list.signal_row_selected().connect([this](Gtk::ListBoxRow *selected_) {
- if (auto *selected = dynamic_cast<GuildSettingsMembersListItem *>(selected_))
- m_signal_member_select.emit(selected->UserID);
- });
-
- m_search.set_placeholder_text("Filter");
- m_search.signal_changed().connect([this] {
- m_list.invalidate_filter();
- });
-
- m_list.set_filter_func([this](Gtk::ListBoxRow *row_) -> bool {
- const auto search_term = m_search.get_text();
- if (search_term.size() == 0) return true;
- if (auto *row = dynamic_cast<GuildSettingsMembersListItem *>(row_))
- return StringContainsCaseless(row->DisplayTerm, m_search.get_text());
- return true;
- });
-
- m_list_scroll.add(m_list);
- add(m_search);
- add(m_list_scroll);
-
- m_search.show();
- m_list.show();
- m_list_scroll.show();
-}
-
-GuildSettingsMembersPaneMembers::type_signal_member_select GuildSettingsMembersPaneMembers::signal_member_select() {
- return m_signal_member_select;
-}
-
-GuildSettingsMembersListItem::GuildSettingsMembersListItem(const GuildData &guild, const GuildMember &member)
- : UserID(member.User->ID)
- , GuildID(guild.ID)
- , m_avatar(32, 32) {
- m_avatar.SetAnimated(true);
-
- m_ev.signal_button_press_event().connect([this](GdkEventButton *event) -> bool {
- if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_SECONDARY) {
- Abaddon::Get().ShowUserMenu(reinterpret_cast<GdkEvent *>(event), UserID, GuildID);
- return true;
- }
- return false;
- });
-
- auto &discord = Abaddon::Get().GetDiscordClient();
-
- if (member.User->HasAnimatedAvatar() && Abaddon::Get().GetSettings().GetShowAnimations())
- m_avatar.SetURL(member.User->GetAvatarURL("gif", "32"));
- else
- m_avatar.SetURL(member.User->GetAvatarURL("png", "32"));
-
- DisplayTerm = member.User->Username + "#" + member.User->Discriminator;
-
- const auto member_update_cb = [this](Snowflake guild_id, Snowflake user_id) {
- if (user_id == UserID)
- UpdateColor();
- };
- discord.signal_guild_member_update().connect(sigc::track_obj(member_update_cb, *this));
- UpdateColor();
-
- static bool crown = Abaddon::Get().GetSettings().GetShowOwnerCrown();
- if (crown && guild.OwnerID == member.User->ID) {
- try {
- const static auto crown_path = Abaddon::GetResPath("/crown.png");
- auto pixbuf = Gdk::Pixbuf::create_from_file(crown_path, 12, 12);
- m_crown = Gtk::manage(new Gtk::Image(pixbuf));
- m_crown->set_valign(Gtk::ALIGN_CENTER);
- m_crown->set_margin_start(10);
- m_crown->show();
- } catch (...) {}
- }
-
- m_avatar.set_margin_end(5);
- m_avatar.set_halign(Gtk::ALIGN_START);
- m_avatar.set_valign(Gtk::ALIGN_CENTER);
- m_name.set_halign(Gtk::ALIGN_START);
- m_name.set_valign(Gtk::ALIGN_CENTER);
-
- m_main.set_hexpand(true);
-
- m_main.add(m_avatar);
- m_main.add(m_name);
- if (m_crown != nullptr)
- m_main.add(*m_crown);
-
- m_ev.add(m_main);
- add(m_ev);
-
- m_avatar.show();
- m_name.show();
- m_main.show();
- m_ev.show();
-}
-
-void GuildSettingsMembersListItem::UpdateColor() {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto user = *discord.GetUser(UserID);
- if (auto color_id = discord.GetMemberHoistedRole(GuildID, UserID, true); color_id.IsValid()) {
- auto role = *discord.GetRole(color_id);
- m_name.set_markup("<span color='#" + IntToCSSColor(role.Color) + "'>" + user.GetEscapedBoldString<false>() + "</span>");
- } else
- m_name.set_markup(user.GetEscapedBoldString<false>());
-}
-
-GuildSettingsMembersPaneInfo::GuildSettingsMembersPaneInfo(Snowflake guild_id)
- : GuildID(guild_id)
- , m_roles(guild_id)
- , m_box(Gtk::ORIENTATION_VERTICAL) {
- get_style_context()->add_class("guild-members-pane-info");
-
- const auto label = [](Gtk::Label &lbl) {
- lbl.set_single_line_mode(true);
- lbl.set_halign(Gtk::ALIGN_START);
- lbl.set_valign(Gtk::ALIGN_START);
- lbl.set_ellipsize(Pango::ELLIPSIZE_END);
- lbl.set_margin_bottom(5);
- lbl.show();
- };
-
- m_bot.set_text("User is a bot");
-
- label(m_bot);
- label(m_id);
- label(m_created);
- label(m_joined);
- label(m_nickname);
- label(m_boosting);
-
- m_box.set_halign(Gtk::ALIGN_FILL);
- m_box.set_valign(Gtk::ALIGN_START);
- m_box.set_hexpand(true);
- m_box.set_vexpand(true);
- m_box.add(m_bot);
- m_box.add(m_id);
- m_box.add(m_created);
- m_box.add(m_joined);
- m_box.add(m_nickname);
- m_box.add(m_boosting);
- m_box.add(m_roles);
-
- m_bot.hide();
- m_box.show();
-
- add(m_box);
-}
-
-void GuildSettingsMembersPaneInfo::SetUser(Snowflake user_id) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto guild = *discord.GetGuild(GuildID);
- auto member = *discord.GetMember(user_id, GuildID);
- member.User = discord.GetUser(user_id);
-
- m_bot.set_visible(member.User->IsBot.has_value() && *member.User->IsBot);
-
- m_id.set_text("User ID: " + std::to_string(user_id));
- m_created.set_text("Account created: " + user_id.GetLocalTimestamp());
- if (member.JoinedAt != "")
- m_joined.set_text("Joined server: " + FormatISO8601(member.JoinedAt));
- else
- m_joined.set_text("Joined server: Unknown");
- m_nickname.set_text("Nickname: " + member.Nickname);
- m_nickname.set_visible(member.Nickname != "");
- if (member.PremiumSince.has_value()) {
- m_boosting.set_text("Boosting since " + FormatISO8601(*member.PremiumSince));
- m_boosting.show();
- } else
- m_boosting.hide();
-
- m_roles.show();
- m_roles.SetRoles(user_id, member.Roles, guild.OwnerID == discord.GetUserData().ID);
-}
-
-GuildSettingsMembersPaneRoles::GuildSettingsMembersPaneRoles(Snowflake guild_id)
- : GuildID(guild_id) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto self_id = discord.GetUserData().ID;
- const bool can_modify = discord.HasGuildPermission(self_id, guild_id, Permission::MANAGE_ROLES);
- const auto highest = discord.GetMemberHighestRole(GuildID, self_id);
- if (highest.has_value())
- m_hoisted_position = highest->Position;
-
- discord.signal_role_create().connect(sigc::mem_fun(*this, &GuildSettingsMembersPaneRoles::OnRoleCreate));
- discord.signal_role_update().connect(sigc::mem_fun(*this, &GuildSettingsMembersPaneRoles::OnRoleUpdate));
- discord.signal_role_delete().connect(sigc::mem_fun(*this, &GuildSettingsMembersPaneRoles::OnRoleDelete));
-
- const auto guild = *discord.GetGuild(guild_id);
- const auto roles = guild.FetchRoles();
- for (const auto &role : roles) {
- CreateRow(can_modify, role, guild.OwnerID == self_id);
- }
-
- m_list.set_sort_func([this](Gtk::ListBoxRow *a, Gtk::ListBoxRow *b) -> int {
- auto *rowa = dynamic_cast<GuildSettingsMembersPaneRolesItem *>(a);
- auto *rowb = dynamic_cast<GuildSettingsMembersPaneRolesItem *>(b);
- return rowb->Position - rowa->Position;
- });
-
- set_propagate_natural_height(true);
- set_propagate_natural_width(true);
- set_hexpand(true);
- set_vexpand(true);
- set_halign(Gtk::ALIGN_FILL);
- set_valign(Gtk::ALIGN_START);
-
- m_list.show();
-
- add(m_list);
-}
-
-void GuildSettingsMembersPaneRoles::SetRoles(Snowflake user_id, const std::vector<Snowflake> &roles, bool is_owner) {
- UserID = user_id;
-
- for (auto it = m_update_connection.begin(); it != m_update_connection.end();) {
- it->disconnect();
- it = m_update_connection.erase(it);
- }
-
- m_set_role_ids = { roles.begin(), roles.end() };
- for (const auto &[role_id, row] : m_rows) {
- auto role = *Abaddon::Get().GetDiscordClient().GetRole(role_id);
- if (role.ID == GuildID) {
- row->SetChecked(true);
- row->SetToggleable(false);
- } else {
- row->SetToggleable(role.Position < m_hoisted_position || is_owner);
- row->SetChecked(m_set_role_ids.find(role_id) != m_set_role_ids.end());
- }
- }
-}
-
-void GuildSettingsMembersPaneRoles::CreateRow(bool has_manage_roles, const RoleData &role, bool is_owner) {
- auto *row = Gtk::manage(new GuildSettingsMembersPaneRolesItem(has_manage_roles, role));
- if (role.ID == GuildID) {
- row->SetChecked(true);
- row->SetToggleable(false);
- } else
- row->SetToggleable(role.Position < m_hoisted_position || is_owner);
- row->signal_role_click().connect(sigc::mem_fun(*this, &GuildSettingsMembersPaneRoles::OnRoleToggle));
- row->show();
- m_rows[role.ID] = row;
- m_list.add(*row);
-}
-
-void GuildSettingsMembersPaneRoles::OnRoleToggle(Snowflake role_id, bool new_set) {
- auto row = m_rows.at(role_id);
- row->SetToggleable(false);
- auto &discord = Abaddon::Get().GetDiscordClient();
- auto cb = [this, new_set, role_id, row](bool success) {
- if (!success) { // undo
- if (new_set)
- m_set_role_ids.erase(role_id);
- else
- m_set_role_ids.insert(role_id);
- } else
- row->SetChecked(new_set);
-
- row->SetToggleable(true);
- };
-
- if (new_set)
- m_set_role_ids.insert(role_id);
- else
- m_set_role_ids.erase(role_id);
-
- // hack to prevent cb from being called if SetRoles is called before callback completion
- sigc::signal<void, bool> tmp;
- m_update_connection.push_back(tmp.connect(std::move(cb)));
- const auto tmp_cb = [this, tmp = std::move(tmp)](DiscordError code) { tmp.emit(code == DiscordError::NONE); };
- discord.SetMemberRoles(GuildID, UserID, m_set_role_ids.begin(), m_set_role_ids.end(), sigc::track_obj(tmp_cb, *this));
-}
-
-void GuildSettingsMembersPaneRoles::OnRoleCreate(Snowflake guild_id, Snowflake role_id) {
- if (guild_id != GuildID) return;
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto self_id = discord.GetUserData().ID;
- const bool can_modify = discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_ROLES);
- const auto role = *discord.GetRole(role_id);
- CreateRow(can_modify, role, discord.GetGuild(guild_id)->OwnerID == self_id);
-}
-
-void GuildSettingsMembersPaneRoles::OnRoleUpdate(Snowflake guild_id, Snowflake role_id) {
- if (guild_id != GuildID) return;
- auto role = *Abaddon::Get().GetDiscordClient().GetRole(role_id);
- m_rows.at(role_id)->UpdateRoleData(role);
- m_list.invalidate_sort();
-}
-
-void GuildSettingsMembersPaneRoles::OnRoleDelete(Snowflake guild_id, Snowflake role_id) {
- if (guild_id != GuildID) return;
- delete m_rows.at(role_id);
-}
-
-GuildSettingsMembersPaneRolesItem::GuildSettingsMembersPaneRolesItem(bool sensitive, const RoleData &role)
- : RoleID(role.ID) {
- UpdateRoleData(role);
-
- m_main.set_hexpand(true);
- m_main.set_vexpand(true);
-
- const auto cb = [this](GdkEventButton *event) -> bool {
- if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) {
- m_signal_role_click.emit(RoleID, !m_check.get_active());
- return true;
- }
- return false;
- };
- m_check.signal_button_press_event().connect(cb, false);
-
- m_desired_sensitivity = sensitive;
- ComputeSensitivity();
-
- m_check.set_margin_start(5);
- m_label.set_margin_start(5);
-
- m_main.add(m_check);
- m_main.add(m_label);
- add(m_main);
- m_check.show();
- m_label.show();
- m_main.show();
-}
-
-void GuildSettingsMembersPaneRolesItem::SetChecked(bool checked) {
- m_check.set_active(checked);
-}
-
-void GuildSettingsMembersPaneRolesItem::SetToggleable(bool toggleable) {
- m_desired_sensitivity = toggleable;
- ComputeSensitivity();
-}
-
-void GuildSettingsMembersPaneRolesItem::UpdateRoleData(const RoleData &role) {
- m_role = role;
- Position = role.Position;
- UpdateLabel();
-}
-
-void GuildSettingsMembersPaneRolesItem::UpdateLabel() {
- if (m_role.Color)
- m_label.set_markup("<span color='#" + IntToCSSColor(m_role.Color) + "'>" + Glib::Markup::escape_text(m_role.Name) + "</span>");
- else
- m_label.set_text(m_role.Name);
-}
-
-void GuildSettingsMembersPaneRolesItem::ComputeSensitivity() {
- if (m_role.IsManaged) {
- m_check.set_sensitive(false);
- return;
- }
- m_check.set_sensitive(m_desired_sensitivity);
-}
-
-GuildSettingsMembersPaneRolesItem::type_signal_role_click GuildSettingsMembersPaneRolesItem::signal_role_click() {
- return m_signal_role_click;
-}
diff --git a/windows/guildsettings/memberspane.hpp b/windows/guildsettings/memberspane.hpp
deleted file mode 100644
index 01398da..0000000
--- a/windows/guildsettings/memberspane.hpp
+++ /dev/null
@@ -1,135 +0,0 @@
-#pragma once
-#include <unordered_set>
-#include <gtkmm.h>
-#include "discord/member.hpp"
-#include "discord/guild.hpp"
-#include "components/lazyimage.hpp"
-
-class GuildSettingsMembersPaneRolesItem : public Gtk::ListBoxRow {
-public:
- GuildSettingsMembersPaneRolesItem(bool sensitive, const RoleData &role);
- void SetChecked(bool checked);
- void SetToggleable(bool toggleable);
- void UpdateRoleData(const RoleData &role);
-
- Snowflake RoleID;
- int Position;
-
-private:
- void UpdateLabel();
- void ComputeSensitivity();
- bool m_desired_sensitivity = true;
-
- RoleData m_role;
-
- Gtk::Box m_main;
- Gtk::CheckButton m_check;
- Gtk::Label m_label;
-
- // own thing so we can stop it from actually changing
- typedef sigc::signal<void, Snowflake, bool> type_signal_role_click;
-
- type_signal_role_click m_signal_role_click;
-
-public:
- type_signal_role_click signal_role_click();
-};
-
-class GuildSettingsMembersPaneRoles : public Gtk::ScrolledWindow {
-public:
- GuildSettingsMembersPaneRoles(Snowflake guild_id);
-
- void SetRoles(Snowflake user_id, const std::vector<Snowflake> &roles, bool is_owner);
-
-private:
- void CreateRow(bool has_manage_roles, const RoleData &role, bool is_owner);
-
- void OnRoleToggle(Snowflake role_id, bool new_set);
-
- void OnRoleCreate(Snowflake guild_id, Snowflake role_id);
- void OnRoleUpdate(Snowflake guild_id, Snowflake role_id);
- void OnRoleDelete(Snowflake guild_id, Snowflake role_id);
-
- int m_hoisted_position = 0;
-
- std::vector<sigc::connection> m_update_connection;
-
- std::unordered_set<Snowflake> m_set_role_ids;
-
- Snowflake GuildID;
- Snowflake UserID;
-
- Gtk::ListBox m_list;
-
- std::unordered_map<Snowflake, GuildSettingsMembersPaneRolesItem *> m_rows;
-};
-
-class GuildSettingsMembersPaneInfo : public Gtk::ScrolledWindow {
-public:
- GuildSettingsMembersPaneInfo(Snowflake guild_id);
-
- void SetUser(Snowflake user_id);
-
-private:
- Snowflake GuildID;
- Snowflake UserID;
-
- Gtk::Label m_bot;
- Gtk::Label m_id;
- Gtk::Label m_created;
- Gtk::Label m_joined;
- Gtk::Label m_nickname;
- Gtk::Label m_boosting;
- GuildSettingsMembersPaneRoles m_roles;
- Gtk::Box m_box;
-};
-
-class GuildSettingsMembersPaneMembers : public Gtk::Box {
-public:
- GuildSettingsMembersPaneMembers(Snowflake id);
-
-private:
- Snowflake GuildID;
-
- Gtk::Entry m_search;
- Gtk::ScrolledWindow m_list_scroll;
- Gtk::ListBox m_list;
-
- typedef sigc::signal<void, Snowflake> type_signal_member_select;
- type_signal_member_select m_signal_member_select;
-
-public:
- type_signal_member_select signal_member_select();
-};
-
-class GuildSettingsMembersListItem : public Gtk::ListBoxRow {
-public:
- GuildSettingsMembersListItem(const GuildData &guild, const GuildMember &member);
-
- Glib::ustring DisplayTerm;
-
- Snowflake UserID;
- Snowflake GuildID;
-
-private:
- void UpdateColor();
-
- Gtk::EventBox m_ev;
- LazyImage m_avatar;
- Gtk::Label m_name;
- Gtk::Box m_main;
- Gtk::Image *m_crown = nullptr;
-};
-
-class GuildSettingsMembersPane : public Gtk::Box {
-public:
- GuildSettingsMembersPane(Snowflake id);
-
-private:
- Snowflake GuildID;
-
- Gtk::Box m_layout;
- Gtk::Label m_note;
- GuildSettingsMembersPaneMembers m_member_list;
- GuildSettingsMembersPaneInfo m_member_info;
-};
diff --git a/windows/guildsettings/rolespane.cpp b/windows/guildsettings/rolespane.cpp
deleted file mode 100644
index 8d355ee..0000000
--- a/windows/guildsettings/rolespane.cpp
+++ /dev/null
@@ -1,419 +0,0 @@
-#include "rolespane.hpp"
-#include "abaddon.hpp"
-
-GuildSettingsRolesPane::GuildSettingsRolesPane(Snowflake id)
- : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)
- , GuildID(id)
- , m_roles_list(id)
- , m_roles_perms(id) {
- set_name("guild-roles-pane");
- set_hexpand(true);
- set_vexpand(true);
-
- m_roles_list.signal_role_select().connect(sigc::mem_fun(*this, &GuildSettingsRolesPane::OnRoleSelect));
-
- m_roles_perms.set_sensitive(false);
-
- m_layout.set_homogeneous(true);
- m_layout.add(m_roles_list);
- m_layout.add(m_roles_perms);
- add(m_layout);
-
- m_roles_list.show();
- m_roles_perms.show();
- m_layout.show();
-}
-
-void GuildSettingsRolesPane::OnRoleSelect(Snowflake role_id) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto role = *discord.GetRole(role_id);
- m_roles_perms.SetRole(role);
- m_roles_perms.set_sensitive(discord.CanModifyRole(GuildID, role_id));
-}
-
-static std::vector<Gtk::TargetEntry> g_target_entries = {
- Gtk::TargetEntry("GTK_LIST_ROLES_ROW", Gtk::TARGET_SAME_APP, 0)
-};
-
-GuildSettingsRolesPaneRoles::GuildSettingsRolesPaneRoles(Snowflake guild_id)
- : Gtk::Box(Gtk::ORIENTATION_VERTICAL)
- , GuildID(guild_id) {
- m_list.get_style_context()->add_class("guild-roles-pane-list");
-
- m_list_scroll.set_hexpand(true);
- m_list_scroll.set_vexpand(true);
- m_list_scroll.set_propagate_natural_height(true);
- m_list_scroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
-
- m_list.set_selection_mode(Gtk::SELECTION_SINGLE);
- m_list.signal_row_selected().connect([this](Gtk::ListBoxRow *selected_) {
- if (auto *selected = dynamic_cast<GuildSettingsRolesPaneRolesListItem *>(selected_))
- m_signal_role_select.emit(selected->RoleID);
- });
-
- m_list.set_focus_vadjustment(m_list_scroll.get_vadjustment());
- m_list.signal_on_drop().connect([this](Gtk::ListBoxRow *row_, int new_index) -> bool {
- if (auto *row = dynamic_cast<GuildSettingsRolesPaneRolesListItem *>(row_)) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto num_rows = m_list.get_children().size();
- const auto new_pos = num_rows - new_index - 1;
- if (row->RoleID == GuildID) return true; // moving role @everyone
- if (static_cast<size_t>(new_index) == num_rows) return true; // trying to move row below @everyone
- // make sure it wont modify a neighbor role u dont have perms to modify
- if (!discord.CanModifyRole(GuildID, row->RoleID)) return false;
- const auto cb = [this](DiscordError code) {
- if (code != DiscordError::NONE) {
- Gtk::MessageDialog dlg("Failed to set role position", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- dlg.set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
- dlg.run();
- }
- };
- discord.ModifyRolePosition(GuildID, row->RoleID, new_pos, sigc::track_obj(cb, *this));
- return true;
- }
- return false;
- });
-
- auto &discord = Abaddon::Get().GetDiscordClient();
- discord.signal_role_create().connect(sigc::mem_fun(*this, &GuildSettingsRolesPaneRoles::OnRoleCreate));
- discord.signal_role_delete().connect(sigc::mem_fun(*this, &GuildSettingsRolesPaneRoles::OnRoleDelete));
-
- const auto guild = *discord.GetGuild(GuildID);
- const auto roles = guild.FetchRoles();
- const bool can_modify = discord.HasGuildPermission(discord.GetUserData().ID, GuildID, Permission::MANAGE_ROLES);
- for (const auto &role : roles) {
- auto *row = Gtk::manage(new GuildSettingsRolesPaneRolesListItem(guild, role));
- row->drag_source_set(g_target_entries, Gdk::BUTTON1_MASK, Gdk::ACTION_MOVE);
- row->set_margin_start(5);
- row->set_halign(Gtk::ALIGN_FILL);
- row->show();
- m_rows[role.ID] = row;
- if (can_modify)
- m_list.add_draggable(row);
- else
- m_list.add(*row);
- }
-
- m_list.set_sort_func([this](Gtk::ListBoxRow *rowa_, Gtk::ListBoxRow *rowb_) -> int {
- auto *rowa = dynamic_cast<GuildSettingsRolesPaneRolesListItem *>(rowa_);
- auto *rowb = dynamic_cast<GuildSettingsRolesPaneRolesListItem *>(rowb_);
- return rowb->Position - rowa->Position;
- });
- m_list.invalidate_sort();
-
- m_list.set_filter_func([this](Gtk::ListBoxRow *row_) -> bool {
- const auto search_term = m_search.get_text();
- if (search_term.size() == 0) return true;
- if (auto *row = dynamic_cast<GuildSettingsRolesPaneRolesListItem *>(row_))
- return StringContainsCaseless(row->DisplayTerm, m_search.get_text());
- return true;
- });
-
- m_search.set_placeholder_text("Filter");
- m_search.signal_changed().connect([this] {
- m_list.invalidate_filter();
- });
-
- m_list_scroll.add(m_list);
- add(m_search);
- add(m_list_scroll);
-
- m_search.show();
- m_list.show();
- m_list_scroll.show();
-}
-
-void GuildSettingsRolesPaneRoles::OnRoleCreate(Snowflake guild_id, Snowflake role_id) {
- if (guild_id != GuildID) return;
- auto &discord = Abaddon::Get().GetDiscordClient();
- const bool can_modify = discord.HasGuildPermission(discord.GetUserData().ID, guild_id, Permission::MANAGE_ROLES);
- const auto guild = *discord.GetGuild(guild_id);
- const auto role = *discord.GetRole(role_id);
- auto *row = Gtk::manage(new GuildSettingsRolesPaneRolesListItem(guild, role));
- row->show();
- m_rows[role_id] = row;
- if (can_modify)
- m_list.add_draggable(row);
- else
- m_list.add(*row);
-}
-
-void GuildSettingsRolesPaneRoles::OnRoleDelete(Snowflake guild_id, Snowflake role_id) {
- if (guild_id != GuildID) return;
- auto it = m_rows.find(role_id);
- delete it->second;
- m_rows.erase(it);
-}
-
-GuildSettingsRolesPaneRoles::type_signal_role_select GuildSettingsRolesPaneRoles::signal_role_select() {
- return m_signal_role_select;
-}
-
-GuildSettingsRolesPaneRolesListItem::GuildSettingsRolesPaneRolesListItem(const GuildData &guild, const RoleData &role)
- : GuildID(guild.ID)
- , RoleID(role.ID)
- , Position(role.Position) {
- auto &discord = Abaddon::Get().GetDiscordClient();
-
- set_hexpand(true);
-
- UpdateItem(role);
-
- discord.signal_role_update().connect(sigc::mem_fun(*this, &GuildSettingsRolesPaneRolesListItem::OnRoleUpdate));
-
- m_name.set_ellipsize(Pango::ELLIPSIZE_END);
-
- m_ev.set_halign(Gtk::ALIGN_START);
- m_ev.add(m_name);
- add(m_ev);
-
- m_name.show();
- m_ev.show();
-}
-
-void GuildSettingsRolesPaneRolesListItem::UpdateItem(const RoleData &role) {
- DisplayTerm = role.Name;
-
- if (role.Color != 0)
- m_name.set_markup("<span color='#" + IntToCSSColor(role.Color) + "'>" +
- Glib::Markup::escape_text(role.Name) +
- "</span>");
- else
- m_name.set_text(role.Name);
-}
-
-void GuildSettingsRolesPaneRolesListItem::OnRoleUpdate(Snowflake guild_id, Snowflake role_id) {
- if (guild_id != GuildID || role_id != RoleID) return;
- const auto role = Abaddon::Get().GetDiscordClient().GetRole(RoleID);
- if (!role.has_value()) return;
- Position = role->Position;
- UpdateItem(*role);
- changed();
-}
-
-GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id)
- : GuildID(guild_id)
- , m_layout(Gtk::ORIENTATION_VERTICAL)
- , m_meta(Gtk::ORIENTATION_HORIZONTAL) {
- set_propagate_natural_height(true);
- set_propagate_natural_width(true);
-
- auto &discord = Abaddon::Get().GetDiscordClient();
- discord.signal_role_update().connect(sigc::mem_fun(*this, &GuildSettingsRolesPaneInfo::OnRoleUpdate));
-
- const auto cb = [this](GdkEventKey *e) -> bool {
- if (e->keyval == GDK_KEY_Return)
- UpdateRoleName();
- return false;
- };
- m_role_name.signal_key_press_event().connect(cb, false);
-
- m_role_name.set_tooltip_text("Press enter to submit");
-
- m_role_name.set_max_length(100);
-
- m_role_name.set_margin_top(5);
- m_role_name.set_margin_bottom(5);
- m_role_name.set_margin_start(5);
- m_role_name.set_margin_end(5);
-
- m_color_button.set_margin_top(5);
- m_color_button.set_margin_bottom(5);
- m_color_button.set_margin_start(5);
- m_color_button.set_margin_end(5);
-
- m_color_button.signal_color_set().connect([this, &discord]() {
- const auto color = m_color_button.get_rgba();
- const auto cb = [this, &discord](DiscordError code) {
- if (code != DiscordError::NONE) {
- m_color_button.set_rgba(IntToRGBA(discord.GetRole(RoleID)->Color));
- Gtk::MessageDialog dlg("Failed to set role color", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- dlg.set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
- dlg.run();
- }
- };
- discord.ModifyRoleColor(GuildID, RoleID, color, cb);
- });
-
- int left_ypos = 0;
- int right_ypos = 0;
-
- const int LEFT = 0;
- const int RIGHT = 1;
-
- auto add_perms = [&](const std::string &label, int side, const std::initializer_list<Permission> &perms) {
- int &pos = side == LEFT ? left_ypos : right_ypos;
- auto *header = Gtk::manage(new Gtk::Label(label));
- header->show();
- m_grid.attach(*header, side, pos++, 1, 1);
- for (const auto perm : perms) {
- auto *btn = Gtk::manage(new GuildSettingsRolesPanePermItem(perm));
- btn->signal_permission_click().connect(sigc::mem_fun(*this, &GuildSettingsRolesPaneInfo::OnPermissionToggle));
- m_perm_items[perm] = btn;
- btn->show();
- m_grid.attach(*btn, side, pos++, 1, 1);
- }
- pos++;
- };
-
- // fuck you clang-format you suck
- // clang-format off
- add_perms("General", LEFT, {
- Permission::VIEW_CHANNEL,
- Permission::MANAGE_CHANNELS,
- Permission::MANAGE_ROLES,
- Permission::MANAGE_EMOJIS,
- Permission::VIEW_AUDIT_LOG,
- Permission::VIEW_GUILD_INSIGHTS,
- Permission::MANAGE_WEBHOOKS,
- Permission::MANAGE_GUILD });
-
- add_perms("Membership", LEFT, {
- Permission::CREATE_INSTANT_INVITE,
- Permission::CHANGE_NICKNAME,
- Permission::MANAGE_NICKNAMES,
- Permission::KICK_MEMBERS,
- Permission::BAN_MEMBERS });
-
- add_perms("Text Channels", RIGHT, {
- Permission::SEND_MESSAGES,
- Permission::USE_PUBLIC_THREADS,
- Permission::USE_PRIVATE_THREADS,
- Permission::EMBED_LINKS,
- Permission::ATTACH_FILES,
- Permission::ADD_REACTIONS,
- Permission::USE_EXTERNAL_EMOJIS,
- Permission::MENTION_EVERYONE,
- Permission::MANAGE_MESSAGES,
- Permission::MANAGE_THREADS,
- Permission::READ_MESSAGE_HISTORY,
- Permission::SEND_TTS_MESSAGES,
- Permission::USE_SLASH_COMMANDS });
-
- add_perms("Voice Channels", RIGHT, {
- Permission::CONNECT,
- Permission::SPEAK,
- Permission::STREAM,
- Permission::USE_VAD,
- Permission::PRIORITY_SPEAKER,
- Permission::MUTE_MEMBERS,
- Permission::DEAFEN_MEMBERS,
- Permission::MOVE_MEMBERS });
-
- add_perms("Advanced", LEFT, { Permission::ADMINISTRATOR });
-
- // clang-format on
-
- m_meta.add(m_role_name);
- m_meta.add(m_color_button);
- m_layout.add(m_meta);
- m_layout.add(m_grid);
- add(m_layout);
- m_meta.show();
- m_color_button.show();
- m_role_name.show();
- m_layout.show();
- m_grid.show();
-}
-
-void GuildSettingsRolesPaneInfo::SetRole(const RoleData &role) {
- for (auto it = m_update_connections.begin(); it != m_update_connections.end();) {
- it->disconnect();
- it = m_update_connections.erase(it);
- }
-
- if (role.Color != 0) {
- m_color_button.set_rgba(IntToRGBA(role.Color));
- } else {
- static Gdk::RGBA trans;
- trans.set_alpha(0.0);
- m_color_button.set_rgba(trans);
- }
-
- m_role_name.set_text(role.Name);
-
- RoleID = role.ID;
- m_perms = role.Permissions;
- for (const auto [perm, btn] : m_perm_items) {
- btn->set_sensitive(true);
- btn->set_active((role.Permissions & perm) == perm);
- }
-}
-
-void GuildSettingsRolesPaneInfo::OnRoleUpdate(Snowflake guild_id, Snowflake role_id) {
- if (guild_id != GuildID || role_id != RoleID) return;
- const auto role = *Abaddon::Get().GetDiscordClient().GetRole(RoleID);
- m_role_name.set_text(role.Name);
-
- if (role.Color != 0) {
- m_color_button.set_rgba(IntToRGBA(role.Color));
- } else {
- static Gdk::RGBA trans;
- trans.set_alpha(0.0);
- m_color_button.set_rgba(trans);
- }
-
- m_perms = role.Permissions;
- for (const auto [perm, btn] : m_perm_items)
- btn->set_active((role.Permissions & perm) == perm);
-}
-
-void GuildSettingsRolesPaneInfo::OnPermissionToggle(Permission perm, bool new_set) {
- auto btn = m_perm_items.at(perm);
- btn->set_sensitive(false);
- auto &discord = Abaddon::Get().GetDiscordClient();
- auto cb = [this, new_set, perm, btn](bool success) {
- if (!success) { // undo
- if (new_set)
- m_perms &= ~perm;
- else
- m_perms |= perm;
- } else
- btn->set_active(new_set);
- btn->set_sensitive(true);
- };
-
- if (new_set)
- m_perms |= perm;
- else
- m_perms &= ~perm;
-
- sigc::signal<void, bool> tmp;
- m_update_connections.push_back(tmp.connect(std::move(cb)));
- const auto tmp_cb = [this, tmp = std::move(tmp)](DiscordError code) { tmp.emit(code == DiscordError::NONE); };
- discord.ModifyRolePermissions(GuildID, RoleID, m_perms, sigc::track_obj(tmp_cb, *this));
-}
-
-void GuildSettingsRolesPaneInfo::UpdateRoleName() {
- auto &discord = Abaddon::Get().GetDiscordClient();
- if (discord.GetRole(RoleID)->Name == m_role_name.get_text()) return;
-
- const auto cb = [this, &discord](DiscordError code) {
- if (code != DiscordError::NONE) {
- m_role_name.set_text(discord.GetRole(RoleID)->Name);
- Gtk::MessageDialog dlg("Failed to set role name", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- dlg.set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
- dlg.run();
- }
- };
- discord.ModifyRoleName(GuildID, RoleID, m_role_name.get_text(), cb);
-}
-
-GuildSettingsRolesPanePermItem::GuildSettingsRolesPanePermItem(Permission perm)
- : Gtk::CheckButton(GetPermissionString(perm))
- , m_permission(perm) {
- set_tooltip_text(GetPermissionDescription(m_permission));
-
- const auto cb = [this](GdkEventButton *event) -> bool {
- if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) {
- m_signal_permission.emit(m_permission, !get_active());
- return true;
- }
- return false;
- };
- signal_button_press_event().connect(cb, false);
-}
-
-GuildSettingsRolesPanePermItem::type_signal_permission_click GuildSettingsRolesPanePermItem::signal_permission_click() {
- return m_signal_permission;
-}
diff --git a/windows/guildsettings/rolespane.hpp b/windows/guildsettings/rolespane.hpp
deleted file mode 100644
index 2999f32..0000000
--- a/windows/guildsettings/rolespane.hpp
+++ /dev/null
@@ -1,102 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include <unordered_map>
-#include "discord/guild.hpp"
-#include "components/draglistbox.hpp"
-
-class GuildSettingsRolesPaneRolesListItem : public Gtk::ListBoxRow {
-public:
- GuildSettingsRolesPaneRolesListItem(const GuildData &guild, const RoleData &role);
-
- Glib::ustring DisplayTerm;
-
- Snowflake GuildID;
- Snowflake RoleID;
- int Position;
-
-private:
- void UpdateItem(const RoleData &role);
- void OnRoleUpdate(Snowflake guild_id, Snowflake role_id);
-
- Gtk::EventBox m_ev;
- Gtk::Label m_name;
-};
-
-class GuildSettingsRolesPaneRoles : public Gtk::Box {
-public:
- GuildSettingsRolesPaneRoles(Snowflake guild_id);
-
-private:
- void OnRoleCreate(Snowflake guild_id, Snowflake role_id);
- void OnRoleDelete(Snowflake guild_id, Snowflake role_id);
-
- Snowflake GuildID;
-
- Gtk::Entry m_search;
- Gtk::ScrolledWindow m_list_scroll;
- DragListBox m_list;
-
- typedef sigc::signal<void, Snowflake /* role_id */> type_signal_role_select;
- type_signal_role_select m_signal_role_select;
-
-public:
- std::unordered_map<Snowflake, GuildSettingsRolesPaneRolesListItem *> m_rows;
- type_signal_role_select signal_role_select();
-};
-
-class GuildSettingsRolesPanePermItem : public Gtk::CheckButton {
-public:
- GuildSettingsRolesPanePermItem(Permission perm);
-
-private:
- Permission m_permission;
-
- typedef sigc::signal<void, Permission, bool> type_signal_permission_click;
-
- type_signal_permission_click m_signal_permission;
-
-public:
- type_signal_permission_click signal_permission_click();
-};
-
-class GuildSettingsRolesPaneInfo : public Gtk::ScrolledWindow {
-public:
- GuildSettingsRolesPaneInfo(Snowflake guild_id);
-
- void SetRole(const RoleData &role);
-
-private:
- void OnRoleUpdate(Snowflake guild_id, Snowflake role_id);
- void OnPermissionToggle(Permission perm, bool new_set);
-
- void UpdateRoleName();
-
- Snowflake GuildID;
- Snowflake RoleID;
-
- Permission m_perms;
-
- std::vector<sigc::connection> m_update_connections;
-
- Gtk::Box m_layout;
- Gtk::Box m_meta;
- Gtk::Entry m_role_name;
- Gtk::ColorButton m_color_button;
- Gtk::Grid m_grid;
-
- std::unordered_map<Permission, GuildSettingsRolesPanePermItem *> m_perm_items;
-};
-
-class GuildSettingsRolesPane : public Gtk::Box {
-public:
- GuildSettingsRolesPane(Snowflake id);
-
-private:
- void OnRoleSelect(Snowflake role_id);
-
- Snowflake GuildID;
-
- Gtk::Box m_layout;
- GuildSettingsRolesPaneRoles m_roles_list;
- GuildSettingsRolesPaneInfo m_roles_perms;
-};
diff --git a/windows/guildsettingswindow.cpp b/windows/guildsettingswindow.cpp
deleted file mode 100644
index 1e3395d..0000000
--- a/windows/guildsettingswindow.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "guildsettingswindow.hpp"
-#include "abaddon.hpp"
-
-GuildSettingsWindow::GuildSettingsWindow(Snowflake id)
- : m_main(Gtk::ORIENTATION_VERTICAL)
- , m_pane_info(id)
- , m_pane_members(id)
- , m_pane_roles(id)
- , m_pane_bans(id)
- , m_pane_invites(id)
- , m_pane_emojis(id)
- , m_pane_audit_log(id)
- , GuildID(id) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- const auto guild = *discord.GetGuild(id);
-
- auto guild_update_cb = [this](Snowflake id) {
- if (id != GuildID) return;
- const auto guild = *Abaddon::Get().GetDiscordClient().GetGuild(id);
- set_title(guild.Name);
- if (guild.HasIcon())
- Abaddon::Get().GetImageManager().LoadFromURL(guild.GetIconURL(), sigc::mem_fun(*this, &GuildSettingsWindow::set_icon));
- };
- discord.signal_guild_update().connect(sigc::track_obj(guild_update_cb, *this));
-
- set_name("guild-settings");
- set_default_size(800, 600);
- set_title(guild.Name);
- set_position(Gtk::WIN_POS_CENTER);
- get_style_context()->add_class("app-window");
- get_style_context()->add_class("app-popup");
- get_style_context()->add_class("guild-settings-window");
-
- if (guild.HasIcon()) {
- Abaddon::Get().GetImageManager().LoadFromURL(guild.GetIconURL(), sigc::mem_fun(*this, &GuildSettingsWindow::set_icon));
- }
-
- m_switcher.set_stack(m_stack);
- m_switcher.set_halign(Gtk::ALIGN_CENTER);
- m_switcher.set_hexpand(true);
- m_switcher.set_margin_top(10);
- m_switcher.show();
-
- m_pane_info.show();
- m_pane_members.show();
- m_pane_roles.show();
- m_pane_bans.show();
- m_pane_invites.show();
- m_pane_emojis.show();
- m_pane_audit_log.show();
-
- m_stack.set_transition_duration(100);
- m_stack.set_transition_type(Gtk::STACK_TRANSITION_TYPE_CROSSFADE);
- m_stack.set_margin_top(10);
- m_stack.set_margin_bottom(10);
- m_stack.set_margin_left(10);
- m_stack.set_margin_right(10);
-
- const auto self_id = discord.GetUserData().ID;
-
- m_stack.add(m_pane_info, "info", "Info");
- m_stack.add(m_pane_members, "members", "Members");
- m_stack.add(m_pane_roles, "roles", "Roles");
- m_stack.add(m_pane_bans, "bans", "Bans");
- if (discord.HasGuildPermission(self_id, GuildID, Permission::MANAGE_GUILD))
- m_stack.add(m_pane_invites, "invites", "Invites");
- m_stack.add(m_pane_emojis, "emojis", "Emojis");
- if (discord.HasGuildPermission(self_id, GuildID, Permission::VIEW_AUDIT_LOG))
- m_stack.add(m_pane_audit_log, "audit-log", "Audit Log");
- m_stack.show();
-
- m_main.add(m_switcher);
- m_main.add(m_stack);
- m_main.show();
- add(m_main);
-}
diff --git a/windows/guildsettingswindow.hpp b/windows/guildsettingswindow.hpp
deleted file mode 100644
index b591640..0000000
--- a/windows/guildsettingswindow.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/snowflake.hpp"
-#include "guildsettings/infopane.hpp"
-#include "guildsettings/banspane.hpp"
-#include "guildsettings/invitespane.hpp"
-#include "guildsettings/auditlogpane.hpp"
-#include "guildsettings/memberspane.hpp"
-#include "guildsettings/rolespane.hpp"
-#include "guildsettings/emojispane.hpp"
-
-class GuildSettingsWindow : public Gtk::Window {
-public:
- GuildSettingsWindow(Snowflake id);
-
-private:
- Gtk::Box m_main;
- Gtk::Stack m_stack;
- Gtk::StackSwitcher m_switcher;
-
- GuildSettingsInfoPane m_pane_info;
- GuildSettingsMembersPane m_pane_members;
- GuildSettingsRolesPane m_pane_roles;
- GuildSettingsBansPane m_pane_bans;
- GuildSettingsInvitesPane m_pane_invites;
- GuildSettingsEmojisPane m_pane_emojis;
- GuildSettingsAuditLogPane m_pane_audit_log;
-
- Snowflake GuildID;
-};
diff --git a/windows/mainwindow.cpp b/windows/mainwindow.cpp
deleted file mode 100644
index 659107a..0000000
--- a/windows/mainwindow.cpp
+++ /dev/null
@@ -1,308 +0,0 @@
-#include "mainwindow.hpp"
-#include "abaddon.hpp"
-
-MainWindow::MainWindow()
- : m_main_box(Gtk::ORIENTATION_VERTICAL)
- , m_content_box(Gtk::ORIENTATION_HORIZONTAL)
- , m_chan_content_paned(Gtk::ORIENTATION_HORIZONTAL)
- , m_content_members_paned(Gtk::ORIENTATION_HORIZONTAL) {
- set_default_size(1200, 800);
- get_style_context()->add_class("app-window");
-
- m_menu_discord.set_label("Discord");
- m_menu_discord.set_submenu(m_menu_discord_sub);
- m_menu_discord_connect.set_label("Connect");
- m_menu_discord_connect.set_sensitive(false);
- m_menu_discord_disconnect.set_label("Disconnect");
- m_menu_discord_disconnect.set_sensitive(false);
- m_menu_discord_set_token.set_label("Set Token");
- m_menu_discord_join_guild.set_label("Accept Invite");
- m_menu_discord_join_guild.set_sensitive(false);
- m_menu_discord_set_status.set_label("Set Status");
- m_menu_discord_set_status.set_sensitive(false);
- m_menu_discord_add_recipient.set_label("Add user to DM");
- m_menu_discord_sub.append(m_menu_discord_connect);
- m_menu_discord_sub.append(m_menu_discord_disconnect);
- m_menu_discord_sub.append(m_menu_discord_set_token);
- m_menu_discord_sub.append(m_menu_discord_join_guild);
- m_menu_discord_sub.append(m_menu_discord_set_status);
- m_menu_discord_sub.append(m_menu_discord_add_recipient);
- m_menu_discord_sub.signal_popped_up().connect(sigc::mem_fun(*this, &MainWindow::OnDiscordSubmenuPopup)); // this gets called twice for some reason
- m_menu_discord.set_submenu(m_menu_discord_sub);
-
- m_menu_file.set_label("File");
- m_menu_file.set_submenu(m_menu_file_sub);
- m_menu_file_reload_css.set_label("Reload CSS");
- m_menu_file_clear_cache.set_label("Clear file cache");
- m_menu_file_sub.append(m_menu_file_reload_css);
- m_menu_file_sub.append(m_menu_file_clear_cache);
-
- m_menu_view.set_label("View");
- 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);
- m_menu_bar.append(m_menu_discord);
- m_menu_bar.append(m_menu_view);
- m_menu_bar.show_all();
-
- m_menu_discord_connect.signal_activate().connect([this] {
- m_signal_action_connect.emit();
- });
-
- m_menu_discord_disconnect.signal_activate().connect([this] {
- m_signal_action_disconnect.emit();
- });
-
- m_menu_discord_set_token.signal_activate().connect([this] {
- m_signal_action_set_token.emit();
- });
-
- m_menu_discord_join_guild.signal_activate().connect([this] {
- m_signal_action_join_guild.emit();
- });
-
- m_menu_file_reload_css.signal_activate().connect([this] {
- m_signal_action_reload_css.emit();
- });
-
- m_menu_discord_set_status.signal_activate().connect([this] {
- m_signal_action_set_status.emit();
- });
-
- m_menu_file_clear_cache.signal_activate().connect([this] {
- Abaddon::Get().GetImageManager().ClearCache();
- });
-
- m_menu_discord_add_recipient.signal_activate().connect([this] {
- m_signal_action_add_recipient.emit(GetChatActiveChannel());
- });
-
- m_menu_view_friends.signal_activate().connect([this] {
- UpdateChatActiveChannel(Snowflake::Invalid);
- m_members.UpdateMemberList();
- m_content_stack.set_visible_child("friends");
- });
-
- m_menu_view_pins.signal_activate().connect([this] {
- 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();
-
- m_main_box.add(m_menu_bar);
- m_main_box.add(m_content_box);
- m_main_box.show();
-
- auto *member_list = m_members.GetRoot();
- auto *chat = m_chat.GetRoot();
-
- chat->set_vexpand(true);
- chat->set_hexpand(true);
- chat->show();
-
- m_channel_list.set_vexpand(true);
- m_channel_list.set_size_request(-1, -1);
- m_channel_list.show();
-
- member_list->set_vexpand(true);
- member_list->show();
-
- m_friends.set_vexpand(true);
- m_friends.set_hexpand(true);
- m_friends.show();
-
- m_content_stack.add(*chat, "chat");
- m_content_stack.add(m_friends, "friends");
- m_content_stack.set_vexpand(true);
- m_content_stack.set_hexpand(true);
- m_content_stack.set_visible_child("chat");
- m_content_stack.show();
-
- m_chan_content_paned.pack1(m_channel_list);
- m_chan_content_paned.pack2(m_content_members_paned);
- m_chan_content_paned.child_property_shrink(m_channel_list) = false;
- m_chan_content_paned.child_property_resize(m_channel_list) = false;
- m_chan_content_paned.set_position(200);
- m_chan_content_paned.show();
- m_content_box.add(m_chan_content_paned);
-
- m_content_members_paned.pack1(m_content_stack);
- m_content_members_paned.pack2(*member_list);
- m_content_members_paned.child_property_shrink(*member_list) = false;
- m_content_members_paned.child_property_resize(*member_list) = false;
- int w, h;
- get_default_size(w, h); // :s
- m_content_members_paned.set_position(w - m_chan_content_paned.get_position() - 150);
- m_content_members_paned.show();
-
- add(m_main_box);
-}
-
-void MainWindow::UpdateComponents() {
- bool discord_active = Abaddon::Get().IsDiscordActive();
-
- if (!discord_active) {
- m_chat.Clear();
- m_members.Clear();
- } else {
- m_members.UpdateMemberList();
- }
- UpdateChannelListing();
-}
-
-void MainWindow::UpdateMembers() {
- m_members.UpdateMemberList();
-}
-
-void MainWindow::UpdateChannelListing() {
- m_channel_list.UpdateListing();
-}
-
-void MainWindow::UpdateChatWindowContents() {
- auto &discord = Abaddon::Get().GetDiscordClient();
- auto msgs = discord.GetMessagesForChannel(m_chat.GetActiveChannel(), 50);
- m_chat.SetMessages(msgs);
- m_members.UpdateMemberList();
-}
-
-void MainWindow::UpdateChatActiveChannel(Snowflake id) {
- m_chat.SetActiveChannel(id);
- m_members.SetActiveChannel(id);
- m_channel_list.SetActiveChannel(id);
- m_content_stack.set_visible_child("chat");
-}
-
-Snowflake MainWindow::GetChatActiveChannel() const {
- return m_chat.GetActiveChannel();
-}
-
-void MainWindow::UpdateChatNewMessage(const Message &data) {
- if (data.ChannelID == GetChatActiveChannel()) {
- m_chat.AddNewMessage(data);
- }
-}
-
-void MainWindow::UpdateChatMessageDeleted(Snowflake id, Snowflake channel_id) {
- if (channel_id == GetChatActiveChannel())
- m_chat.DeleteMessage(id);
-}
-
-void MainWindow::UpdateChatMessageUpdated(Snowflake id, Snowflake channel_id) {
- if (channel_id == GetChatActiveChannel())
- m_chat.UpdateMessage(id);
-}
-
-void MainWindow::UpdateChatPrependHistory(const std::vector<Message> &msgs) {
- m_chat.AddNewHistory(msgs); // given vector should be sorted ascending
-}
-
-void MainWindow::InsertChatInput(std::string text) {
- m_chat.InsertChatInput(text);
-}
-
-Snowflake MainWindow::GetChatOldestListedMessage() {
- return m_chat.GetOldestListedMessage();
-}
-
-void MainWindow::UpdateChatReactionAdd(Snowflake id, const Glib::ustring &param) {
- m_chat.UpdateReactions(id);
-}
-
-void MainWindow::UpdateChatReactionRemove(Snowflake id, const Glib::ustring &param) {
- m_chat.UpdateReactions(id);
-}
-
-void MainWindow::OnDiscordSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- auto channel_id = GetChatActiveChannel();
- m_menu_discord_add_recipient.set_visible(false);
- if (channel_id.IsValid()) {
- auto channel = discord.GetChannel(channel_id);
- if (channel.has_value() && channel->GetDMRecipients().size() + 1 < 10)
- m_menu_discord_add_recipient.set_visible(channel->Type == ChannelType::GROUP_DM);
- }
-
- const bool discord_active = Abaddon::Get().GetDiscordClient().IsStarted();
-
- std::string token = Abaddon::Get().GetDiscordToken();
- m_menu_discord_connect.set_sensitive(token.size() > 0 && !discord_active);
- m_menu_discord_disconnect.set_sensitive(discord_active);
- m_menu_discord_join_guild.set_sensitive(discord_active);
- m_menu_discord_set_token.set_sensitive(!discord_active);
- m_menu_discord_set_status.set_sensitive(discord_active);
-}
-
-void MainWindow::OnViewSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y) {
- m_menu_view_friends.set_sensitive(Abaddon::Get().GetDiscordClient().IsStarted());
- auto channel_id = GetChatActiveChannel();
- m_menu_view_pins.set_sensitive(false);
- m_menu_view_threads.set_sensitive(false);
- if (channel_id.IsValid()) {
- auto channel = Abaddon::Get().GetDiscordClient().GetChannel(channel_id);
- if (channel.has_value()) {
- m_menu_view_threads.set_sensitive(channel->Type == ChannelType::GUILD_TEXT || channel->IsThread());
- m_menu_view_pins.set_sensitive(channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM || channel->IsThread());
- }
- }
-}
-
-ChannelList *MainWindow::GetChannelList() {
- return &m_channel_list;
-}
-
-ChatWindow *MainWindow::GetChatWindow() {
- return &m_chat;
-}
-
-MemberList *MainWindow::GetMemberList() {
- return &m_members;
-}
-
-MainWindow::type_signal_action_connect MainWindow::signal_action_connect() {
- return m_signal_action_connect;
-}
-
-MainWindow::type_signal_action_disconnect MainWindow::signal_action_disconnect() {
- return m_signal_action_disconnect;
-}
-
-MainWindow::type_signal_action_set_token MainWindow::signal_action_set_token() {
- return m_signal_action_set_token;
-}
-
-MainWindow::type_signal_action_reload_css MainWindow::signal_action_reload_css() {
- return m_signal_action_reload_css;
-}
-
-MainWindow::type_signal_action_join_guild MainWindow::signal_action_join_guild() {
- return m_signal_action_join_guild;
-}
-
-MainWindow::type_signal_action_set_status MainWindow::signal_action_set_status() {
- return m_signal_action_set_status;
-}
-
-MainWindow::type_signal_action_add_recipient MainWindow::signal_action_add_recipient() {
- return m_signal_action_add_recipient;
-}
-
-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
deleted file mode 100644
index df1c968..0000000
--- a/windows/mainwindow.hpp
+++ /dev/null
@@ -1,99 +0,0 @@
-#pragma once
-#include "components/channels.hpp"
-#include "components/chatwindow.hpp"
-#include "components/memberlist.hpp"
-#include "components/friendslist.hpp"
-#include <gtkmm.h>
-
-class MainWindow : public Gtk::Window {
-public:
- MainWindow();
-
- void UpdateComponents();
- void UpdateMembers();
- void UpdateChannelListing();
- void UpdateChatWindowContents();
- void UpdateChatActiveChannel(Snowflake id);
- Snowflake GetChatActiveChannel() const;
- void UpdateChatNewMessage(const Message &data);
- void UpdateChatMessageDeleted(Snowflake id, Snowflake channel_id);
- void UpdateChatMessageUpdated(Snowflake id, Snowflake channel_id);
- void UpdateChatPrependHistory(const std::vector<Message> &msgs);
- void InsertChatInput(std::string text);
- Snowflake GetChatOldestListedMessage();
- void UpdateChatReactionAdd(Snowflake id, const Glib::ustring &param);
- void UpdateChatReactionRemove(Snowflake id, const Glib::ustring &param);
-
- ChannelList *GetChannelList();
- ChatWindow *GetChatWindow();
- MemberList *GetMemberList();
-
-public:
- typedef sigc::signal<void> type_signal_action_connect;
- typedef sigc::signal<void> type_signal_action_disconnect;
- typedef sigc::signal<void> type_signal_action_set_token;
- typedef sigc::signal<void> type_signal_action_reload_css;
- typedef sigc::signal<void> type_signal_action_join_guild;
- typedef sigc::signal<void> type_signal_action_set_status;
- // this should probably be removed
- typedef sigc::signal<void, Snowflake> type_signal_action_add_recipient; // channel id
- typedef sigc::signal<void, Snowflake> type_signal_action_view_pins; // channel id
- typedef sigc::signal<void, Snowflake> type_signal_action_view_threads; // channel id
-
- type_signal_action_connect signal_action_connect();
- type_signal_action_disconnect signal_action_disconnect();
- type_signal_action_set_token signal_action_set_token();
- type_signal_action_reload_css signal_action_reload_css();
- type_signal_action_join_guild signal_action_join_guild();
- 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;
- type_signal_action_disconnect m_signal_action_disconnect;
- type_signal_action_set_token m_signal_action_set_token;
- type_signal_action_reload_css m_signal_action_reload_css;
- type_signal_action_join_guild m_signal_action_join_guild;
- 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;
- Gtk::Box m_content_box;
- Gtk::Paned m_chan_content_paned;
- Gtk::Paned m_content_members_paned;
-
- ChannelList m_channel_list;
- ChatWindow m_chat;
- MemberList m_members;
- FriendsList m_friends;
-
- Gtk::Stack m_content_stack;
-
- Gtk::MenuBar m_menu_bar;
- Gtk::MenuItem m_menu_discord;
- Gtk::Menu m_menu_discord_sub;
- Gtk::MenuItem m_menu_discord_connect;
- Gtk::MenuItem m_menu_discord_disconnect;
- Gtk::MenuItem m_menu_discord_set_token;
- Gtk::MenuItem m_menu_discord_join_guild;
- Gtk::MenuItem m_menu_discord_set_status;
- Gtk::MenuItem m_menu_discord_add_recipient; // move me somewhere else some day
- void OnDiscordSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y);
-
- Gtk::MenuItem m_menu_file;
- Gtk::Menu m_menu_file_sub;
- Gtk::MenuItem m_menu_file_reload_css;
- Gtk::MenuItem m_menu_file_clear_cache;
-
- Gtk::MenuItem m_menu_view;
- 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);
-};
diff --git a/windows/pinnedwindow.cpp b/windows/pinnedwindow.cpp
deleted file mode 100644
index a5484e3..0000000
--- a/windows/pinnedwindow.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#include "pinnedwindow.hpp"
-#include "abaddon.hpp"
-
-PinnedWindow::PinnedWindow(const ChannelData &data)
- : ChannelID(data.ID) {
- if (data.GuildID.has_value())
- GuildID = *data.GuildID;
-
- set_name("pinned-messages");
- set_default_size(450, 375);
- if (data.Name.has_value())
- set_title("#" + *data.Name + " - Pinned Messages");
- else
- set_title("Pinned Messages");
- set_position(Gtk::WIN_POS_CENTER);
- get_style_context()->add_class("app-window");
- get_style_context()->add_class("app-popup");
- get_style_context()->add_class("pinned-messages-window");
-
- add(m_chat);
- m_chat.show();
-
- m_chat.SetSeparateAll(true);
- m_chat.SetActiveChannel(ChannelID);
- m_chat.SetUsePinnedMenu();
-
- Abaddon::Get().GetDiscordClient().signal_message_pinned().connect(sigc::mem_fun(*this, &PinnedWindow::OnMessagePinned));
- Abaddon::Get().GetDiscordClient().signal_message_unpinned().connect(sigc::mem_fun(*this, &PinnedWindow::OnMessageUnpinned));
- FetchPinned();
-}
-
-void PinnedWindow::OnMessagePinned(const Message &msg) {
- FetchPinned();
-}
-
-void PinnedWindow::OnMessageUnpinned(const Message &msg) {
- m_chat.ActuallyRemoveMessage(msg.ID);
-}
-
-void PinnedWindow::FetchPinned() {
- Abaddon::Get().GetDiscordClient().FetchPinned(ChannelID, sigc::mem_fun(*this, &PinnedWindow::OnFetchedPinned));
-}
-
-void PinnedWindow::OnFetchedPinned(const std::vector<Message> &msgs, DiscordError code) {
- if (code != DiscordError::NONE) return;
- m_chat.SetMessages(msgs.begin(), msgs.end());
-}
diff --git a/windows/pinnedwindow.hpp b/windows/pinnedwindow.hpp
deleted file mode 100644
index cf2ec3c..0000000
--- a/windows/pinnedwindow.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/errors.hpp"
-#include "discord/channel.hpp"
-#include "discord/message.hpp"
-#include "components/chatlist.hpp"
-
-class PinnedWindow : public Gtk::Window {
-public:
- PinnedWindow(const ChannelData &data);
-
- Snowflake GuildID;
- Snowflake ChannelID;
-
-private:
- void OnMessagePinned(const Message &msg);
- void OnMessageUnpinned(const Message &msg);
- void FetchPinned();
- void OnFetchedPinned(const std::vector<Message> &msgs, DiscordError code);
-
- ChatList m_chat;
-};
diff --git a/windows/profile/mutualfriendspane.cpp b/windows/profile/mutualfriendspane.cpp
deleted file mode 100644
index 339fd71..0000000
--- a/windows/profile/mutualfriendspane.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "mutualfriendspane.hpp"
-#include "abaddon.hpp"
-
-MutualFriendItem::MutualFriendItem(const UserData &user)
- : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) {
- get_style_context()->add_class("mutual-friend-item");
- m_name.get_style_context()->add_class("mutual-friend-item-name");
- m_avatar.get_style_context()->add_class("mutual-friend-item-avatar");
-
- m_avatar.set_margin_end(10);
-
- const auto show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
- auto &img = Abaddon::Get().GetImageManager();
- m_avatar.property_pixbuf() = img.GetPlaceholder(24);
- if (user.HasAnimatedAvatar() && show_animations) {
- auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
- m_avatar.property_pixbuf_animation() = pb;
- };
- img.LoadAnimationFromURL(user.GetAvatarURL("gif", "32"), 24, 24, sigc::track_obj(cb, *this));
- } else {
- auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
- m_avatar.property_pixbuf() = pb->scale_simple(24, 24, Gdk::INTERP_BILINEAR);
- };
- img.LoadFromURL(user.GetAvatarURL("png", "32"), sigc::track_obj(cb, *this));
- }
-
- m_name.set_markup(user.GetEscapedBoldString<false>());
-
- m_name.set_valign(Gtk::ALIGN_CENTER);
- add(m_avatar);
- add(m_name);
- show_all_children();
-}
-
-MutualFriendsPane::MutualFriendsPane(Snowflake id)
- : UserID(id) {
- signal_map().connect(sigc::mem_fun(*this, &MutualFriendsPane::OnMap));
- add(m_list);
- show_all_children();
-}
-
-void MutualFriendsPane::OnFetchRelationships(const std::vector<UserData> &users) {
- for (auto child : m_list.get_children())
- delete child;
-
- for (const auto &user : users) {
- auto *item = Gtk::manage(new MutualFriendItem(user));
- item->show();
- m_list.add(*item);
- }
-}
-
-void MutualFriendsPane::OnMap() {
- if (m_requested) return;
- m_requested = true;
-
- Abaddon::Get().GetDiscordClient().FetchUserRelationships(UserID, sigc::mem_fun(*this, &MutualFriendsPane::OnFetchRelationships));
-}
diff --git a/windows/profile/mutualfriendspane.hpp b/windows/profile/mutualfriendspane.hpp
deleted file mode 100644
index ef41aa6..0000000
--- a/windows/profile/mutualfriendspane.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/objects.hpp"
-
-class MutualFriendItem : public Gtk::Box {
-public:
- MutualFriendItem(const UserData &user);
-
-private:
- Gtk::Image m_avatar;
- Gtk::Label m_name;
-};
-
-class MutualFriendsPane : public Gtk::ScrolledWindow {
-public:
- MutualFriendsPane(Snowflake id);
-
- Snowflake UserID;
-
-private:
- void OnMap();
-
- bool m_requested = false;
-
- void OnFetchRelationships(const std::vector<UserData> &users);
-
- Gtk::ListBox m_list;
-};
diff --git a/windows/profile/mutualguildspane.cpp b/windows/profile/mutualguildspane.cpp
deleted file mode 100644
index 6bfdc7b..0000000
--- a/windows/profile/mutualguildspane.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-#include "mutualguildspane.hpp"
-#include "abaddon.hpp"
-
-MutualGuildItem::MutualGuildItem(const MutualGuildData &guild)
- : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)
- , m_box(Gtk::ORIENTATION_VERTICAL) {
- get_style_context()->add_class("mutual-guild-item");
- m_name.get_style_context()->add_class("mutual-guild-item-name");
- m_icon.get_style_context()->add_class("mutual-guild-item-icon");
-
- m_icon.set_margin_end(10);
-
- // discord will return info (id + nick) for "deleted" guilds from this endpoint. strange !
- const auto data = Abaddon::Get().GetDiscordClient().GetGuild(guild.ID);
- if (data.has_value()) {
- const auto show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
- auto &img = Abaddon::Get().GetImageManager();
- m_icon.property_pixbuf() = img.GetPlaceholder(24);
- if (data->HasIcon()) {
- if (data->HasAnimatedIcon() && show_animations) {
- auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
- m_icon.property_pixbuf_animation() = pb;
- };
- img.LoadAnimationFromURL(data->GetIconURL("gif", "32"), 24, 24, sigc::track_obj(cb, *this));
- } else {
- auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
- m_icon.property_pixbuf() = pb->scale_simple(24, 24, Gdk::INTERP_BILINEAR);
- };
- img.LoadFromURL(data->GetIconURL("png", "32"), sigc::track_obj(cb, *this));
- }
- }
-
- m_name.set_markup("<b>" + Glib::Markup::escape_text(data->Name) + "</b>");
- } else {
- m_icon.property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(24);
- m_name.set_markup("<b>Unknown server</b>");
- }
-
- if (guild.Nick.has_value()) {
- m_nick = Gtk::manage(new Gtk::Label(*guild.Nick));
- m_nick->get_style_context()->add_class("mutual-guild-item-nick");
- m_nick->set_margin_start(5);
- m_nick->set_halign(Gtk::ALIGN_START);
- m_nick->set_single_line_mode(true);
- m_nick->set_ellipsize(Pango::ELLIPSIZE_END);
- }
-
- m_box.set_valign(Gtk::ALIGN_CENTER);
-
- m_box.add(m_name);
- if (m_nick != nullptr)
- m_box.add(*m_nick);
- add(m_icon);
- add(m_box);
- show_all_children();
-}
-
-UserMutualGuildsPane::UserMutualGuildsPane(Snowflake id)
- : UserID(id) {
- add(m_list);
- show_all_children();
-}
-
-void UserMutualGuildsPane::SetMutualGuilds(const std::vector<MutualGuildData> &guilds) {
- for (auto child : m_list.get_children())
- delete child;
-
- for (const auto &guild : guilds) {
- auto *item = Gtk::manage(new MutualGuildItem(guild));
- item->show();
- m_list.add(*item);
- }
-}
diff --git a/windows/profile/mutualguildspane.hpp b/windows/profile/mutualguildspane.hpp
deleted file mode 100644
index 9bdd97e..0000000
--- a/windows/profile/mutualguildspane.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/objects.hpp"
-
-class MutualGuildItem : public Gtk::Box {
-public:
- MutualGuildItem(const MutualGuildData &guild);
-
-private:
- Gtk::Image m_icon;
- Gtk::Box m_box;
- Gtk::Label m_name;
- Gtk::Label *m_nick = nullptr;
-};
-
-class UserMutualGuildsPane : public Gtk::ScrolledWindow {
-public:
- UserMutualGuildsPane(Snowflake id);
-
- void SetMutualGuilds(const std::vector<MutualGuildData> &guilds);
-
- Snowflake UserID;
-
-private:
- Gtk::ListBox m_list;
-};
diff --git a/windows/profile/userinfopane.cpp b/windows/profile/userinfopane.cpp
deleted file mode 100644
index a95a14c..0000000
--- a/windows/profile/userinfopane.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-#include "userinfopane.hpp"
-#include <unordered_set>
-#include "abaddon.hpp"
-
-ConnectionItem::ConnectionItem(const ConnectionData &conn)
- : m_box(Gtk::ORIENTATION_HORIZONTAL)
- , m_name(conn.Name) {
- Glib::RefPtr<Gdk::Pixbuf> pixbuf;
- try {
- pixbuf = Gdk::Pixbuf::create_from_file(Abaddon::GetResPath("/" + conn.Type + ".png"), 32, 32);
- } catch (const Glib::Exception &e) {}
- std::string url;
- if (conn.Type == "github")
- url = "https://github.com/" + conn.Name;
- else if (conn.Type == "steam")
- url = "https://steamcommunity.com/profiles/" + conn.ID;
- else if (conn.Type == "twitch")
- url = "https://twitch.tv/" + conn.Name;
- else if (conn.Type == "twitter")
- url = "https://twitter.com/i/user/" + conn.ID;
- else if (conn.Type == "spotify")
- url = "https://open.spotify.com/user/" + conn.ID;
- else if (conn.Type == "reddit")
- url = "https://reddit.com/u/" + conn.Name;
- else if (conn.Type == "youtube")
- url = "https://www.youtube.com/channel/" + conn.ID;
- else if (conn.Type == "facebook")
- url = "https://www.facebook.com/" + conn.ID;
- if (pixbuf) {
- m_image = Gtk::manage(new Gtk::Image(pixbuf));
- m_image->get_style_context()->add_class("profile-connection-image");
- m_box.add(*m_image);
- }
- m_box.set_halign(Gtk::ALIGN_START);
- m_box.set_size_request(200, -1);
- m_box.get_style_context()->add_class("profile-connection");
- m_name.get_style_context()->add_class("profile-connection-label");
- m_name.set_valign(Gtk::ALIGN_CENTER);
- m_name.set_single_line_mode(true);
- m_name.set_ellipsize(Pango::ELLIPSIZE_END);
- m_box.add(m_name);
- if (url != "") {
- auto cb = [this, url](GdkEventButton *event) -> bool {
- if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) {
- LaunchBrowser(url);
- return true;
- }
- return false;
- };
- signal_button_press_event().connect(sigc::track_obj(cb, *this));
- AddPointerCursor(*this);
- }
- m_overlay.add(m_box);
- if (conn.IsVerified) {
- try {
- const static auto checkmarks_path = Abaddon::GetResPath("/checkmark.png");
- static auto pb = Gdk::Pixbuf::create_from_file(checkmarks_path, 24, 24);
- m_check = Gtk::manage(new Gtk::Image(pb));
- m_check->get_style_context()->add_class("profile-connection-check");
- m_check->set_margin_end(25);
- m_check->set_valign(Gtk::ALIGN_CENTER);
- m_check->set_halign(Gtk::ALIGN_END);
- m_check->show();
- m_overlay.add_overlay(*m_check);
- } catch (const Glib::Exception &e) {}
- }
- m_overlay.set_hexpand(false);
- m_overlay.set_halign(Gtk::ALIGN_START);
- add(m_overlay);
- show_all_children();
-}
-
-ConnectionsContainer::ConnectionsContainer() {
- get_style_context()->add_class("profile-connections");
- set_column_homogeneous(true);
- set_row_spacing(10);
- set_column_spacing(10);
- show_all_children();
-}
-
-void ConnectionsContainer::SetConnections(const std::vector<ConnectionData> &connections) {
- for (auto child : get_children())
- delete child;
-
- static const std::unordered_set<std::string> supported_services = {
- "battlenet",
- "github",
- "leagueoflegends",
- "reddit",
- "skype",
- "spotify",
- "steam",
- "twitch",
- "twitter",
- "xbox",
- "youtube",
- "facebook"
- };
-
- for (size_t i = 0; i < connections.size(); i++) {
- const auto &conn = connections[i];
- if (supported_services.find(conn.Type) == supported_services.end()) continue;
- auto widget = Gtk::manage(new ConnectionItem(conn));
- widget->show();
- attach(*widget, i % 2, i / 2, 1, 1);
- }
-
- set_halign(Gtk::ALIGN_FILL);
- set_hexpand(true);
-}
-
-NotesContainer::NotesContainer()
- : Gtk::Box(Gtk::ORIENTATION_VERTICAL) {
- get_style_context()->add_class("profile-notes");
- m_label.get_style_context()->add_class("profile-notes-label");
- m_note.get_style_context()->add_class("profile-notes-text");
-
- m_label.set_markup("<b>NOTE</b>");
- m_label.set_halign(Gtk::ALIGN_START);
-
- m_note.set_wrap_mode(Gtk::WRAP_WORD_CHAR);
- m_note.signal_key_press_event().connect(sigc::mem_fun(*this, &NotesContainer::OnNoteKeyPress), false);
-
- add(m_label);
- add(m_note);
- show_all_children();
-}
-
-void NotesContainer::SetNote(const std::string &note) {
- m_note.get_buffer()->set_text(note);
-}
-
-void NotesContainer::UpdateNote() {
- auto text = m_note.get_buffer()->get_text();
- if (text.size() > 256)
- text = text.substr(0, 256);
- m_signal_update_note.emit(text);
-}
-
-bool NotesContainer::OnNoteKeyPress(GdkEventKey *event) {
- if (event->type != GDK_KEY_PRESS) return false;
- const auto text = m_note.get_buffer()->get_text();
- if (event->keyval == GDK_KEY_Return) {
- if (event->state & GDK_SHIFT_MASK) {
- int newlines = 0;
- for (const auto c : text)
- if (c == '\n') newlines++;
- return newlines >= 5;
- } else {
- UpdateNote();
- return true;
- }
- }
-
- return false;
-}
-
-NotesContainer::type_signal_update_note NotesContainer::signal_update_note() {
- return m_signal_update_note;
-}
-
-BioContainer::BioContainer()
- : Gtk::Box(Gtk::ORIENTATION_VERTICAL) {
- m_label.set_markup("<b>ABOUT ME</b>");
- m_label.set_halign(Gtk::ALIGN_START);
- m_bio.set_halign(Gtk::ALIGN_START);
- m_bio.set_line_wrap(true);
- m_bio.set_line_wrap_mode(Pango::WRAP_WORD_CHAR);
-
- m_label.show();
- m_bio.show();
-
- add(m_label);
- add(m_bio);
-}
-
-void BioContainer::SetBio(const std::string &bio) {
- m_bio.set_text(bio);
-}
-
-ProfileUserInfoPane::ProfileUserInfoPane(Snowflake ID)
- : Gtk::Box(Gtk::ORIENTATION_VERTICAL)
- , UserID(ID) {
- get_style_context()->add_class("profile-info-pane");
- m_created.get_style_context()->add_class("profile-info-created");
-
- m_note.signal_update_note().connect([this](const Glib::ustring &note) {
- auto cb = [this](DiscordError code) {
- if (code != DiscordError::NONE) {
- Gtk::MessageDialog dlg("Failed to set note", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- dlg.set_position(Gtk::WIN_POS_CENTER);
- dlg.run();
- }
- };
- Abaddon::Get().GetDiscordClient().SetUserNote(UserID, note, sigc::track_obj(cb, *this));
- });
-
- auto &discord = Abaddon::Get().GetDiscordClient();
- auto note_update_cb = [this](Snowflake id, std::string note) {
- if (id == UserID)
- m_note.SetNote(note);
- };
- discord.signal_note_update().connect(sigc::track_obj(note_update_cb, m_note));
-
- auto fetch_note_cb = [this](const std::string &note) {
- m_note.SetNote(note);
- };
- discord.FetchUserNote(UserID, sigc::track_obj(fetch_note_cb, *this));
-
- m_created.set_halign(Gtk::ALIGN_START);
- m_created.set_margin_top(5);
- m_created.set_text("Account created: " + ID.GetLocalTimestamp());
-
- m_conns.set_halign(Gtk::ALIGN_START);
- m_conns.set_hexpand(true);
-
- m_created.show();
- m_note.show();
- m_conns.show();
-
- add(m_created);
- add(m_bio);
- add(m_note);
- add(m_conns);
-}
-
-void ProfileUserInfoPane::SetProfile(const UserProfileData &data) {
- if (data.User.Bio.has_value() && *data.User.Bio != "") {
- m_bio.SetBio(*data.User.Bio);
- m_bio.show();
- } else {
- m_bio.hide();
- }
-
- m_conns.SetConnections(data.ConnectedAccounts);
-}
diff --git a/windows/profile/userinfopane.hpp b/windows/profile/userinfopane.hpp
deleted file mode 100644
index 90a4d55..0000000
--- a/windows/profile/userinfopane.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/objects.hpp"
-
-class ConnectionItem : public Gtk::EventBox {
-public:
- ConnectionItem(const ConnectionData &connection);
-
-private:
- Gtk::Overlay m_overlay;
- Gtk::Box m_box;
- Gtk::Label m_name;
- Gtk::Image *m_image = nullptr;
- Gtk::Image *m_check = nullptr;
-};
-
-class ConnectionsContainer : public Gtk::Grid {
-public:
- ConnectionsContainer();
- void SetConnections(const std::vector<ConnectionData> &connections);
-};
-
-class NotesContainer : public Gtk::Box {
-public:
- NotesContainer();
- void SetNote(const std::string &note);
-
-private:
- void UpdateNote();
- bool OnNoteKeyPress(GdkEventKey *event);
-
- Gtk::Label m_label;
- Gtk::TextView m_note;
-
- typedef sigc::signal<void, Glib::ustring> type_signal_update_note;
- type_signal_update_note m_signal_update_note;
-
-public:
- type_signal_update_note signal_update_note();
-};
-
-class BioContainer : public Gtk::Box {
-public:
- BioContainer();
- void SetBio(const std::string &bio);
-
-private:
- Gtk::Label m_label;
- Gtk::Label m_bio;
-};
-
-class ProfileUserInfoPane : public Gtk::Box {
-public:
- ProfileUserInfoPane(Snowflake ID);
- void SetProfile(const UserProfileData &data);
-
- Snowflake UserID;
-
-private:
- Gtk::Label m_created;
-
- BioContainer m_bio;
- NotesContainer m_note;
- ConnectionsContainer m_conns;
-};
diff --git a/windows/profilewindow.cpp b/windows/profilewindow.cpp
deleted file mode 100644
index 4d41f89..0000000
--- a/windows/profilewindow.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-#include "profilewindow.hpp"
-#include "abaddon.hpp"
-
-ProfileWindow::ProfileWindow(Snowflake user_id)
- : ID(user_id)
- , m_main(Gtk::ORIENTATION_VERTICAL)
- , m_upper(Gtk::ORIENTATION_HORIZONTAL)
- , m_badges(Gtk::ORIENTATION_HORIZONTAL)
- , m_pane_info(user_id)
- , m_pane_guilds(user_id)
- , m_pane_friends(user_id) {
- auto &discord = Abaddon::Get().GetDiscordClient();
- auto user = *discord.GetUser(ID);
-
- discord.FetchUserProfile(user_id, sigc::mem_fun(*this, &ProfileWindow::OnFetchProfile));
-
- set_name("user-profile");
- set_default_size(450, 375);
- set_title(user.Username + "#" + user.Discriminator);
- set_position(Gtk::WIN_POS_CENTER);
- get_style_context()->add_class("app-window");
- get_style_context()->add_class("app-popup");
- get_style_context()->add_class("user-profile-window");
- m_main.get_style_context()->add_class("profile-main-container");
- m_avatar.get_style_context()->add_class("profile-avatar");
- m_username.get_style_context()->add_class("profile-username");
- m_switcher.get_style_context()->add_class("profile-switcher");
- m_stack.get_style_context()->add_class("profile-stack");
- m_badges.get_style_context()->add_class("profile-badges");
-
- m_scroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
- m_scroll.set_vexpand(true);
- m_scroll.set_propagate_natural_height(true);
-
- if (user.HasAvatar())
- AddPointerCursor(m_avatar_ev);
- m_avatar_ev.signal_button_press_event().connect([this, user](GdkEventButton *event) -> bool {
- if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) {
- if (user.HasAnimatedAvatar())
- LaunchBrowser(user.GetAvatarURL("gif", "512"));
- else
- LaunchBrowser(user.GetAvatarURL("png", "512"));
- }
- return false;
- });
-
- static const bool show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
- auto &img = Abaddon::Get().GetImageManager();
- m_avatar.property_pixbuf() = img.GetPlaceholder(64);
- auto icon_cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
- set_icon(pb);
- };
- img.LoadFromURL(user.GetAvatarURL("png", "64"), sigc::track_obj(icon_cb, *this));
-
- if (show_animations && user.HasAnimatedAvatar()) {
- auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
- m_avatar.property_pixbuf_animation() = pb;
- };
- img.LoadAnimationFromURL(user.GetAvatarURL("gif", "64"), 64, 64, sigc::track_obj(cb, *this));
- } else {
- auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
- m_avatar.property_pixbuf() = pb->scale_simple(64, 64, Gdk::INTERP_BILINEAR);
- };
- img.LoadFromURL(user.GetAvatarURL("png", "64"), sigc::track_obj(cb, *this));
- }
-
- m_username.set_markup(user.GetEscapedString());
-
- m_switcher.set_stack(m_stack);
- m_switcher.set_halign(Gtk::ALIGN_START);
- m_switcher.set_hexpand(true);
-
- m_stack.add(m_pane_info, "info", "User Info");
- m_stack.add(m_pane_guilds, "guilds", "Mutual Servers");
- m_stack.add(m_pane_friends, "friends", "Mutual Friends");
-
- m_badges.set_valign(Gtk::ALIGN_CENTER);
- m_badges_scroll.set_hexpand(true);
- m_badges_scroll.set_propagate_natural_width(true);
- m_badges_scroll.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_NEVER);
-
- m_upper.set_halign(Gtk::ALIGN_START);
- m_avatar.set_halign(Gtk::ALIGN_START);
- m_username.set_halign(Gtk::ALIGN_START);
- m_avatar_ev.add(m_avatar);
- m_upper.add(m_avatar_ev);
- m_upper.add(m_username);
- m_badges_scroll.add(m_badges);
- m_upper.add(m_badges_scroll);
- m_main.add(m_upper);
- m_main.add(m_switcher);
- m_scroll.add(m_stack);
- m_main.add(m_scroll);
- add(m_main);
- show_all_children();
-}
-
-void ProfileWindow::OnFetchProfile(const UserProfileData &data) {
- m_pane_info.SetProfile(data);
- m_pane_guilds.SetMutualGuilds(data.MutualGuilds);
-
- for (auto child : m_badges.get_children())
- delete child;
-
- if (!data.User.PublicFlags.has_value()) return;
- const auto x = *data.User.PublicFlags;
- for (uint64_t i = 1; i <= UserData::MaxFlag; i <<= 1) {
- if (!(x & i)) continue;
- const std::string name = UserData::GetFlagName(i);
- if (name == "unknown") continue;
- Glib::RefPtr<Gdk::Pixbuf> pixbuf;
- try {
- if (name == "verifiedbot")
- pixbuf = Gdk::Pixbuf::create_from_file(Abaddon::GetResPath("/checkmark.png"), 24, 24);
- else
- pixbuf = Gdk::Pixbuf::create_from_file(Abaddon::GetResPath("/" + name + ".png"), 24, 24);
- } catch (const Glib::Exception &e) {
- pixbuf = Abaddon::Get().GetImageManager().GetPlaceholder(24);
- }
- if (!pixbuf) continue;
- auto *image = Gtk::manage(new Gtk::Image(pixbuf));
- image->get_style_context()->add_class("profile-badge");
- image->set_tooltip_text(UserData::GetFlagReadableName(i));
- image->show();
- m_badges.add(*image);
- }
-}
diff --git a/windows/profilewindow.hpp b/windows/profilewindow.hpp
deleted file mode 100644
index 3d8199b..0000000
--- a/windows/profilewindow.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/snowflake.hpp"
-#include "profile/userinfopane.hpp"
-#include "profile/mutualguildspane.hpp"
-#include "profile/mutualfriendspane.hpp"
-
-class ProfileWindow : public Gtk::Window {
-public:
- ProfileWindow(Snowflake user_id);
-
- Snowflake ID;
-
-private:
- void OnFetchProfile(const UserProfileData &data);
-
- Gtk::Box m_main;
- Gtk::Box m_upper;
- Gtk::Box m_badges;
- Gtk::ScrolledWindow m_badges_scroll;
- Gtk::EventBox m_avatar_ev;
- Gtk::Image m_avatar;
- Gtk::Label m_username;
- Gtk::ScrolledWindow m_scroll;
- Gtk::Stack m_stack;
- Gtk::StackSwitcher m_switcher;
-
- ProfileUserInfoPane m_pane_info;
- UserMutualGuildsPane m_pane_guilds;
- MutualFriendsPane m_pane_friends;
-};
diff --git a/windows/threadswindow.cpp b/windows/threadswindow.cpp
deleted file mode 100644
index 9071d81..0000000
--- a/windows/threadswindow.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "threadswindow.hpp"
-#include "abaddon.hpp"
-
-ThreadsWindow::ThreadsWindow(const ChannelData &channel)
- : m_channel_id(channel.ID)
- , m_filter_public(m_group, "Public")
- , m_filter_private(m_group, "Private")
- , m_box(Gtk::ORIENTATION_VERTICAL)
- , m_active(channel, sigc::mem_fun(*this, &ThreadsWindow::ListFilterFunc))
- , m_archived(channel, sigc::mem_fun(*this, &ThreadsWindow::ListFilterFunc)) {
- set_name("threads-window");
- set_default_size(450, 375);
- set_title("#" + *channel.Name + " - Threads");
- set_position(Gtk::WIN_POS_CENTER);
- get_style_context()->add_class("app-window");
- get_style_context()->add_class("app-popup");
- get_style_context()->add_class("threads-window");
-
- const auto cb = [this](Snowflake id) {
- Abaddon::Get().ActionChannelOpened(id);
- hide();
- };
- m_active.signal_thread_open().connect(cb);
- m_archived.signal_thread_open().connect(cb);
-
- m_switcher.set_halign(Gtk::ALIGN_CENTER);
- m_switcher.set_stack(m_stack);
-
- m_stack.add(m_active, "active", "Active Threads");
- m_stack.add(m_archived, "archived", "Archived Threads");
-
- m_filter_buttons.set_homogeneous(true);
- m_filter_buttons.set_halign(Gtk::ALIGN_CENTER);
- m_filter_buttons.add(m_filter_public);
- m_filter_buttons.add(m_filter_private);
-
- // a little strange
- const auto btncb = [this](Gtk::RadioButton *btn) {
- if (btn->get_active()) {
- if (btn == &m_filter_public)
- m_filter_mode = FILTER_PUBLIC;
- else if (btn == &m_filter_private)
- m_filter_mode = FILTER_PRIVATE;
-
- m_active.InvalidateFilter();
- m_archived.InvalidateFilter();
- }
- };
- m_filter_public.signal_toggled().connect(sigc::bind(btncb, &m_filter_public));
- m_filter_private.signal_toggled().connect(sigc::bind(btncb, &m_filter_private));
-
- m_active.show();
- m_archived.show();
- m_switcher.show();
- m_filter_buttons.show_all();
- m_stack.show();
- m_box.show();
-
- m_box.add(m_switcher);
- m_box.add(m_filter_buttons);
- m_box.add(m_stack);
- add(m_box);
-}
-
-bool ThreadsWindow::ListFilterFunc(Gtk::ListBoxRow *row_) {
- if (auto *row = dynamic_cast<ThreadListRow *>(row_))
- return (m_filter_mode == FILTER_PUBLIC && (row->Type == ChannelType::GUILD_PUBLIC_THREAD || row->Type == ChannelType::GUILD_NEWS_THREAD)) ||
- (m_filter_mode == FILTER_PRIVATE && row->Type == ChannelType::GUILD_PRIVATE_THREAD);
- return false;
-}
-
-ThreadListRow::ThreadListRow(const ChannelData &channel)
- : ID(channel.ID)
- , Type(channel.Type)
- , m_label(*channel.Name, Gtk::ALIGN_START) {
- m_label.show();
- add(m_label);
-}
-
-ActiveThreadsList::ActiveThreadsList(const ChannelData &channel, const Gtk::ListBox::SlotFilter &filter) {
- set_vexpand(true);
-
- m_list.set_filter_func(filter);
- m_list.set_selection_mode(Gtk::SELECTION_SINGLE);
- m_list.set_hexpand(true);
- m_list.show();
-
- add(m_list);
-
- m_list.signal_button_press_event().connect([this](GdkEventButton *ev) -> bool {
- if (ev->button == GDK_BUTTON_PRIMARY && ev->type == GDK_2BUTTON_PRESS) {
- if (auto row = dynamic_cast<ThreadListRow *>(m_list.get_selected_row()))
- m_signal_thread_open.emit(row->ID);
- }
- return false;
- });
-
- const auto threads = Abaddon::Get().GetDiscordClient().GetActiveThreads(channel.ID);
- for (const auto &thread : threads) {
- auto row = Gtk::manage(new ThreadListRow(thread));
- row->show();
- m_list.add(*row);
- }
-}
-
-void ActiveThreadsList::InvalidateFilter() {
- m_list.invalidate_filter();
-}
-
-ActiveThreadsList::type_signal_thread_open ActiveThreadsList::signal_thread_open() {
- return m_signal_thread_open;
-}
-
-ArchivedThreadsList::ArchivedThreadsList(const ChannelData &channel, const Gtk::ListBox::SlotFilter &filter) {
- set_vexpand(true);
-
- m_list.set_filter_func(filter);
- m_list.set_selection_mode(Gtk::SELECTION_SINGLE);
- m_list.set_hexpand(true);
- m_list.show();
-
- add(m_list);
-
- m_list.signal_button_press_event().connect([this](GdkEventButton *ev) -> bool {
- if (ev->button == GDK_BUTTON_PRIMARY && ev->type == GDK_2BUTTON_PRESS) {
- if (auto row = dynamic_cast<ThreadListRow *>(m_list.get_selected_row()))
- m_signal_thread_open.emit(row->ID);
- }
- return false;
- });
-
- Abaddon::Get().GetDiscordClient().GetArchivedPublicThreads(channel.ID, sigc::mem_fun(*this, &ArchivedThreadsList::OnPublicFetched));
-}
-
-void ArchivedThreadsList::InvalidateFilter() {
- m_list.invalidate_filter();
-}
-
-void ArchivedThreadsList::OnPublicFetched(DiscordError code, const ArchivedThreadsResponseData &data) {
- for (const auto &thread : data.Threads) {
- auto row = Gtk::manage(new ThreadListRow(thread));
- row->show();
- m_list.add(*row);
- }
-}
-
-ArchivedThreadsList::type_signal_thread_open ArchivedThreadsList::signal_thread_open() {
- return m_signal_thread_open;
-}
diff --git a/windows/threadswindow.hpp b/windows/threadswindow.hpp
deleted file mode 100644
index 0e42414..0000000
--- a/windows/threadswindow.hpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#pragma once
-#include <gtkmm.h>
-#include "discord/objects.hpp"
-
-class ActiveThreadsList : public Gtk::ScrolledWindow {
-public:
- ActiveThreadsList(const ChannelData &channel, const Gtk::ListBox::SlotFilter &filter);
-
- void InvalidateFilter();
-
-private:
- Gtk::ListBox m_list;
-
- using type_signal_thread_open = sigc::signal<void, Snowflake>;
- type_signal_thread_open m_signal_thread_open;
-
-public:
- type_signal_thread_open signal_thread_open();
-};
-
-class ArchivedThreadsList : public Gtk::ScrolledWindow {
-public:
- ArchivedThreadsList(const ChannelData &channel, const Gtk::ListBox::SlotFilter &filter);
-
- void InvalidateFilter();
-
-private:
- Gtk::ListBox m_list;
-
- void OnPublicFetched(DiscordError code, const ArchivedThreadsResponseData &data);
-
- using type_signal_thread_open = sigc::signal<void, Snowflake>;
- type_signal_thread_open m_signal_thread_open;
-
-public:
- type_signal_thread_open signal_thread_open();
-};
-
-// view all threads in a channel
-class ThreadsWindow : public Gtk::Window {
-public:
- ThreadsWindow(const ChannelData &channel);
-
-private:
- // this filtering is rather cringe but idk what a better alternative would be
- bool ListFilterFunc(Gtk::ListBoxRow *row_);
-
- enum FilterMode {
- FILTER_PUBLIC = 0,
- FILTER_PRIVATE = 1,
- };
- bool m_filter_mode = FILTER_PUBLIC;
-
- Snowflake m_channel_id;
-
- Gtk::StackSwitcher m_switcher;
- Gtk::Stack m_stack;
-
- Gtk::RadioButtonGroup m_group;
- Gtk::ButtonBox m_filter_buttons;
- Gtk::RadioButton m_filter_public;
- Gtk::RadioButton m_filter_private;
-
- Gtk::Box m_box;
-
- ActiveThreadsList m_active;
- ArchivedThreadsList m_archived;
-};
-
-class ThreadListRow : public Gtk::ListBoxRow {
-public:
- ThreadListRow(const ChannelData &channel);
-
- Snowflake ID;
- ChannelType Type;
-
-private:
- Gtk::Label m_label;
-};