mirror of
https://github.com/celisej567/abaddon.git
synced 2026-09-13 20:18:50 +03:00
add menu item to add recipient to group dm
This commit is contained in:
11
abaddon.cpp
11
abaddon.cpp
@@ -8,6 +8,7 @@
|
||||
#include "dialogs/joinguild.hpp"
|
||||
#include "dialogs/confirm.hpp"
|
||||
#include "dialogs/setstatus.hpp"
|
||||
#include "dialogs/friendpicker.hpp"
|
||||
#include "abaddon.hpp"
|
||||
#include "windows/guildsettingswindow.hpp"
|
||||
#include "windows/profilewindow.hpp"
|
||||
@@ -124,6 +125,7 @@ int Abaddon::StartGTK() {
|
||||
m_main_window->signal_action_join_guild().connect(sigc::mem_fun(*this, &Abaddon::ActionJoinGuildDialog));
|
||||
m_main_window->signal_action_set_status().connect(sigc::mem_fun(*this, &Abaddon::ActionSetStatus));
|
||||
m_main_window->signal_action_reload_settings().connect(sigc::mem_fun(*this, &Abaddon::ActionReloadSettings));
|
||||
m_main_window->signal_action_add_recipient().connect(sigc::mem_fun(*this, &Abaddon::ActionAddRecipient));
|
||||
|
||||
m_main_window->signal_action_show_user_menu().connect(sigc::mem_fun(*this, &Abaddon::ShowUserMenu));
|
||||
|
||||
@@ -547,6 +549,15 @@ void Abaddon::ActionGuildSettings(Snowflake id) {
|
||||
window->show();
|
||||
}
|
||||
|
||||
void Abaddon::ActionAddRecipient(Snowflake channel_id) {
|
||||
FriendPickerDialog dlg(*m_main_window);
|
||||
auto response = dlg.run();
|
||||
if (response == Gtk::RESPONSE_OK) {
|
||||
auto user_id = dlg.GetUserID();
|
||||
m_discord.AddGroupDMRecipient(channel_id, user_id);
|
||||
}
|
||||
}
|
||||
|
||||
void Abaddon::ActionReloadSettings() {
|
||||
m_settings.Reload();
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
void ActionReactionAdd(Snowflake id, const Glib::ustring ¶m);
|
||||
void ActionReactionRemove(Snowflake id, const Glib::ustring ¶m);
|
||||
void ActionGuildSettings(Snowflake id);
|
||||
void ActionAddRecipient(Snowflake channel_id);
|
||||
|
||||
void ActionReloadSettings();
|
||||
void ActionReloadCSS();
|
||||
|
||||
96
dialogs/friendpicker.cpp
Normal file
96
dialogs/friendpicker.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "friendpicker.hpp"
|
||||
#include "../abaddon.hpp"
|
||||
|
||||
FriendPickerDialog::FriendPickerDialog(Gtk::Window &parent)
|
||||
: Gtk::Dialog("Pick a friend", parent, true)
|
||||
, m_bbox(Gtk::ORIENTATION_HORIZONTAL) {
|
||||
set_default_size(300, 300);
|
||||
get_style_context()->add_class("app-window");
|
||||
get_style_context()->add_class("app-popup");
|
||||
|
||||
m_ok_button = add_button("OK", Gtk::RESPONSE_OK);
|
||||
m_cancel_button = add_button("Cancel", Gtk::RESPONSE_CANCEL);
|
||||
|
||||
m_ok_button->set_sensitive(false);
|
||||
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
auto relationships = discord.GetRelationships(RelationshipType::Friend);
|
||||
for (auto id : relationships) {
|
||||
auto *item = Gtk::manage(new FriendPickerDialogItem(id));
|
||||
item->show();
|
||||
m_list.add(*item);
|
||||
}
|
||||
|
||||
m_list.signal_row_activated().connect(sigc::mem_fun(*this, &FriendPickerDialog::OnRowActivated));
|
||||
m_list.signal_selected_rows_changed().connect(sigc::mem_fun(*this, &FriendPickerDialog::OnSelectionChange));
|
||||
m_list.set_activate_on_single_click(false);
|
||||
m_list.set_selection_mode(Gtk::SELECTION_SINGLE);
|
||||
|
||||
m_main.set_propagate_natural_height(true);
|
||||
|
||||
m_main.add(m_list);
|
||||
|
||||
get_content_area()->add(m_main);
|
||||
|
||||
show_all_children();
|
||||
}
|
||||
|
||||
Snowflake FriendPickerDialog::GetUserID() const {
|
||||
return m_chosen_id;
|
||||
}
|
||||
|
||||
void FriendPickerDialog::OnRowActivated(Gtk::ListBoxRow *row) {
|
||||
auto *x = dynamic_cast<FriendPickerDialogItem *>(row);
|
||||
if (x != nullptr) {
|
||||
m_chosen_id = x->ID;
|
||||
response(Gtk::RESPONSE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void FriendPickerDialog::OnSelectionChange() {
|
||||
auto selection = m_list.get_selected_row();
|
||||
m_ok_button->set_sensitive(false);
|
||||
if (selection != nullptr) {
|
||||
auto *row = dynamic_cast<FriendPickerDialogItem *>(selection);
|
||||
if (!row) return;
|
||||
m_chosen_id = row->ID;
|
||||
m_ok_button->set_sensitive(true);
|
||||
}
|
||||
}
|
||||
|
||||
FriendPickerDialogItem::FriendPickerDialogItem(Snowflake user_id)
|
||||
: ID(user_id)
|
||||
, m_layout(Gtk::ORIENTATION_HORIZONTAL) {
|
||||
auto user = *Abaddon::Get().GetDiscordClient().GetUser(user_id);
|
||||
|
||||
m_name.set_markup("<b>" +
|
||||
Glib::Markup::escape_text(user.Username) + "</b>#" + user.Discriminator);
|
||||
m_name.set_single_line_mode(true);
|
||||
|
||||
m_avatar.property_pixbuf() = Abaddon::Get().GetImageManager().GetPlaceholder(32);
|
||||
if (user.HasAvatar()) {
|
||||
if (user.HasAnimatedAvatar() && Abaddon::Get().GetSettings().GetShowAnimations()) {
|
||||
auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
|
||||
m_avatar.property_pixbuf_animation() = pb;
|
||||
};
|
||||
Abaddon::Get().GetImageManager().LoadAnimationFromURL(user.GetAvatarURL("gif", "32"), 32, 32, sigc::track_obj(cb, *this));
|
||||
} else {
|
||||
auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
|
||||
m_avatar.property_pixbuf() = pb->scale_simple(32, 32, Gdk::INTERP_BILINEAR);
|
||||
};
|
||||
Abaddon::Get().GetImageManager().LoadFromURL(user.GetAvatarURL("png", "32"), sigc::track_obj(cb, *this));
|
||||
}
|
||||
}
|
||||
|
||||
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_layout.add(m_avatar);
|
||||
m_layout.add(m_name);
|
||||
add(m_layout);
|
||||
|
||||
show_all_children();
|
||||
}
|
||||
35
dialogs/friendpicker.hpp
Normal file
35
dialogs/friendpicker.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include <gtkmm.h>
|
||||
#include "../discord/snowflake.hpp"
|
||||
|
||||
class FriendPickerDialog : public Gtk::Dialog {
|
||||
public:
|
||||
FriendPickerDialog(Gtk::Window &parent);
|
||||
|
||||
Snowflake GetUserID() const;
|
||||
|
||||
protected:
|
||||
void OnRowActivated(Gtk::ListBoxRow *row);
|
||||
void OnSelectionChange();
|
||||
|
||||
Snowflake m_chosen_id;
|
||||
|
||||
Gtk::ScrolledWindow m_main;
|
||||
Gtk::ListBox m_list;
|
||||
Gtk::ButtonBox m_bbox;
|
||||
|
||||
Gtk::Button *m_ok_button;
|
||||
Gtk::Button *m_cancel_button;
|
||||
};
|
||||
|
||||
class FriendPickerDialogItem : public Gtk::ListBoxRow {
|
||||
public:
|
||||
FriendPickerDialogItem(Snowflake user_id);
|
||||
|
||||
Snowflake ID;
|
||||
|
||||
private:
|
||||
Gtk::Box m_layout;
|
||||
Gtk::Image m_avatar;
|
||||
Gtk::Label m_name;
|
||||
};
|
||||
@@ -522,6 +522,12 @@ void DiscordClient::DeleteInvite(const std::string &code, sigc::slot<void(bool s
|
||||
});
|
||||
}
|
||||
|
||||
void DiscordClient::AddGroupDMRecipient(Snowflake channel_id, Snowflake user_id) {
|
||||
m_http.MakePUT("/channels/" + std::to_string(channel_id) + "/recipients/" + std::to_string(user_id), "", [this](const http::response_type &response) {
|
||||
CheckCode(response);
|
||||
});
|
||||
}
|
||||
|
||||
void DiscordClient::RemoveGroupDMRecipient(Snowflake channel_id, Snowflake user_id) {
|
||||
m_http.MakeDELETE("/channels/" + std::to_string(channel_id) + "/recipients/" + std::to_string(user_id), [this](const http::response_type &response) {
|
||||
CheckCode(response);
|
||||
@@ -645,6 +651,14 @@ std::optional<PresenceStatus> DiscordClient::GetUserStatus(Snowflake id) const {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::unordered_set<Snowflake> DiscordClient::GetRelationships(RelationshipType type) const {
|
||||
std::unordered_set<Snowflake> ret;
|
||||
for (const auto &[id, rtype] : m_user_relationships)
|
||||
if (rtype == type)
|
||||
ret.insert(id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DiscordClient::HandleGatewayMessageRaw(std::string str) {
|
||||
// handles multiple zlib compressed messages, calling HandleGatewayMessage when a full message is received
|
||||
std::vector<uint8_t> buf(str.begin(), str.end());
|
||||
@@ -890,6 +904,10 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
|
||||
}
|
||||
}
|
||||
|
||||
if (data.Relationships.has_value())
|
||||
for (const auto &relationship : *data.Relationships)
|
||||
m_user_relationships[relationship.ID] = relationship.Type;
|
||||
|
||||
m_store.EndTransaction();
|
||||
|
||||
m_session_id = data.SessionID;
|
||||
|
||||
@@ -120,6 +120,7 @@ public:
|
||||
void UnbanUser(Snowflake guild_id, Snowflake user_id, sigc::slot<void(bool success)> callback);
|
||||
void DeleteInvite(const std::string &code);
|
||||
void DeleteInvite(const std::string &code, sigc::slot<void(bool success)> callback);
|
||||
void AddGroupDMRecipient(Snowflake channel_id, Snowflake user_id);
|
||||
void RemoveGroupDMRecipient(Snowflake channel_id, Snowflake user_id);
|
||||
|
||||
// FetchGuildBans fetches all bans+reasons via api, this func fetches stored bans (so usually just GUILD_BAN_ADD data)
|
||||
@@ -143,6 +144,8 @@ public:
|
||||
|
||||
std::optional<PresenceStatus> GetUserStatus(Snowflake id) const;
|
||||
|
||||
std::unordered_set<Snowflake> GetRelationships(RelationshipType type) const;
|
||||
|
||||
private:
|
||||
static const constexpr int InflateChunkSize = 0x10000;
|
||||
std::vector<uint8_t> m_compressed_buf;
|
||||
@@ -207,6 +210,8 @@ private:
|
||||
|
||||
std::unordered_map<Snowflake, PresenceStatus> m_user_to_status;
|
||||
|
||||
std::unordered_map<Snowflake, RelationshipType> m_user_relationships;
|
||||
|
||||
UserData m_user_data;
|
||||
UserSettings m_user_settings;
|
||||
|
||||
|
||||
@@ -75,7 +75,8 @@ void HTTPClient::MakePUT(const std::string &path, const std::string &payload, st
|
||||
m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] {
|
||||
http::request req(http::REQUEST_PUT, m_api_base + path);
|
||||
req.set_header("Authorization", m_authorization);
|
||||
req.set_header("Content-Type", "application/json");
|
||||
if (payload != "")
|
||||
req.set_header("Content-Type", "application/json");
|
||||
req.set_user_agent(m_agent != "" ? m_agent : "Abaddon");
|
||||
req.set_body(payload);
|
||||
#ifdef USE_LOCAL_PROXY
|
||||
|
||||
@@ -118,6 +118,7 @@ void from_json(const nlohmann::json &j, ReadyEventData &m) {
|
||||
JS_D("private_channels", m.PrivateChannels);
|
||||
JS_O("users", m.Users);
|
||||
JS_ON("merged_members", m.MergedMembers);
|
||||
JS_O("relationships", m.Relationships);
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json &j, MergedPresence &m) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "sticker.hpp"
|
||||
#include "ban.hpp"
|
||||
#include "auditlog.hpp"
|
||||
#include "relationship.hpp"
|
||||
|
||||
// most stuff below should just be objects that get processed and thrown away immediately
|
||||
|
||||
@@ -200,6 +201,7 @@ struct ReadyEventData {
|
||||
std::optional<int> FriendSuggestionCount;
|
||||
UserSettings Settings;
|
||||
std::optional<std::vector<std::vector<GuildMember>>> MergedMembers;
|
||||
std::optional<std::vector<RelationshipData>> Relationships;
|
||||
// std::vector<Unknown> ConnectedAccounts; // opt
|
||||
// std::map<std::string, Unknown> Consents; // opt
|
||||
// std::vector<Unknown> Experiments; // opt
|
||||
@@ -207,7 +209,6 @@ struct ReadyEventData {
|
||||
// std::map<Unknown, Unknown> Notes; // opt
|
||||
// std::vector<PresenceData> Presences; // opt
|
||||
// std::vector<ReadStateData> ReadStates; // opt
|
||||
// std::vector<RelationshipData> Relationships; // opt
|
||||
// Unknown Tutorial; // opt, null
|
||||
// std::vector<GuildSettingData> UserGuildSettings; // opt
|
||||
|
||||
|
||||
6
discord/relationship.cpp
Normal file
6
discord/relationship.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "relationship.hpp"
|
||||
|
||||
void from_json(const nlohmann::json &j, RelationshipData &m) {
|
||||
JS_D("type", m.Type);
|
||||
JS_D("id", m.ID);
|
||||
}
|
||||
21
discord/relationship.hpp
Normal file
21
discord/relationship.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "json.hpp"
|
||||
#include "user.hpp"
|
||||
|
||||
enum class RelationshipType {
|
||||
None = 0,
|
||||
Friend = 1,
|
||||
Blocked = 2,
|
||||
PendingIncoming = 3,
|
||||
PendingOutgoing = 4,
|
||||
Implicit = 5,
|
||||
};
|
||||
|
||||
struct RelationshipData {
|
||||
// Snowflake UserID; this is the same as ID apparently but it looks new so i wont touch it
|
||||
RelationshipType Type;
|
||||
Snowflake ID;
|
||||
// Unknown Nickname; // null
|
||||
|
||||
friend void from_json(const nlohmann::json &j, RelationshipData &m);
|
||||
};
|
||||
@@ -20,11 +20,14 @@ MainWindow::MainWindow()
|
||||
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");
|
||||
@@ -72,6 +75,10 @@ MainWindow::MainWindow()
|
||||
Abaddon::Get().GetImageManager().ClearCache();
|
||||
});
|
||||
|
||||
m_menu_discord_add_recipient.signal_activate().connect([this] {
|
||||
m_signal_action_add_recipient.emit(GetChatActiveChannel());
|
||||
});
|
||||
|
||||
m_content_box.set_hexpand(true);
|
||||
m_content_box.set_vexpand(true);
|
||||
m_content_box.show();
|
||||
@@ -237,6 +244,15 @@ void MainWindow::UpdateChatReactionRemove(Snowflake id, const Glib::ustring &par
|
||||
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();
|
||||
auto channel = discord.GetChannel(channel_id);
|
||||
m_menu_discord_add_recipient.set_visible(false);
|
||||
if (channel.has_value() && channel->GetDMRecipients().size() + 1 < 10)
|
||||
m_menu_discord_add_recipient.set_visible(channel->Type == ChannelType::GROUP_DM);
|
||||
}
|
||||
|
||||
ChannelList *MainWindow::GetChannelList() {
|
||||
return &m_channel_list;
|
||||
}
|
||||
@@ -280,3 +296,7 @@ MainWindow::type_signal_action_show_user_menu MainWindow::signal_action_show_use
|
||||
MainWindow::type_signal_action_reload_settings MainWindow::signal_action_reload_settings() {
|
||||
return m_signal_action_reload_settings;
|
||||
}
|
||||
|
||||
MainWindow::type_signal_action_add_recipient MainWindow::signal_action_add_recipient() {
|
||||
return m_signal_action_add_recipient;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
typedef sigc::signal<void> type_signal_action_set_status;
|
||||
typedef sigc::signal<void, const GdkEvent *, Snowflake, Snowflake> type_signal_action_show_user_menu;
|
||||
typedef sigc::signal<void> type_signal_action_reload_settings;
|
||||
typedef sigc::signal<void, Snowflake> type_signal_action_add_recipient; // channel id
|
||||
|
||||
type_signal_action_connect signal_action_connect();
|
||||
type_signal_action_disconnect signal_action_disconnect();
|
||||
@@ -51,6 +52,7 @@ public:
|
||||
type_signal_action_set_status signal_action_set_status();
|
||||
type_signal_action_show_user_menu signal_action_show_user_menu();
|
||||
type_signal_action_reload_settings signal_action_reload_settings();
|
||||
type_signal_action_add_recipient signal_action_add_recipient();
|
||||
|
||||
protected:
|
||||
type_signal_action_connect m_signal_action_connect;
|
||||
@@ -61,6 +63,7 @@ protected:
|
||||
type_signal_action_set_status m_signal_action_set_status;
|
||||
type_signal_action_show_user_menu m_signal_action_show_user_menu;
|
||||
type_signal_action_reload_settings m_signal_action_reload_settings;
|
||||
type_signal_action_add_recipient m_signal_action_add_recipient;
|
||||
|
||||
protected:
|
||||
Gtk::Box m_main_box;
|
||||
@@ -80,6 +83,8 @@ protected:
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user