mirror of
https://github.com/celisej567/abaddon.git
synced 2026-09-19 20:11:59 +03:00
animated avatars on hover
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
constexpr const int EmojiSize = 24; // settings eventually
|
constexpr const int EmojiSize = 24; // settings eventually
|
||||||
|
constexpr const int AvatarSize = 32;
|
||||||
|
|
||||||
ChatMessageItemContainer::ChatMessageItemContainer() {
|
ChatMessageItemContainer::ChatMessageItemContainer() {
|
||||||
m_main = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
|
m_main = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
|
||||||
@@ -44,14 +45,14 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(Snowflake id) {
|
|||||||
|
|
||||||
if (data->Content.size() > 0 || data->Type != MessageType::DEFAULT) {
|
if (data->Content.size() > 0 || data->Type != MessageType::DEFAULT) {
|
||||||
container->m_text_component = container->CreateTextComponent(&*data);
|
container->m_text_component = container->CreateTextComponent(&*data);
|
||||||
container->AttachGuildMenuHandler(container->m_text_component);
|
container->AttachEventHandlers(container->m_text_component);
|
||||||
container->m_main->add(*container->m_text_component);
|
container->m_main->add(*container->m_text_component);
|
||||||
}
|
}
|
||||||
|
|
||||||
// there should only ever be 1 embed (i think?)
|
// there should only ever be 1 embed (i think?)
|
||||||
if (data->Embeds.size() == 1) {
|
if (data->Embeds.size() == 1) {
|
||||||
container->m_embed_component = container->CreateEmbedComponent(&*data);
|
container->m_embed_component = container->CreateEmbedComponent(&*data);
|
||||||
container->AttachGuildMenuHandler(container->m_embed_component);
|
container->AttachEventHandlers(container->m_embed_component);
|
||||||
container->m_main->add(*container->m_embed_component);
|
container->m_main->add(*container->m_embed_component);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +104,7 @@ void ChatMessageItemContainer::UpdateContent() {
|
|||||||
if (m_embed_imgurl.size() > 0) {
|
if (m_embed_imgurl.size() > 0) {
|
||||||
m_signal_image_load.emit(m_embed_imgurl);
|
m_signal_image_load.emit(m_embed_imgurl);
|
||||||
}
|
}
|
||||||
AttachGuildMenuHandler(m_embed_component);
|
AttachEventHandlers(m_embed_component);
|
||||||
m_main->add(*m_embed_component);
|
m_main->add(*m_embed_component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -375,7 +376,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateImageComponent(const AttachmentData
|
|||||||
widget->set_halign(Gtk::ALIGN_START);
|
widget->set_halign(Gtk::ALIGN_START);
|
||||||
widget->set_size_request(w, h);
|
widget->set_size_request(w, h);
|
||||||
|
|
||||||
AttachGuildMenuHandler(ev);
|
AttachEventHandlers(ev);
|
||||||
AddClickHandler(ev, data.URL);
|
AddClickHandler(ev, data.URL);
|
||||||
HandleImage(data, widget, data.ProxyURL);
|
HandleImage(data, widget, data.ProxyURL);
|
||||||
|
|
||||||
@@ -390,7 +391,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateAttachmentComponent(const Attachmen
|
|||||||
ev->get_style_context()->add_class("message-attachment-box");
|
ev->get_style_context()->add_class("message-attachment-box");
|
||||||
ev->add(*btn);
|
ev->add(*btn);
|
||||||
|
|
||||||
AttachGuildMenuHandler(ev);
|
AttachEventHandlers(ev);
|
||||||
AddClickHandler(ev, data.URL);
|
AddClickHandler(ev, data.URL);
|
||||||
|
|
||||||
return ev;
|
return ev;
|
||||||
@@ -410,7 +411,7 @@ Gtk::Widget *ChatMessageItemContainer::CreateStickerComponent(const Sticker &dat
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachGuildMenuHandler(box);
|
AttachEventHandlers(box);
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -859,21 +860,40 @@ ChatMessageItemContainer::type_signal_action_reaction_remove ChatMessageItemCont
|
|||||||
return m_signal_action_reaction_remove;
|
return m_signal_action_reaction_remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatMessageItemContainer::type_signal_enter ChatMessageItemContainer::signal_enter() {
|
||||||
|
return m_signal_enter;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatMessageItemContainer::type_signal_leave ChatMessageItemContainer::signal_leave() {
|
||||||
|
return m_signal_leave;
|
||||||
|
}
|
||||||
|
|
||||||
ChatMessageItemContainer::type_signal_image_load ChatMessageItemContainer::signal_image_load() {
|
ChatMessageItemContainer::type_signal_image_load ChatMessageItemContainer::signal_image_load() {
|
||||||
return m_signal_image_load;
|
return m_signal_image_load;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatMessageItemContainer::AttachGuildMenuHandler(Gtk::Widget *widget) {
|
void ChatMessageItemContainer::AttachEventHandlers(Gtk::Widget *widget) {
|
||||||
// clang-format off
|
const auto on_button_press_event = [this](GdkEventButton *event) -> bool {
|
||||||
widget->signal_button_press_event().connect([this](GdkEventButton *event) -> bool {
|
|
||||||
if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_SECONDARY) {
|
if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_SECONDARY) {
|
||||||
ShowMenu(reinterpret_cast<GdkEvent*>(event));
|
ShowMenu(reinterpret_cast<GdkEvent *>(event));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}, false);
|
};
|
||||||
// clang-format on
|
widget->signal_button_press_event().connect(on_button_press_event, false);
|
||||||
|
|
||||||
|
widget->add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
|
||||||
|
const auto on_notify_crossing = [this](GdkEventCrossing *event) -> bool {
|
||||||
|
if (event->type == GDK_ENTER_NOTIFY)
|
||||||
|
m_signal_enter.emit();
|
||||||
|
else if (event->type == GDK_LEAVE_NOTIFY)
|
||||||
|
m_signal_leave.emit();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
widget->signal_enter_notify_event().connect(on_notify_crossing);
|
||||||
|
widget->signal_leave_notify_event().connect(on_notify_crossing);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatMessageHeader::ChatMessageHeader(const Message *data) {
|
ChatMessageHeader::ChatMessageHeader(const Message *data) {
|
||||||
@@ -890,16 +910,22 @@ ChatMessageHeader::ChatMessageHeader(const Message *data) {
|
|||||||
|
|
||||||
const auto author = Abaddon::Get().GetDiscordClient().GetUser(UserID);
|
const auto author = Abaddon::Get().GetDiscordClient().GetUser(UserID);
|
||||||
auto &img = Abaddon::Get().GetImageManager();
|
auto &img = Abaddon::Get().GetImageManager();
|
||||||
Glib::RefPtr<Gdk::Pixbuf> buf;
|
|
||||||
if (author.has_value())
|
|
||||||
buf = img.GetFromURLIfCached(author->GetAvatarURL());
|
|
||||||
|
|
||||||
if (buf)
|
auto static_buf = img.GetFromURLIfCached(author->GetAvatarURL());
|
||||||
m_avatar = Gtk::manage(new Gtk::Image(buf));
|
auto anim_buf = img.GetAnimationFromURLIfCached(author->GetAvatarURL("gif"), AvatarSize, AvatarSize);
|
||||||
else {
|
|
||||||
m_avatar = Gtk::manage(new Gtk::Image(img.GetPlaceholder(32)));
|
if (anim_buf)
|
||||||
if (author.has_value())
|
m_anim_avatar = anim_buf;
|
||||||
|
|
||||||
|
if (static_buf) {
|
||||||
|
m_static_avatar = static_buf;
|
||||||
|
m_avatar = Gtk::manage(new Gtk::Image(static_buf));
|
||||||
|
} else {
|
||||||
|
m_avatar = Gtk::manage(new Gtk::Image(img.GetPlaceholder(AvatarSize)));
|
||||||
|
if (author.has_value()) {
|
||||||
img.LoadFromURL(author->GetAvatarURL(), sigc::mem_fun(*this, &ChatMessageHeader::OnAvatarLoad));
|
img.LoadFromURL(author->GetAvatarURL(), sigc::mem_fun(*this, &ChatMessageHeader::OnAvatarLoad));
|
||||||
|
img.LoadAnimationFromURL(author->GetAvatarURL("gif"), AvatarSize, AvatarSize, sigc::mem_fun(*this, &ChatMessageHeader::OnAnimatedAvatarLoad));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get_style_context()->add_class("message-container");
|
get_style_context()->add_class("message-container");
|
||||||
@@ -990,9 +1016,14 @@ void ChatMessageHeader::UpdateNameColor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ChatMessageHeader::OnAvatarLoad(const Glib::RefPtr<Gdk::Pixbuf> &pixbuf) {
|
void ChatMessageHeader::OnAvatarLoad(const Glib::RefPtr<Gdk::Pixbuf> &pixbuf) {
|
||||||
|
m_static_avatar = pixbuf;
|
||||||
m_avatar->property_pixbuf() = pixbuf;
|
m_avatar->property_pixbuf() = pixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatMessageHeader::OnAnimatedAvatarLoad(const Glib::RefPtr<Gdk::PixbufAnimation> &pixbuf) {
|
||||||
|
m_anim_avatar = pixbuf;
|
||||||
|
}
|
||||||
|
|
||||||
void ChatMessageHeader::AttachUserMenuHandler(Gtk::Widget &widget) {
|
void ChatMessageHeader::AttachUserMenuHandler(Gtk::Widget &widget) {
|
||||||
widget.signal_button_press_event().connect([this](GdkEventButton *ev) -> bool {
|
widget.signal_button_press_event().connect([this](GdkEventButton *ev) -> bool {
|
||||||
if (ev->type == GDK_BUTTON_PRESS && ev->button == GDK_BUTTON_SECONDARY) {
|
if (ev->type == GDK_BUTTON_PRESS && ev->button == GDK_BUTTON_SECONDARY) {
|
||||||
@@ -1022,6 +1053,19 @@ ChatMessageHeader::type_signal_action_open_user_menu ChatMessageHeader::signal_a
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ChatMessageHeader::AddContent(Gtk::Widget *widget, bool prepend) {
|
void ChatMessageHeader::AddContent(Gtk::Widget *widget, bool prepend) {
|
||||||
|
if (Abaddon::Get().GetSettings().GetShowAnimations()) {
|
||||||
|
auto *container = dynamic_cast<ChatMessageItemContainer *>(widget);
|
||||||
|
if (container != nullptr) {
|
||||||
|
container->signal_enter().connect([this] {
|
||||||
|
if (m_anim_avatar)
|
||||||
|
m_avatar->property_pixbuf_animation() = m_anim_avatar;
|
||||||
|
});
|
||||||
|
container->signal_leave().connect([this] {
|
||||||
|
if (m_anim_avatar) // if there is no anim avatar then it would have never switched off
|
||||||
|
m_avatar->property_pixbuf() = m_static_avatar;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
m_content_box->add(*widget);
|
m_content_box->add(*widget);
|
||||||
if (prepend)
|
if (prepend)
|
||||||
m_content_box->reorder_child(*widget, 1);
|
m_content_box->reorder_child(*widget, 1);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ protected:
|
|||||||
|
|
||||||
std::unordered_map<std::string, std::pair<Gtk::Image *, AttachmentData>> m_img_loadmap;
|
std::unordered_map<std::string, std::pair<Gtk::Image *, AttachmentData>> m_img_loadmap;
|
||||||
|
|
||||||
void AttachGuildMenuHandler(Gtk::Widget *widget);
|
void AttachEventHandlers(Gtk::Widget *widget);
|
||||||
void ShowMenu(GdkEvent *event);
|
void ShowMenu(GdkEvent *event);
|
||||||
|
|
||||||
Gtk::Menu m_menu;
|
Gtk::Menu m_menu;
|
||||||
@@ -88,12 +88,16 @@ public:
|
|||||||
typedef sigc::signal<void, Snowflake> type_signal_channel_click;
|
typedef sigc::signal<void, Snowflake> type_signal_channel_click;
|
||||||
typedef sigc::signal<void, Glib::ustring> type_signal_action_reaction_add;
|
typedef sigc::signal<void, Glib::ustring> type_signal_action_reaction_add;
|
||||||
typedef sigc::signal<void, Glib::ustring> type_signal_action_reaction_remove;
|
typedef sigc::signal<void, Glib::ustring> type_signal_action_reaction_remove;
|
||||||
|
typedef sigc::signal<void> type_signal_enter;
|
||||||
|
typedef sigc::signal<void> type_signal_leave;
|
||||||
|
|
||||||
type_signal_action_delete signal_action_delete();
|
type_signal_action_delete signal_action_delete();
|
||||||
type_signal_action_edit signal_action_edit();
|
type_signal_action_edit signal_action_edit();
|
||||||
type_signal_channel_click signal_action_channel_click();
|
type_signal_channel_click signal_action_channel_click();
|
||||||
type_signal_action_reaction_add signal_action_reaction_add();
|
type_signal_action_reaction_add signal_action_reaction_add();
|
||||||
type_signal_action_reaction_remove signal_action_reaction_remove();
|
type_signal_action_reaction_remove signal_action_reaction_remove();
|
||||||
|
type_signal_enter signal_enter();
|
||||||
|
type_signal_leave signal_leave();
|
||||||
|
|
||||||
type_signal_image_load signal_image_load();
|
type_signal_image_load signal_image_load();
|
||||||
|
|
||||||
@@ -103,6 +107,8 @@ private:
|
|||||||
type_signal_channel_click m_signal_action_channel_click;
|
type_signal_channel_click m_signal_action_channel_click;
|
||||||
type_signal_action_reaction_add m_signal_action_reaction_add;
|
type_signal_action_reaction_add m_signal_action_reaction_add;
|
||||||
type_signal_action_reaction_remove m_signal_action_reaction_remove;
|
type_signal_action_reaction_remove m_signal_action_reaction_remove;
|
||||||
|
type_signal_enter m_signal_enter;
|
||||||
|
type_signal_leave m_signal_leave;
|
||||||
|
|
||||||
type_signal_image_load m_signal_image_load;
|
type_signal_image_load m_signal_image_load;
|
||||||
};
|
};
|
||||||
@@ -118,6 +124,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnAvatarLoad(const Glib::RefPtr<Gdk::Pixbuf> &pixbuf);
|
void OnAvatarLoad(const Glib::RefPtr<Gdk::Pixbuf> &pixbuf);
|
||||||
|
void OnAnimatedAvatarLoad(const Glib::RefPtr<Gdk::PixbufAnimation> &pixbuf);
|
||||||
|
|
||||||
void AttachUserMenuHandler(Gtk::Widget &widget);
|
void AttachUserMenuHandler(Gtk::Widget &widget);
|
||||||
|
|
||||||
@@ -133,6 +140,9 @@ protected:
|
|||||||
Gtk::Image *m_avatar;
|
Gtk::Image *m_avatar;
|
||||||
Gtk::EventBox *m_avatar_ev;
|
Gtk::EventBox *m_avatar_ev;
|
||||||
|
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> m_static_avatar;
|
||||||
|
Glib::RefPtr<Gdk::PixbufAnimation> m_anim_avatar;
|
||||||
|
|
||||||
typedef sigc::signal<void> type_signal_action_insert_mention;
|
typedef sigc::signal<void> type_signal_action_insert_mention;
|
||||||
typedef sigc::signal<void, const GdkEvent *> type_signal_action_open_user_menu;
|
typedef sigc::signal<void, const GdkEvent *> type_signal_action_open_user_menu;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ bool User::HasAvatar() const {
|
|||||||
return Avatar.size() > 0;
|
return Avatar.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool User::HasAnimatedAvatar() const {
|
||||||
|
return Avatar.size() > 0 && Avatar[0] == 'a' && Avatar[1] == '_';
|
||||||
|
}
|
||||||
|
|
||||||
std::string User::GetAvatarURL(std::string ext, std::string size) const {
|
std::string User::GetAvatarURL(std::string ext, std::string size) const {
|
||||||
return "https://cdn.discordapp.com/avatars/" + std::to_string(ID) + "/" + Avatar + "." + ext + "?size=" + size;
|
return "https://cdn.discordapp.com/avatars/" + std::to_string(ID) + "/" + Avatar + "." + ext + "?size=" + size;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ struct User {
|
|||||||
static void update_from_json(const nlohmann::json &j, User &m);
|
static void update_from_json(const nlohmann::json &j, User &m);
|
||||||
|
|
||||||
bool HasAvatar() const;
|
bool HasAvatar() const;
|
||||||
|
bool HasAnimatedAvatar() const;
|
||||||
std::string GetAvatarURL(std::string ext = "png", std::string size = "32") const;
|
std::string GetAvatarURL(std::string ext = "png", std::string size = "32") const;
|
||||||
Snowflake GetHoistedRole(Snowflake guild_id, bool with_color = false) const;
|
Snowflake GetHoistedRole(Snowflake guild_id, bool with_color = false) const;
|
||||||
std::string GetMention() const;
|
std::string GetMention() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user