summaryrefslogtreecommitdiff
path: root/windows
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2021-02-04 23:41:53 -0500
committerouwou <26526779+ouwou@users.noreply.github.com>2021-02-04 23:41:53 -0500
commit64adcffe4272d109f296ff46fbc52eea5cf367bd (patch)
tree7df5a5ef1f0cd77541c684af5a794a1f536ff6ea /windows
parent0479bf52c2417cd983d808b6bce3f48f1551d6d9 (diff)
downloadabaddon-portaudio-64adcffe4272d109f296ff46fbc52eea5cf367bd.tar.gz
abaddon-portaudio-64adcffe4272d109f296ff46fbc52eea5cf367bd.zip
view user profile (notes+connections+badges)
change some stuff with callbacks
Diffstat (limited to 'windows')
-rw-r--r--windows/profile/userinfopane.cpp179
-rw-r--r--windows/profile/userinfopane.hpp40
-rw-r--r--windows/profilewindow.cpp124
-rw-r--r--windows/profilewindow.hpp29
4 files changed, 372 insertions, 0 deletions
diff --git a/windows/profile/userinfopane.cpp b/windows/profile/userinfopane.cpp
new file mode 100644
index 0000000..00652ad
--- /dev/null
+++ b/windows/profile/userinfopane.cpp
@@ -0,0 +1,179 @@
+#include "userinfopane.hpp"
+#include <unordered_set>
+#include "../../abaddon.hpp"
+
+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 (int i = 0; i < connections.size(); i++) {
+ const auto &conn = connections[i];
+ if (supported_services.find(conn.Type) == supported_services.end()) continue;
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf;
+ try {
+ pixbuf = Gdk::Pixbuf::create_from_file("./res/" + 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;
+ auto *ev = Gtk::manage(new Gtk::EventBox);
+ auto *box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
+ if (pixbuf) {
+ auto *img = Gtk::manage(new Gtk::Image(pixbuf));
+ img->get_style_context()->add_class("profile-connection-image");
+ box->add(*img);
+ }
+ auto *lbl = Gtk::manage(new Gtk::Label(conn.Name));
+ box->set_halign(Gtk::ALIGN_START);
+ box->set_size_request(200, -1);
+ box->get_style_context()->add_class("profile-connection");
+ lbl->get_style_context()->add_class("profile-connection-label");
+ lbl->set_valign(Gtk::ALIGN_CENTER);
+ lbl->set_single_line_mode(true);
+ lbl->set_ellipsize(Pango::ELLIPSIZE_END);
+ box->add(*lbl);
+ 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;
+ };
+ ev->signal_button_press_event().connect(sigc::track_obj(cb, *ev));
+ AddPointerCursor(*ev);
+ }
+ ev->add(*box);
+ ev->show_all();
+ attach(*ev, 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;
+}
+
+ProfileUserInfoPane::ProfileUserInfoPane(Snowflake ID)
+ : Gtk::Box(Gtk::ORIENTATION_VERTICAL)
+ , UserID(ID) {
+ get_style_context()->add_class("profile-info-pane");
+
+ m_note.signal_update_note().connect([this](const Glib::ustring &note) {
+ auto cb = [this](bool success) {
+ if (!success) {
+ 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();
+ discord.signal_note_update().connect([this](Snowflake id, std::string note) {
+ if (id == UserID)
+ m_note.SetNote(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_conns.set_halign(Gtk::ALIGN_START);
+ m_conns.set_hexpand(true);
+
+ add(m_note);
+ add(m_conns);
+ show_all_children();
+}
+
+void ProfileUserInfoPane::SetConnections(const std::vector<ConnectionData> &connections) {
+ m_conns.SetConnections(connections);
+}
diff --git a/windows/profile/userinfopane.hpp b/windows/profile/userinfopane.hpp
new file mode 100644
index 0000000..ae88c70
--- /dev/null
+++ b/windows/profile/userinfopane.hpp
@@ -0,0 +1,40 @@
+#pragma once
+#include <gtkmm.h>
+#include "../../discord/objects.hpp"
+
+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 ProfileUserInfoPane : public Gtk::Box {
+public:
+ ProfileUserInfoPane(Snowflake ID);
+ void SetConnections(const std::vector<ConnectionData> &connections);
+
+ Snowflake UserID;
+
+private:
+ NotesContainer m_note;
+ ConnectionsContainer m_conns;
+};
diff --git a/windows/profilewindow.cpp b/windows/profilewindow.cpp
new file mode 100644
index 0000000..c83fa77
--- /dev/null
+++ b/windows/profilewindow.cpp
@@ -0,0 +1,124 @@
+#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) {
+ const auto &discord = Abaddon::Get().GetDiscordClient();
+ auto user = *discord.GetUser(ID);
+
+ Abaddon::Get().GetDiscordClient().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;
+ });
+
+ auto &img = Abaddon::Get().GetImageManager();
+ m_avatar.property_pixbuf() = img.GetPlaceholder(64);
+ if (user.HasAvatar()) {
+ 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 (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_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::on_hide() {
+ Gtk::Window::on_hide();
+ delete this;
+}
+
+void ProfileWindow::OnFetchProfile(const UserProfileData &data) {
+ m_pane_info.SetConnections(data.ConnectedAccounts);
+
+ 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 {
+ pixbuf = Gdk::Pixbuf::create_from_file("./res/" + 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
new file mode 100644
index 0000000..5d4f319
--- /dev/null
+++ b/windows/profilewindow.hpp
@@ -0,0 +1,29 @@
+#pragma once
+#include <gtkmm.h>
+#include "../discord/snowflake.hpp"
+#include "profile/userinfopane.hpp"
+
+class ProfileWindow : public Gtk::Window {
+public:
+ ProfileWindow(Snowflake user_id);
+
+ void on_hide() override;
+
+ 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;
+};