summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--abaddon.cpp8
-rw-r--r--abaddon.hpp1
m---------ci/vcpkg0
-rw-r--r--components/chatmessage.cpp192
-rw-r--r--components/chatmessage.hpp29
-rw-r--r--discord/discord.cpp63
-rw-r--r--discord/discord.hpp24
-rw-r--r--discord/message.cpp2
-rw-r--r--discord/message.hpp1
-rw-r--r--discord/snowflake.cpp2
-rw-r--r--discord/snowflake.hpp2
-rw-r--r--discord/sticker.cpp20
-rw-r--r--discord/sticker.hpp11
-rw-r--r--discord/store.cpp25
-rw-r--r--windows/mainwindow.cpp26
-rw-r--r--windows/mainwindow.hpp6
17 files changed, 238 insertions, 176 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 472b96d..94a5c40 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,7 +5,7 @@ on: [push, pull_request]
jobs:
windows:
name: windows-${{ matrix.buildtype }}
- runs-on: windows-2016
+ runs-on: windows-latest
strategy:
matrix:
buildtype: [Debug, RelWithDebInfo, MinSizeRel]
diff --git a/abaddon.cpp b/abaddon.cpp
index f0729a9..e309a78 100644
--- a/abaddon.cpp
+++ b/abaddon.cpp
@@ -98,7 +98,6 @@ int Abaddon::StartGTK() {
m_main_window->signal_action_reload_css().connect(sigc::mem_fun(*this, &Abaddon::ActionReloadCSS));
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_view_pins().connect(sigc::mem_fun(*this, &Abaddon::ActionViewPins));
@@ -451,8 +450,7 @@ void Abaddon::ActionConnect() {
}
void Abaddon::ActionDisconnect() {
- if (m_discord.IsStarted())
- StopDiscord();
+ StopDiscord();
}
void Abaddon::ActionSetToken() {
@@ -654,10 +652,6 @@ bool Abaddon::ShowConfirm(const Glib::ustring &prompt, Gtk::Window *window) {
return dlg.run() == Gtk::RESPONSE_OK;
}
-void Abaddon::ActionReloadSettings() {
- m_settings.Reload();
-}
-
void Abaddon::ActionReloadCSS() {
try {
Gtk::StyleContext::remove_provider_for_screen(Gdk::Screen::get_default(), m_css_provider);
diff --git a/abaddon.hpp b/abaddon.hpp
index d3b9c1c..3784f77 100644
--- a/abaddon.hpp
+++ b/abaddon.hpp
@@ -50,7 +50,6 @@ public:
bool ShowConfirm(const Glib::ustring &prompt, Gtk::Window *window = nullptr);
- void ActionReloadSettings();
void ActionReloadCSS();
ImageManager &GetImageManager();
diff --git a/ci/vcpkg b/ci/vcpkg
-Subproject a9b27ed5dffbf70b135eddb0c4729f3ca87f106
+Subproject 50ea8c0ab7aca3bb9245bba7fc877ad2f2a4464
diff --git a/components/chatmessage.cpp b/components/chatmessage.cpp
index 727b64a..63db7e9 100644
--- a/components/chatmessage.cpp
+++ b/components/chatmessage.cpp
@@ -9,10 +9,11 @@ constexpr static int AvatarSize = 32;
constexpr static int EmbedImageWidth = 400;
constexpr static int EmbedImageHeight = 300;
constexpr static int ThumbnailSize = 100;
+constexpr static int StickerComponentSize = 160;
-ChatMessageItemContainer::ChatMessageItemContainer() {
- m_main = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
- add(*m_main);
+ChatMessageItemContainer::ChatMessageItemContainer()
+ : m_main(Gtk::ORIENTATION_VERTICAL) {
+ add(m_main);
m_link_menu_copy = Gtk::manage(new Gtk::MenuItem("Copy Link"));
m_link_menu_copy->signal_activate().connect(sigc::mem_fun(*this, &ChatMessageItemContainer::on_link_menu_copy));
@@ -32,13 +33,13 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(const Message &d
if (data.Content.size() > 0 || data.Type != MessageType::DEFAULT) {
container->m_text_component = container->CreateTextComponent(data);
container->AttachEventHandlers(*container->m_text_component);
- container->m_main->add(*container->m_text_component);
+ container->m_main.add(*container->m_text_component);
}
if ((data.MessageReference.has_value() || data.Interaction.has_value()) && data.Type != MessageType::CHANNEL_FOLLOW_ADD) {
auto *widget = container->CreateReplyComponent(data);
- container->m_main->add(*widget);
- container->m_main->child_property_position(*widget) = 0; // eek
+ container->m_main.add(*widget);
+ container->m_main.child_property_position(*widget) = 0; // eek
}
// there should only ever be 1 embed (i think?)
@@ -47,11 +48,11 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(const Message &d
if (IsEmbedImageOnly(embed)) {
auto *widget = container->CreateImageComponent(*embed.Thumbnail->ProxyURL, *embed.Thumbnail->URL, *embed.Thumbnail->Width, *embed.Thumbnail->Height);
container->AttachEventHandlers(*widget);
- container->m_main->add(*widget);
+ container->m_main.add(*widget);
} else {
container->m_embed_component = container->CreateEmbedComponent(embed);
container->AttachEventHandlers(*container->m_embed_component);
- container->m_main->add(*container->m_embed_component);
+ container->m_main.add(*container->m_embed_component);
}
}
@@ -60,14 +61,16 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(const Message &d
for (const auto &a : data.Attachments) {
if (IsURLViewableImage(a.ProxyURL) && a.Width.has_value() && a.Height.has_value()) {
auto *widget = container->CreateImageComponent(a.ProxyURL, a.URL, *a.Width, *a.Height);
- container->m_main->add(*widget);
+ container->m_main.add(*widget);
} else {
auto *widget = container->CreateAttachmentComponent(a);
- container->m_main->add(*widget);
+ container->m_main.add(*widget);
}
}
// only 1?
+ /*
+ DEPRECATED
if (data.Stickers.has_value()) {
const auto &sticker = data.Stickers.value()[0];
// todo: lottie, proper apng
@@ -75,11 +78,16 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(const Message &d
auto *widget = container->CreateStickerComponent(sticker);
container->m_main->add(*widget);
}
+ }*/
+
+ if (data.StickerItems.has_value()) {
+ auto *widget = container->CreateStickersComponent(*data.StickerItems);
+ container->m_main.add(*widget);
}
if (data.Reactions.has_value() && data.Reactions->size() > 0) {
container->m_reactions_component = container->CreateReactionsComponent(data);
- container->m_main->add(*container->m_reactions_component);
+ container->m_main.add(*container->m_reactions_component);
}
container->UpdateAttributes();
@@ -101,7 +109,7 @@ void ChatMessageItemContainer::UpdateContent() {
if (data->Embeds.size() == 1) {
m_embed_component = CreateEmbedComponent(data->Embeds[0]);
AttachEventHandlers(*m_embed_component);
- m_main->add(*m_embed_component);
+ m_main.add(*m_embed_component);
}
}
@@ -113,7 +121,7 @@ void ChatMessageItemContainer::UpdateReactions() {
if (data->Reactions.has_value() && data->Reactions->size() > 0) {
m_reactions_component = CreateReactionsComponent(*data);
m_reactions_component->show_all();
- m_main->add(*m_reactions_component);
+ m_main.add(*m_reactions_component);
}
}
@@ -137,7 +145,7 @@ void ChatMessageItemContainer::UpdateAttributes() {
m_attrib_label = Gtk::manage(new Gtk::Label);
m_attrib_label->set_halign(Gtk::ALIGN_START);
m_attrib_label->show();
- m_main->add(*m_attrib_label); // todo: maybe insert markup into existing text widget's buffer if the circumstances are right (or pack horizontally)
+ m_main.add(*m_attrib_label); // todo: maybe insert markup into existing text widget's buffer if the circumstances are right (or pack horizontally)
}
if (deleted)
@@ -479,7 +487,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateAttachmentComponent(const Attachmen
return ev;
}
-Gtk::Widget *ChatMessageItemContainer::CreateStickerComponent(const StickerData &data) {
+Gtk::Widget *ChatMessageItemContainer::CreateStickerComponentDeprecated(const StickerData &data) {
auto *box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
auto *imgw = Gtk::manage(new Gtk::Image);
box->add(*imgw);
@@ -496,6 +504,27 @@ Gtk::Widget *ChatMessageItemContainer::CreateStickerComponent(const StickerData
return box;
}
+Gtk::Widget *ChatMessageItemContainer::CreateStickersComponent(const std::vector<StickerItem> &data) {
+ auto *box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
+
+ for (const auto &sticker : data) {
+ // no lottie
+ if (sticker.FormatType != StickerFormatType::PNG && sticker.FormatType != StickerFormatType::APNG) continue;
+ auto *ev = Gtk::manage(new Gtk::EventBox);
+ auto *img = Gtk::manage(new LazyImage(sticker.GetURL(), StickerComponentSize, StickerComponentSize, false));
+ img->set_size_request(StickerComponentSize, StickerComponentSize); // should this go in LazyImage ?
+ img->show();
+ ev->show();
+ ev->add(*img);
+ box->add(*ev);
+ }
+
+ box->show();
+
+ AttachEventHandlers(*box);
+ return box;
+}
+
Gtk::Widget *ChatMessageItemContainer::CreateReactionsComponent(const Message &data) {
auto *flow = Gtk::manage(new Gtk::FlowBox);
flow->set_orientation(Gtk::ORIENTATION_HORIZONTAL);
@@ -843,8 +872,10 @@ void ChatMessageItemContainer::HandleChannelMentions(Glib::RefPtr<Gtk::TextBuffe
}
auto tag = buf->create_tag();
- m_channel_tagmap[tag] = channel_id;
- tag->property_weight() = Pango::WEIGHT_BOLD;
+ if (chan->Type == ChannelType::GUILD_TEXT) {
+ m_channel_tagmap[tag] = channel_id;
+ tag->property_weight() = Pango::WEIGHT_BOLD;
+ }
const auto chars_start = g_utf8_pointer_to_offset(text.c_str(), text.c_str() + mstart);
const auto chars_end = g_utf8_pointer_to_offset(text.c_str(), text.c_str() + mend);
@@ -990,26 +1021,20 @@ void ChatMessageItemContainer::AttachEventHandlers(Gtk::Widget &widget) {
widget.signal_button_press_event().connect(on_button_press_event, false);
}
-ChatMessageHeader::ChatMessageHeader(const Message &data) {
+ChatMessageHeader::ChatMessageHeader(const Message &data)
+ : m_main_box(Gtk::ORIENTATION_HORIZONTAL)
+ , m_content_box(Gtk::ORIENTATION_VERTICAL)
+ , m_meta_box(Gtk::ORIENTATION_HORIZONTAL)
+ , m_avatar(Abaddon::Get().GetImageManager().GetPlaceholder(AvatarSize)) {
UserID = data.Author.ID;
ChannelID = data.ChannelID;
- m_main_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
- m_content_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
- m_content_box_ev = Gtk::manage(new Gtk::EventBox);
- m_meta_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
- m_meta_ev = Gtk::manage(new Gtk::EventBox);
- m_author = Gtk::manage(new Gtk::Label);
- m_timestamp = Gtk::manage(new Gtk::Label);
- m_avatar_ev = Gtk::manage(new Gtk::EventBox);
-
const auto author = Abaddon::Get().GetDiscordClient().GetUser(UserID);
auto &img = Abaddon::Get().GetImageManager();
- m_avatar = Gtk::manage(new Gtk::Image(img.GetPlaceholder(AvatarSize)));
auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
m_static_avatar = pb->scale_simple(AvatarSize, AvatarSize, Gdk::INTERP_BILINEAR);
- m_avatar->property_pixbuf() = m_static_avatar;
+ m_avatar.property_pixbuf() = m_static_avatar;
};
img.LoadFromURL(author->GetAvatarURL(data.GuildID), sigc::track_obj(cb, *this));
@@ -1021,21 +1046,21 @@ ChatMessageHeader::ChatMessageHeader(const Message &data) {
}
get_style_context()->add_class("message-container");
- m_author->get_style_context()->add_class("message-container-author");
- m_timestamp->get_style_context()->add_class("message-container-timestamp");
- m_avatar->get_style_context()->add_class("message-container-avatar");
+ m_author.get_style_context()->add_class("message-container-author");
+ m_timestamp.get_style_context()->add_class("message-container-timestamp");
+ m_avatar.get_style_context()->add_class("message-container-avatar");
- m_avatar->set_valign(Gtk::ALIGN_START);
- m_avatar->set_margin_right(10);
+ m_avatar.set_valign(Gtk::ALIGN_START);
+ m_avatar.set_margin_right(10);
- m_author->set_markup(data.Author.GetEscapedBoldName());
- m_author->set_single_line_mode(true);
- m_author->set_line_wrap(false);
- m_author->set_ellipsize(Pango::ELLIPSIZE_END);
- m_author->set_xalign(0.f);
- m_author->set_can_focus(false);
+ m_author.set_markup(data.Author.GetEscapedBoldName());
+ m_author.set_single_line_mode(true);
+ m_author.set_line_wrap(false);
+ m_author.set_ellipsize(Pango::ELLIPSIZE_END);
+ m_author.set_xalign(0.f);
+ m_author.set_can_focus(false);
- m_meta_ev->signal_button_press_event().connect(sigc::mem_fun(*this, &ChatMessageHeader::on_author_button_press));
+ m_meta_ev.signal_button_press_event().connect(sigc::mem_fun(*this, &ChatMessageHeader::on_author_button_press));
if (author->IsBot || data.WebhookID.has_value()) {
m_extra = Gtk::manage(new Gtk::Label);
@@ -1050,59 +1075,59 @@ ChatMessageHeader::ChatMessageHeader(const Message &data) {
else if (data.WebhookID.has_value())
m_extra->set_markup("<b>Webhook</b>");
- m_timestamp->set_text(data.ID.GetLocalTimestamp());
- m_timestamp->set_hexpand(true);
- m_timestamp->set_halign(Gtk::ALIGN_END);
- m_timestamp->set_ellipsize(Pango::ELLIPSIZE_END);
- m_timestamp->set_opacity(0.5);
- m_timestamp->set_single_line_mode(true);
- m_timestamp->set_margin_start(12);
- m_timestamp->set_can_focus(false);
+ m_timestamp.set_text(data.ID.GetLocalTimestamp());
+ m_timestamp.set_hexpand(true);
+ m_timestamp.set_halign(Gtk::ALIGN_END);
+ m_timestamp.set_ellipsize(Pango::ELLIPSIZE_END);
+ m_timestamp.set_opacity(0.5);
+ m_timestamp.set_single_line_mode(true);
+ m_timestamp.set_margin_start(12);
+ m_timestamp.set_can_focus(false);
- m_main_box->set_hexpand(true);
- m_main_box->set_vexpand(true);
- m_main_box->set_can_focus(true);
+ m_main_box.set_hexpand(true);
+ m_main_box.set_vexpand(true);
+ m_main_box.set_can_focus(true);
- m_meta_box->set_hexpand(true);
- m_meta_box->set_can_focus(false);
+ m_meta_box.set_hexpand(true);
+ m_meta_box.set_can_focus(false);
- m_content_box->set_can_focus(false);
+ m_content_box.set_can_focus(false);
const auto on_enter_cb = [this](const GdkEventCrossing *event) -> bool {
if (m_anim_avatar)
- m_avatar->property_pixbuf_animation() = m_anim_avatar;
+ m_avatar.property_pixbuf_animation() = m_anim_avatar;
return false;
};
const auto on_leave_cb = [this](const GdkEventCrossing *event) -> bool {
if (m_anim_avatar)
- m_avatar->property_pixbuf() = m_static_avatar;
+ m_avatar.property_pixbuf() = m_static_avatar;
return false;
};
- m_content_box_ev->add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
- m_meta_ev->add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
- m_avatar_ev->add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
+ m_content_box_ev.add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
+ m_meta_ev.add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
+ m_avatar_ev.add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
if (Abaddon::Get().GetSettings().GetShowAnimations()) {
- m_content_box_ev->signal_enter_notify_event().connect(on_enter_cb);
- m_content_box_ev->signal_leave_notify_event().connect(on_leave_cb);
- m_meta_ev->signal_enter_notify_event().connect(on_enter_cb);
- m_meta_ev->signal_leave_notify_event().connect(on_leave_cb);
- m_avatar_ev->signal_enter_notify_event().connect(on_enter_cb);
- m_avatar_ev->signal_leave_notify_event().connect(on_leave_cb);
+ m_content_box_ev.signal_enter_notify_event().connect(on_enter_cb);
+ m_content_box_ev.signal_leave_notify_event().connect(on_leave_cb);
+ m_meta_ev.signal_enter_notify_event().connect(on_enter_cb);
+ m_meta_ev.signal_leave_notify_event().connect(on_leave_cb);
+ m_avatar_ev.signal_enter_notify_event().connect(on_enter_cb);
+ m_avatar_ev.signal_leave_notify_event().connect(on_leave_cb);
}
- m_meta_box->add(*m_author);
+ m_meta_box.add(m_author);
if (m_extra != nullptr)
- m_meta_box->add(*m_extra);
+ m_meta_box.add(*m_extra);
- m_meta_box->add(*m_timestamp);
- m_meta_ev->add(*m_meta_box);
- m_content_box->add(*m_meta_ev);
- m_avatar_ev->add(*m_avatar);
- m_main_box->add(*m_avatar_ev);
- m_content_box_ev->add(*m_content_box);
- m_main_box->add(*m_content_box_ev);
- add(*m_main_box);
+ m_meta_box.add(m_timestamp);
+ m_meta_ev.add(m_meta_box);
+ m_content_box.add(m_meta_ev);
+ m_avatar_ev.add(m_avatar);
+ m_main_box.add(m_avatar_ev);
+ m_content_box_ev.add(m_content_box);
+ m_main_box.add(m_content_box_ev);
+ add(m_main_box);
set_margin_bottom(8);
@@ -1114,8 +1139,8 @@ ChatMessageHeader::ChatMessageHeader(const Message &data) {
auto guild_member_update_cb = [this](const auto &, const auto &) { UpdateNameColor(); };
discord.signal_guild_member_update().connect(sigc::track_obj(guild_member_update_cb, *this));
UpdateNameColor();
- AttachUserMenuHandler(*m_meta_ev);
- AttachUserMenuHandler(*m_avatar_ev);
+ AttachUserMenuHandler(m_meta_ev);
+ AttachUserMenuHandler(m_avatar_ev);
}
void ChatMessageHeader::UpdateNameColor() {
@@ -1132,7 +1157,7 @@ void ChatMessageHeader::UpdateNameColor() {
else
md = "<span weight='bold'>" + user->GetEscapedName() + "</span>";
- m_author->set_markup(md);
+ m_author.set_markup(md);
}
std::vector<Gtk::Widget *> ChatMessageHeader::GetChildContent() {
@@ -1173,12 +1198,13 @@ ChatMessageHeader::type_signal_action_open_user_menu ChatMessageHeader::signal_a
void ChatMessageHeader::AddContent(Gtk::Widget *widget, bool prepend) {
m_content_widgets.push_back(widget);
- widget->signal_unmap().connect([this, widget]() {
+ const auto cb = [this, widget]() {
m_content_widgets.erase(std::remove(m_content_widgets.begin(), m_content_widgets.end(), widget), m_content_widgets.end());
- });
- m_content_box->add(*widget);
+ };
+ widget->signal_unmap().connect(sigc::track_obj(cb, *this, *widget), false);
+ m_content_box.add(*widget);
if (prepend)
- m_content_box->reorder_child(*widget, 1);
+ m_content_box.reorder_child(*widget, 1);
if (auto *x = dynamic_cast<ChatMessageItemContainer *>(widget)) {
if (x->ID > NewestID)
NewestID = x->ID;
diff --git a/components/chatmessage.hpp b/components/chatmessage.hpp
index 7bc050d..f319449 100644
--- a/components/chatmessage.hpp
+++ b/components/chatmessage.hpp
@@ -25,7 +25,8 @@ protected:
Gtk::Widget *CreateEmbedComponent(const EmbedData &data); // Message.Embeds[0]
Gtk::Widget *CreateImageComponent(const std::string &proxy_url, const std::string &url, int inw, int inh);
Gtk::Widget *CreateAttachmentComponent(const AttachmentData &data); // non-image attachments
- Gtk::Widget *CreateStickerComponent(const StickerData &data);
+ Gtk::Widget *CreateStickerComponentDeprecated(const StickerData &data);
+ Gtk::Widget *CreateStickersComponent(const std::vector<StickerItem> &data);
Gtk::Widget *CreateReactionsComponent(const Message &data);
Gtk::Widget *CreateReplyComponent(const Message &data);
@@ -57,8 +58,8 @@ protected:
void AttachEventHandlers(Gtk::Widget &widget);
- Gtk::EventBox *m_ev;
- Gtk::Box *m_main;
+ Gtk::EventBox *_ev;
+ Gtk::Box m_main;
Gtk::Label *m_attrib_label = nullptr;
Gtk::TextView *m_text_component = nullptr;
@@ -89,25 +90,25 @@ public:
ChatMessageHeader(const Message &data);
void AddContent(Gtk::Widget *widget, bool prepend);
void UpdateNameColor();
- std::vector<Gtk::Widget*> GetChildContent();
+ std::vector<Gtk::Widget *> GetChildContent();
protected:
void AttachUserMenuHandler(Gtk::Widget &widget);
bool on_author_button_press(GdkEventButton *ev);
- std::vector<Gtk::Widget*> m_content_widgets;
+ std::vector<Gtk::Widget *> m_content_widgets;
- Gtk::Box *m_main_box;
- Gtk::Box *m_content_box;
- Gtk::EventBox *m_content_box_ev;
- Gtk::Box *m_meta_box;
- Gtk::EventBox *m_meta_ev;
- Gtk::Label *m_author;
- Gtk::Label *m_timestamp;
+ Gtk::Box m_main_box;
+ Gtk::Box m_content_box;
+ Gtk::EventBox m_content_box_ev;
+ Gtk::Box m_meta_box;
+ Gtk::EventBox m_meta_ev;
+ Gtk::Label m_author;
+ Gtk::Label m_timestamp;
Gtk::Label *m_extra = nullptr;
- Gtk::Image *m_avatar;
- Gtk::EventBox *m_avatar_ev;
+ Gtk::Image m_avatar;
+ Gtk::EventBox m_avatar_ev;
Glib::RefPtr<Gdk::Pixbuf> m_static_avatar;
Glib::RefPtr<Gdk::PixbufAnimation> m_anim_avatar;
diff --git a/discord/discord.cpp b/discord/discord.cpp
index 78036ad..8dc1ef8 100644
--- a/discord/discord.cpp
+++ b/discord/discord.cpp
@@ -24,6 +24,8 @@ DiscordClient::DiscordClient(bool mem_store)
}
void DiscordClient::Start() {
+ if (m_client_started) return;
+
m_http.SetBase(GetAPIURL());
std::memset(&m_zstream, 0, sizeof(m_zstream));
@@ -32,27 +34,31 @@ void DiscordClient::Start() {
m_last_sequence = -1;
m_heartbeat_acked = true;
m_client_connected = true;
+ m_client_started = true;
m_websocket.StartConnection(GetGatewayURL());
}
void DiscordClient::Stop() {
- if (!m_client_connected) return;
+ if (m_client_started) {
+ inflateEnd(&m_zstream);
+ m_compressed_buf.clear();
- inflateEnd(&m_zstream);
- m_compressed_buf.clear();
+ m_heartbeat_waiter.kill();
+ if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join();
+ m_client_connected = false;
+ m_reconnecting = false;
- m_heartbeat_waiter.kill();
- if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join();
- m_client_connected = false;
+ m_store.ClearAll();
+ m_guild_to_users.clear();
- m_store.ClearAll();
- m_guild_to_users.clear();
+ m_websocket.Stop();
+ }
- m_websocket.Stop();
+ m_client_started = false;
}
bool DiscordClient::IsStarted() const {
- return m_client_connected;
+ return m_client_started;
}
bool DiscordClient::IsStoreValid() const {
@@ -199,22 +205,17 @@ Snowflake DiscordClient::GetMemberHoistedRole(Snowflake guild_id, Snowflake user
const auto data = GetMember(user_id, guild_id);
if (!data.has_value()) return Snowflake::Invalid;
- std::vector<RoleData> roles;
+ std::optional<RoleData> top_role;
for (const auto &id : data->Roles) {
const auto role = GetRole(id);
if (role.has_value()) {
- if (role->IsHoisted || (with_color && role->Color != 0))
- roles.push_back(*role);
+ if ((with_color && role->Color != 0x000000) || (!with_color && role->IsHoisted))
+ if (!top_role.has_value() || top_role->Position < role->Position)
+ top_role = role;
}
}
- if (roles.size() == 0) return Snowflake::Invalid;
-
- std::sort(roles.begin(), roles.end(), [this](const RoleData &a, const RoleData &b) -> bool {
- return a.Position > b.Position;
- });
-
- return roles[0].ID;
+ return top_role.has_value() ? top_role->ID : Snowflake::Invalid;
}
std::optional<RoleData> DiscordClient::GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const {
@@ -233,19 +234,19 @@ std::optional<RoleData> DiscordClient::GetMemberHighestRole(Snowflake guild_id,
});
}
-std::unordered_set<Snowflake> DiscordClient::GetUsersInGuild(Snowflake id) const {
+std::set<Snowflake> DiscordClient::GetUsersInGuild(Snowflake id) const {
auto it = m_guild_to_users.find(id);
if (it != m_guild_to_users.end())
return it->second;
- return std::unordered_set<Snowflake>();
+ return {};
}
-std::unordered_set<Snowflake> DiscordClient::GetChannelsInGuild(Snowflake id) const {
+std::set<Snowflake> DiscordClient::GetChannelsInGuild(Snowflake id) const {
auto it = m_guild_to_channels.find(id);
if (it != m_guild_to_channels.end())
return it->second;
- return std::unordered_set<Snowflake>();
+ return {};
}
bool DiscordClient::HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const {
@@ -953,12 +954,12 @@ PresenceStatus DiscordClient::GetUserStatus(Snowflake id) const {
return PresenceStatus::Offline;
}
-std::unordered_map<Snowflake, RelationshipType> DiscordClient::GetRelationships() const {
+std::map<Snowflake, RelationshipType> DiscordClient::GetRelationships() const {
return m_user_relationships;
}
-std::unordered_set<Snowflake> DiscordClient::GetRelationships(RelationshipType type) const {
- std::unordered_set<Snowflake> ret;
+std::set<Snowflake> DiscordClient::GetRelationships(RelationshipType type) const {
+ std::set<Snowflake> ret;
for (const auto &[id, rtype] : m_user_relationships)
if (rtype == type)
ret.insert(id);
@@ -1682,7 +1683,8 @@ void DiscordClient::HandleGatewayInvalidSession(const GatewayMessage &msg) {
m_websocket.Stop(1000);
- m_websocket.StartConnection(GetGatewayURL());
+ if (m_client_started)
+ Glib::signal_timeout().connect_once([this] { if (m_client_started) m_websocket.StartConnection(GetGatewayURL()); }, 1000);
}
bool IsCompleteMessageObject(const nlohmann::json &j) {
@@ -1886,6 +1888,11 @@ void DiscordClient::HandleSocketClose(uint16_t code) {
m_store.ClearAll();
m_guild_to_users.clear();
+ if (m_client_started && !m_reconnecting && close_code == GatewayCloseCode::Abnormal) {
+ Glib::signal_timeout().connect_once([this] { if (m_client_started) HandleGatewayReconnect(GatewayMessage()); }, 1000);
+ m_reconnecting = true;
+ }
+
m_signal_disconnected.emit(m_reconnecting, close_code);
};
m_generic_mutex.lock();
diff --git a/discord/discord.hpp b/discord/discord.hpp
index cfce016..918b1cb 100644
--- a/discord/discord.hpp
+++ b/discord/discord.hpp
@@ -6,9 +6,8 @@
#include <sigc++/sigc++.h>
#include <nlohmann/json.hpp>
#include <thread>
-#include <unordered_map>
+#include <map>
#include <set>
-#include <unordered_set>
#include <mutex>
#include <zlib.h>
#include <glibmm.h>
@@ -85,8 +84,8 @@ public:
std::optional<BanData> GetBan(Snowflake guild_id, Snowflake user_id) const;
Snowflake GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color = false) const;
std::optional<RoleData> GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const;
- std::unordered_set<Snowflake> GetUsersInGuild(Snowflake id) const;
- std::unordered_set<Snowflake> GetChannelsInGuild(Snowflake id) const;
+ std::set<Snowflake> GetUsersInGuild(Snowflake id) const;
+ std::set<Snowflake> GetChannelsInGuild(Snowflake id) const;
bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const;
@@ -184,8 +183,8 @@ public:
PresenceStatus GetUserStatus(Snowflake id) const;
- std::unordered_map<Snowflake, RelationshipType> GetRelationships() const;
- std::unordered_set<Snowflake> GetRelationships(RelationshipType type) const;
+ std::map<Snowflake, RelationshipType> GetRelationships() const;
+ std::set<Snowflake> GetRelationships(RelationshipType type) const;
std::optional<RelationshipType> GetRelationship(Snowflake id) const;
private:
@@ -255,14 +254,14 @@ private:
std::string m_token;
void AddUserToGuild(Snowflake user_id, Snowflake guild_id);
- std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_guild_to_users;
+ std::map<Snowflake, std::set<Snowflake>> m_guild_to_users;
- std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_guild_to_channels;
- std::unordered_map<Snowflake, GuildApplicationData> m_guild_join_requests;
+ std::map<Snowflake, std::set<Snowflake>> m_guild_to_channels;
+ std::map<Snowflake, GuildApplicationData> m_guild_join_requests;
- std::unordered_map<Snowflake, PresenceStatus> m_user_to_status;
+ std::map<Snowflake, PresenceStatus> m_user_to_status;
- std::unordered_map<Snowflake, RelationshipType> m_user_relationships;
+ std::map<Snowflake, RelationshipType> m_user_relationships;
UserData m_user_data;
UserSettings m_user_settings;
@@ -272,8 +271,9 @@ private:
Websocket m_websocket;
std::atomic<bool> m_client_connected = false;
std::atomic<bool> m_ready_received = false;
+ bool m_client_started = false;
- std::unordered_map<std::string, GatewayEvent> m_event_map;
+ std::map<std::string, GatewayEvent> m_event_map;
void LoadEventMap();
std::thread m_heartbeat_thread;
diff --git a/discord/message.cpp b/discord/message.cpp
index b072ba8..70c557d 100644
--- a/discord/message.cpp
+++ b/discord/message.cpp
@@ -218,6 +218,7 @@ void from_json(const nlohmann::json &j, Message &m) {
m.ReferencedMessage = nullptr;
}
JS_O("interaction", m.Interaction);
+ JS_O("sticker_items", m.StickerItems);
}
void Message::from_json_edited(const nlohmann::json &j) {
@@ -244,6 +245,7 @@ void Message::from_json_edited(const nlohmann::json &j) {
JS_O("flags", Flags);
JS_O("stickers", Stickers);
JS_O("interaction", Interaction);
+ JS_O("sticker_items", StickerItems);
}
void Message::SetDeleted() {
diff --git a/discord/message.hpp b/discord/message.hpp
index e24f248..a6ea039 100644
--- a/discord/message.hpp
+++ b/discord/message.hpp
@@ -199,6 +199,7 @@ struct Message {
std::optional<std::vector<StickerData>> Stickers;
std::optional<std::shared_ptr<Message>> ReferencedMessage; // has_value && null means deleted
std::optional<MessageInteractionData> Interaction;
+ std::optional<std::vector<StickerItem>> StickerItems;
friend void from_json(const nlohmann::json &j, Message &m);
void from_json_edited(const nlohmann::json &j); // for MESSAGE_UPDATE
diff --git a/discord/snowflake.cpp b/discord/snowflake.cpp
index 18c7805..cea9153 100644
--- a/discord/snowflake.cpp
+++ b/discord/snowflake.cpp
@@ -5,6 +5,8 @@
constexpr static uint64_t DiscordEpochSeconds = 1420070400;
+const Snowflake Snowflake::Invalid = -1ULL;
+
Snowflake::Snowflake()
: m_num(Invalid) {}
diff --git a/discord/snowflake.hpp b/discord/snowflake.hpp
index 4263bab..0b79723 100644
--- a/discord/snowflake.hpp
+++ b/discord/snowflake.hpp
@@ -26,7 +26,7 @@ struct Snowflake {
return m_num;
}
- const static uint64_t Invalid = -1ULL; // makes sense to me
+ const static Snowflake Invalid; // makes sense to me
const static uint64_t SecondsInterval = 4194304000ULL; // the "difference" between two snowflakes one second apart
friend void from_json(const nlohmann::json &j, Snowflake &s);
diff --git a/discord/sticker.cpp b/discord/sticker.cpp
index 8e50a47..b92d031 100644
--- a/discord/sticker.cpp
+++ b/discord/sticker.cpp
@@ -30,3 +30,23 @@ std::string StickerData::GetURL() const {
return "https://media.discordapp.net/stickers/" + std::to_string(ID) + "/" + *AssetHash + ".json";
return "";
}
+
+void to_json(nlohmann::json &j, const StickerItem &m) {
+ j["id"] = m.ID;
+ j["name"] = m.Name;
+ j["format_type"] = m.FormatType;
+}
+
+void from_json(const nlohmann::json &j, StickerItem &m) {
+ JS_D("id", m.ID);
+ JS_D("name", m.Name);
+ JS_D("format_type", m.FormatType);
+}
+
+std::string StickerItem::GetURL() const {
+ if (FormatType == StickerFormatType::PNG || FormatType == StickerFormatType::APNG)
+ return "https://media.discordapp.net/stickers/" + std::to_string(ID) + ".png?size=256";
+ else if (FormatType == StickerFormatType::LOTTIE)
+ return "https://media.discordapp.net/stickers/" + std::to_string(ID) + ".json";
+ return "";
+}
diff --git a/discord/sticker.hpp b/discord/sticker.hpp
index 89279b3..d23fe7b 100644
--- a/discord/sticker.hpp
+++ b/discord/sticker.hpp
@@ -27,3 +27,14 @@ struct StickerData {
std::string GetURL() const;
};
+
+struct StickerItem {
+ StickerFormatType FormatType;
+ Snowflake ID;
+ std::string Name;
+
+ friend void to_json(nlohmann::json &j, const StickerItem &m);
+ friend void from_json(const nlohmann::json &j, StickerItem &m);
+
+ std::string GetURL() const;
+};
diff --git a/discord/store.cpp b/discord/store.cpp
index fc40108..2439da5 100644
--- a/discord/store.cpp
+++ b/discord/store.cpp
@@ -264,6 +264,12 @@ void Store::SetMessage(Snowflake id, const Message &message) {
Bind(m_set_msg_stmt, 23, message.IsPending);
Bind(m_set_msg_stmt, 24, message.Nonce); // sorry
+ if (message.StickerItems.has_value()) {
+ std::string tmp = nlohmann::json(*message.StickerItems).dump();
+ Bind(m_set_msg_stmt, 25, tmp);
+ } else
+ Bind(m_set_msg_stmt, 25, nullptr);
+
if (!RunInsert(m_set_msg_stmt))
fprintf(stderr, "message insert failed: %s\n", sqlite3_errstr(m_db_err));
@@ -369,14 +375,18 @@ Message Store::GetMessageBound(sqlite3_stmt *stmt) const {
Get(stmt, 22, ret.IsPending);
Get(stmt, 23, ret.Nonce);
+ Get(stmt, 24, tmps);
+ if (tmps != "")
+ ret.StickerItems = nlohmann::json::parse(tmps).get<std::vector<StickerItem>>();
+
// interaction data from join
- if (!IsNull(stmt, 24)) {
+ if (!IsNull(stmt, 25)) {
auto &interaction = ret.Interaction.emplace();
- Get(stmt, 24, interaction.ID);
- Get(stmt, 25, interaction.Name);
- Get(stmt, 26, interaction.Type);
- Get(stmt, 27, interaction.User.ID);
+ Get(stmt, 25, interaction.ID);
+ Get(stmt, 26, interaction.Name);
+ Get(stmt, 27, interaction.Type);
+ Get(stmt, 28, interaction.User.ID);
}
Reset(stmt);
@@ -837,7 +847,8 @@ bool Store::CreateTables() {
deleted BOOL, /* extra */
edited BOOL, /* extra */
pending BOOL, /* extra */
- nonce TEXT
+ nonce TEXT,
+ sticker_items TEXT /* json */
)
)";
@@ -1056,7 +1067,7 @@ bool Store::CreateStatements() {
const char *set_msg = R"(
REPLACE INTO messages VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
)";
diff --git a/windows/mainwindow.cpp b/windows/mainwindow.cpp
index 4d6a1dc..2eb669e 100644
--- a/windows/mainwindow.cpp
+++ b/windows/mainwindow.cpp
@@ -32,10 +32,8 @@ MainWindow::MainWindow()
m_menu_file.set_label("File");
m_menu_file.set_submenu(m_menu_file_sub);
- m_menu_file_reload_settings.set_label("Reload Settings");
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_settings);
m_menu_file_sub.append(m_menu_file_reload_css);
m_menu_file_sub.append(m_menu_file_clear_cache);
@@ -76,10 +74,6 @@ MainWindow::MainWindow()
m_signal_action_set_status.emit();
});
- m_menu_file_reload_settings.signal_activate().connect([this] {
- m_signal_action_reload_settings.emit();
- });
-
m_menu_file_clear_cache.signal_activate().connect([this] {
Abaddon::Get().GetImageManager().ClearCache();
});
@@ -155,13 +149,6 @@ MainWindow::MainWindow()
void MainWindow::UpdateComponents() {
bool discord_active = Abaddon::Get().IsDiscordActive();
- 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);
-
if (!discord_active) {
m_chat.Clear();
m_members.Clear();
@@ -265,6 +252,15 @@ void MainWindow::OnDiscordSubmenuPopup(const Gdk::Rectangle *flipped_rect, const
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);
+
+ 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) {
@@ -312,10 +308,6 @@ MainWindow::type_signal_action_set_status MainWindow::signal_action_set_status()
return m_signal_action_set_status;
}
-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;
}
diff --git a/windows/mainwindow.hpp b/windows/mainwindow.hpp
index 25c1acb..fa3d331 100644
--- a/windows/mainwindow.hpp
+++ b/windows/mainwindow.hpp
@@ -41,9 +41,8 @@ public:
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;
- typedef sigc::signal<void> type_signal_action_reload_settings;
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_pins; // channel id
type_signal_action_connect signal_action_connect();
type_signal_action_disconnect signal_action_disconnect();
@@ -51,7 +50,6 @@ public:
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_reload_settings signal_action_reload_settings();
type_signal_action_add_recipient signal_action_add_recipient();
type_signal_action_view_pins signal_action_view_pins();
@@ -62,7 +60,6 @@ protected:
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_reload_settings m_signal_action_reload_settings;
type_signal_action_add_recipient m_signal_action_add_recipient;
type_signal_action_view_pins m_signal_action_view_pins;
@@ -92,7 +89,6 @@ protected:
Gtk::MenuItem m_menu_file;
Gtk::Menu m_menu_file_sub;
- Gtk::MenuItem m_menu_file_reload_settings;
Gtk::MenuItem m_menu_file_reload_css;
Gtk::MenuItem m_menu_file_clear_cache;