From 75213fcede7388e4390660fa2aa12ff253617fab Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Wed, 2 Feb 2022 22:46:55 -0500 Subject: handle multiple embeds in one message --- src/components/chatmessage.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'src/components/chatmessage.cpp') diff --git a/src/components/chatmessage.cpp b/src/components/chatmessage.cpp index ef972bb..e5a65cd 100644 --- a/src/components/chatmessage.cpp +++ b/src/components/chatmessage.cpp @@ -44,17 +44,21 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(const Message &d } } - // there should only ever be 1 embed (i think?) - if (data.Embeds.size() == 1) { - const auto &embed = data.Embeds[0]; - 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); - } else { - container->m_embed_component = container->CreateEmbedComponent(embed); - container->AttachEventHandlers(*container->m_embed_component); - container->m_main.add(*container->m_embed_component); + if (!data.Embeds.empty()) { + // todo refactor (all of) this lol + auto *box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + container->m_embed_component = box; + container->m_main.add(*container->m_embed_component); + for (const auto &embed : data.Embeds) { + 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); + } else { + auto *widget = container->CreateEmbedComponent(embed); + container->AttachEventHandlers(*widget); + box->add(*widget); + } } } -- cgit v1.2.3 From 25fd2c38400d3cafa63343721899d59b42e639a5 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Mon, 14 Feb 2022 02:53:21 -0500 Subject: fix per-guild avatars --- src/components/chatmessage.cpp | 8 ++++---- src/discord/user.cpp | 29 ++++++++++++++++++++++++----- src/discord/user.hpp | 4 +++- 3 files changed, 31 insertions(+), 10 deletions(-) (limited to 'src/components/chatmessage.cpp') diff --git a/src/components/chatmessage.cpp b/src/components/chatmessage.cpp index e5a65cd..d34730b 100644 --- a/src/components/chatmessage.cpp +++ b/src/components/chatmessage.cpp @@ -1,7 +1,7 @@ -#include "chatmessage.hpp" #include "abaddon.hpp" -#include "util.hpp" +#include "chatmessage.hpp" #include "lazyimage.hpp" +#include "util.hpp" #include constexpr static int EmojiSize = 24; // settings eventually @@ -1068,11 +1068,11 @@ ChatMessageHeader::ChatMessageHeader(const Message &data) }; img.LoadFromURL(author->GetAvatarURL(data.GuildID), sigc::track_obj(cb, *this)); - if (author->HasAnimatedAvatar()) { + if (author->HasAnimatedAvatar(data.GuildID)) { auto cb = [this](const Glib::RefPtr &pb) { m_anim_avatar = pb; }; - img.LoadAnimationFromURL(author->GetAvatarURL("gif"), AvatarSize, AvatarSize, sigc::track_obj(cb, *this)); + img.LoadAnimationFromURL(author->GetAvatarURL(data.GuildID, "gif"), AvatarSize, AvatarSize, sigc::track_obj(cb, *this)); } get_style_context()->add_class("message-container"); diff --git a/src/discord/user.cpp b/src/discord/user.cpp index fae212d..6df53aa 100644 --- a/src/discord/user.cpp +++ b/src/discord/user.cpp @@ -6,22 +6,41 @@ bool UserData::IsDeleted() const { } bool UserData::HasAvatar() const { - return Avatar.size() > 0; + return !Avatar.empty(); } -bool UserData::HasAnimatedAvatar() const { - return Avatar.size() > 0 && Avatar[0] == 'a' && Avatar[1] == '_'; +bool UserData::HasAnimatedAvatar() const noexcept { + return !Avatar.empty() && Avatar[0] == 'a' && Avatar[1] == '_'; +} + +bool UserData::HasAnimatedAvatar(Snowflake guild_id) const { + const auto member = Abaddon::Get().GetDiscordClient().GetMember(ID, guild_id); + if (member.has_value() && member->Avatar.has_value() && member->Avatar.value()[0] == 'a' && member->Avatar.value()[1] == '_') + return true; + else if (!member->Avatar.has_value()) + return HasAnimatedAvatar(); + return false; +} + +bool UserData::HasAnimatedAvatar(const std::optional &guild_id) const { + if (guild_id.has_value()) + return HasAnimatedAvatar(*guild_id); + else + return HasAnimatedAvatar(); } std::string UserData::GetAvatarURL(Snowflake guild_id, std::string ext, std::string size) const { const auto member = Abaddon::Get().GetDiscordClient().GetMember(ID, guild_id); - if (member.has_value() && member->Avatar.has_value()) + if (member.has_value() && member->Avatar.has_value()) { + if (ext == "gif" && !(member->Avatar.value()[0] == 'a' && member->Avatar.value()[1] == '_')) + return GetAvatarURL(ext, size); return "https://cdn.discordapp.com/guilds/" + std::to_string(guild_id) + "/users/" + std::to_string(ID) + "/avatars/" + *member->Avatar + "." + ext + "?" + "size=" + size; - else + } else { return GetAvatarURL(ext, size); + } } std::string UserData::GetAvatarURL(const std::optional &guild_id, std::string ext, std::string size) const { diff --git a/src/discord/user.hpp b/src/discord/user.hpp index d4711fa..c058ea1 100644 --- a/src/discord/user.hpp +++ b/src/discord/user.hpp @@ -62,7 +62,9 @@ struct UserData { bool IsDeleted() const; bool HasAvatar() const; - bool HasAnimatedAvatar() const; + bool HasAnimatedAvatar() const noexcept; + bool HasAnimatedAvatar(Snowflake guild_id) const; + bool HasAnimatedAvatar(const std::optional &guild_id) const; std::string GetAvatarURL(Snowflake guild_id, std::string ext = "png", std::string size = "32") const; std::string GetAvatarURL(const std::optional &guild_id, std::string ext = "png", std::string size = "32") const; std::string GetAvatarURL(std::string ext = "png", std::string size = "32") const; -- cgit v1.2.3 From a0599ab812280c74fdeb6b622bf9701f10d659ea Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 20 Feb 2022 01:19:18 -0500 Subject: parse role mentions --- src/components/chatmessage.cpp | 43 +++++++++++++++++++++++++++++++++++++++++- src/components/chatmessage.hpp | 3 ++- src/discord/role.cpp | 8 ++++++++ src/discord/role.hpp | 3 +++ 4 files changed, 55 insertions(+), 2 deletions(-) (limited to 'src/components/chatmessage.cpp') diff --git a/src/components/chatmessage.cpp b/src/components/chatmessage.cpp index d34730b..69e46a6 100644 --- a/src/components/chatmessage.cpp +++ b/src/components/chatmessage.cpp @@ -203,6 +203,7 @@ void ChatMessageItemContainer::UpdateTextComponent(Gtk::TextView *tv) { case MessageType::DEFAULT: case MessageType::INLINE_REPLY: b->insert(s, data->Content); + HandleRoleMentions(b); HandleUserMentions(b); HandleLinks(*tv); HandleChannelMentions(tv); @@ -736,7 +737,47 @@ bool ChatMessageItemContainer::IsEmbedImageOnly(const EmbedData &data) { return data.Thumbnail->ProxyURL.has_value() && data.Thumbnail->URL.has_value() && data.Thumbnail->Width.has_value() && data.Thumbnail->Height.has_value(); } -void ChatMessageItemContainer::HandleUserMentions(Glib::RefPtr buf) { +void ChatMessageItemContainer::HandleRoleMentions(const Glib::RefPtr &buf) { + constexpr static const auto mentions_regex = R"(<@&(\d+)>)"; + + static auto rgx = Glib::Regex::create(mentions_regex); + + Glib::ustring text = GetText(buf); + const auto &discord = Abaddon::Get().GetDiscordClient(); + + int startpos = 0; + Glib::MatchInfo match; + while (rgx->match(text, startpos, match)) { + int mstart, mend; + if (!match.fetch_pos(0, mstart, mend)) break; + const Glib::ustring role_id = match.fetch(1); + const auto role = discord.GetRole(role_id); + if (!role.has_value()) { + startpos = mend; + continue; + } + + Glib::ustring replacement; + if (role->HasColor()) { + replacement = "Color) + "\">@" + role->GetEscapedName() + ""; + } else { + replacement = "@" + role->GetEscapedName() + ""; + } + + 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); + const auto start_it = buf->get_iter_at_offset(chars_start); + const auto end_it = buf->get_iter_at_offset(chars_end); + + auto it = buf->erase(start_it, end_it); + buf->insert_markup(it, replacement); + + text = GetText(buf); + startpos = 0; + } +} + +void ChatMessageItemContainer::HandleUserMentions(const Glib::RefPtr &buf) { constexpr static const auto mentions_regex = R"(<@!?(\d+)>)"; static auto rgx = Glib::Regex::create(mentions_regex); diff --git a/src/components/chatmessage.hpp b/src/components/chatmessage.hpp index 8b69117..bd99275 100644 --- a/src/components/chatmessage.hpp +++ b/src/components/chatmessage.hpp @@ -34,7 +34,8 @@ protected: static bool IsEmbedImageOnly(const EmbedData &data); - void HandleUserMentions(Glib::RefPtr buf); + void HandleRoleMentions(const Glib::RefPtr &buf); + void HandleUserMentions(const Glib::RefPtr &buf); void HandleStockEmojis(Gtk::TextView &tv); void HandleCustomEmojis(Gtk::TextView &tv); void HandleEmojis(Gtk::TextView &tv); diff --git a/src/discord/role.cpp b/src/discord/role.cpp index 07a912e..8a9ed50 100644 --- a/src/discord/role.cpp +++ b/src/discord/role.cpp @@ -12,3 +12,11 @@ void from_json(const nlohmann::json &j, RoleData &m) { JS_D("managed", m.IsManaged); JS_D("mentionable", m.IsMentionable); } + +bool RoleData::HasColor() const noexcept { + return Color != 0; +} + +Glib::ustring RoleData::GetEscapedName() const { + return Glib::Markup::escape_text(Name); +} diff --git a/src/discord/role.hpp b/src/discord/role.hpp index f638b65..a526f4e 100644 --- a/src/discord/role.hpp +++ b/src/discord/role.hpp @@ -16,5 +16,8 @@ struct RoleData { bool IsManaged; bool IsMentionable; + bool HasColor() const noexcept; + Glib::ustring GetEscapedName() const; + friend void from_json(const nlohmann::json &j, RoleData &m); }; -- cgit v1.2.3 From 4bd5c8926626d267806a06cf04867a826d77576f Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 20 Feb 2022 01:20:19 -0500 Subject: fix and refactor multiple embeds in one message --- src/components/chatmessage.cpp | 38 ++++++++++++++++++++++---------------- src/components/chatmessage.hpp | 1 + 2 files changed, 23 insertions(+), 16 deletions(-) (limited to 'src/components/chatmessage.cpp') diff --git a/src/components/chatmessage.cpp b/src/components/chatmessage.cpp index 69e46a6..2111bcc 100644 --- a/src/components/chatmessage.cpp +++ b/src/components/chatmessage.cpp @@ -45,21 +45,8 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(const Message &d } if (!data.Embeds.empty()) { - // todo refactor (all of) this lol - auto *box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); - container->m_embed_component = box; + container->m_embed_component = container->CreateEmbedsComponent(data.Embeds); container->m_main.add(*container->m_embed_component); - for (const auto &embed : data.Embeds) { - 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); - } else { - auto *widget = container->CreateEmbedComponent(embed); - container->AttachEventHandlers(*widget); - box->add(*widget); - } - } } // i dont think attachments can be edited @@ -112,10 +99,11 @@ void ChatMessageItemContainer::UpdateContent() { m_embed_component = nullptr; } - if (data->Embeds.size() == 1) { - m_embed_component = CreateEmbedComponent(data->Embeds[0]); + if (!data->Embeds.empty()) { + m_embed_component = CreateEmbedsComponent(data->Embeds); AttachEventHandlers(*m_embed_component); m_main.add(*m_embed_component); + m_embed_component->show_all(); } } @@ -303,6 +291,24 @@ void ChatMessageItemContainer::UpdateTextComponent(Gtk::TextView *tv) { } } +Gtk::Widget *ChatMessageItemContainer::CreateEmbedsComponent(const std::vector &embeds) { + auto *box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + for (const auto &embed : embeds) { + if (IsEmbedImageOnly(embed)) { + auto *widget = CreateImageComponent(*embed.Thumbnail->ProxyURL, *embed.Thumbnail->URL, *embed.Thumbnail->Width, *embed.Thumbnail->Height); + widget->show(); + AttachEventHandlers(*widget); + box->add(*widget); + } else { + auto *widget = CreateEmbedComponent(embed); + widget->show(); + AttachEventHandlers(*widget); + box->add(*widget); + } + } + return box; +} + Gtk::Widget *ChatMessageItemContainer::CreateEmbedComponent(const EmbedData &embed) { Gtk::EventBox *ev = Gtk::manage(new Gtk::EventBox); ev->set_can_focus(true); diff --git a/src/components/chatmessage.hpp b/src/components/chatmessage.hpp index bd99275..cf7dd3d 100644 --- a/src/components/chatmessage.hpp +++ b/src/components/chatmessage.hpp @@ -22,6 +22,7 @@ protected: void AddClickHandler(Gtk::Widget *widget, std::string); Gtk::TextView *CreateTextComponent(const Message &data); // Message.Content void UpdateTextComponent(Gtk::TextView *tv); + Gtk::Widget *CreateEmbedsComponent(const std::vector &embeds); 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 -- cgit v1.2.3 From fc3d0fddd2645e6af9ef77736ee34b95f168249b Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 27 Feb 2022 00:52:52 -0500 Subject: align stickers --- src/components/chatmessage.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/components/chatmessage.cpp') diff --git a/src/components/chatmessage.cpp b/src/components/chatmessage.cpp index 2111bcc..2007e1f 100644 --- a/src/components/chatmessage.cpp +++ b/src/components/chatmessage.cpp @@ -541,6 +541,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateStickersComponent(const std::vector 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_halign(Gtk::ALIGN_START); img->set_size_request(StickerComponentSize, StickerComponentSize); // should this go in LazyImage ? img->show(); ev->show(); -- cgit v1.2.3 From a2a45757e917aa97e71cf0b84a01dc843759a5f6 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sat, 26 Mar 2022 02:51:56 -0400 Subject: handle nicknames for message headers --- src/components/chatmessage.cpp | 24 ++++++++++++++++-------- src/components/chatmessage.hpp | 3 ++- 2 files changed, 18 insertions(+), 9 deletions(-) (limited to 'src/components/chatmessage.cpp') diff --git a/src/components/chatmessage.cpp b/src/components/chatmessage.cpp index 2007e1f..823aaa6 100644 --- a/src/components/chatmessage.cpp +++ b/src/components/chatmessage.cpp @@ -1131,11 +1131,10 @@ ChatMessageHeader::ChatMessageHeader(const Message &data) 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_xalign(0.0F); m_author.set_can_focus(false); m_meta_ev.signal_button_press_event().connect(sigc::mem_fun(*this, &ChatMessageHeader::on_author_button_press)); @@ -1212,30 +1211,32 @@ ChatMessageHeader::ChatMessageHeader(const Message &data) show_all(); auto &discord = Abaddon::Get().GetDiscordClient(); - auto role_update_cb = [this](...) { UpdateNameColor(); }; + auto role_update_cb = [this](...) { UpdateName(); }; discord.signal_role_update().connect(sigc::track_obj(role_update_cb, *this)); - auto guild_member_update_cb = [this](const auto &, const auto &) { UpdateNameColor(); }; + auto guild_member_update_cb = [this](const auto &, const auto &) { UpdateName(); }; discord.signal_guild_member_update().connect(sigc::track_obj(guild_member_update_cb, *this)); - UpdateNameColor(); + UpdateName(); AttachUserMenuHandler(m_meta_ev); AttachUserMenuHandler(m_avatar_ev); } -void ChatMessageHeader::UpdateNameColor() { +void ChatMessageHeader::UpdateName() { const auto &discord = Abaddon::Get().GetDiscordClient(); const auto user = discord.GetUser(UserID); if (!user.has_value()) return; const auto chan = discord.GetChannel(ChannelID); bool is_guild = chan.has_value() && chan->GuildID.has_value(); if (is_guild) { + const auto member = discord.GetMember(UserID, *chan->GuildID); const auto role_id = discord.GetMemberHoistedRole(*chan->GuildID, UserID, true); const auto role = discord.GetRole(role_id); + const auto name = GetEscapedDisplayName(*user, member); std::string md; if (role.has_value()) - m_author.set_markup("" + user->GetEscapedName() + ""); + m_author.set_markup("" + name + ""); else - m_author.set_markup("" + user->GetEscapedName() + ""); + m_author.set_markup("" + name + ""); } else m_author.set_markup("" + user->GetEscapedName() + ""); } @@ -1259,6 +1260,13 @@ void ChatMessageHeader::AttachUserMenuHandler(Gtk::Widget &widget) { }); } +Glib::ustring ChatMessageHeader::GetEscapedDisplayName(const UserData &user, const std::optional &member) { + if (member.has_value() && !member->Nickname.empty()) + return Glib::Markup::escape_text(member->Nickname); + else + return Glib::Markup::escape_text(user.GetEscapedName()); +} + bool ChatMessageHeader::on_author_button_press(GdkEventButton *ev) { if (ev->button == GDK_BUTTON_PRIMARY && (ev->state & GDK_SHIFT_MASK)) { m_signal_action_insert_mention.emit(); diff --git a/src/components/chatmessage.hpp b/src/components/chatmessage.hpp index cf7dd3d..5e213ee 100644 --- a/src/components/chatmessage.hpp +++ b/src/components/chatmessage.hpp @@ -91,11 +91,12 @@ public: ChatMessageHeader(const Message &data); void AddContent(Gtk::Widget *widget, bool prepend); - void UpdateNameColor(); + void UpdateName(); std::vector GetChildContent(); protected: void AttachUserMenuHandler(Gtk::Widget &widget); + static Glib::ustring GetEscapedDisplayName(const UserData &user, const std::optional &member); bool on_author_button_press(GdkEventButton *ev); -- cgit v1.2.3