diff --git a/abaddon.cpp b/abaddon.cpp
index 768141d..08e6884 100644
--- a/abaddon.cpp
+++ b/abaddon.cpp
@@ -484,10 +484,14 @@ void Abaddon::ActionSetStatus() {
const auto status = dlg.GetStatusType();
const auto activity_type = dlg.GetActivityType();
const auto activity_name = dlg.GetActivityName();
- ActivityData activity;
- activity.Name = activity_name;
- activity.Type = activity_type;
- m_discord.UpdateStatus(status, false, activity);
+ if (activity_name == "") {
+ m_discord.UpdateStatus(status, false);
+ } else {
+ ActivityData activity;
+ activity.Name = activity_name;
+ activity.Type = activity_type;
+ m_discord.UpdateStatus(status, false, activity);
+ }
}
void Abaddon::ActionReactionAdd(Snowflake id, const Glib::ustring ¶m) {
diff --git a/components/memberlist.cpp b/components/memberlist.cpp
index 0d54448..be7e074 100644
--- a/components/memberlist.cpp
+++ b/components/memberlist.cpp
@@ -1,6 +1,8 @@
#include "memberlist.hpp"
#include "../abaddon.hpp"
#include "../util.hpp"
+#include "lazyimage.hpp"
+#include "statusindicator.hpp"
MemberListUserRow::MemberListUserRow(Snowflake guild_id, const UserData *data) {
ID = data->ID;
@@ -8,6 +10,9 @@ MemberListUserRow::MemberListUserRow(Snowflake guild_id, const UserData *data) {
m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
m_label = Gtk::manage(new Gtk::Label);
m_avatar = Gtk::manage(new LazyImage(16, 16));
+ m_status_indicator = Gtk::manage(new StatusIndicator(ID));
+
+ m_status_indicator->set_margin_start(3);
if (data->HasAvatar())
m_avatar->SetURL(data->GetAvatarURL("png"));
@@ -37,8 +42,10 @@ MemberListUserRow::MemberListUserRow(Snowflake guild_id, const UserData *data) {
m_label->set_use_markup(true);
m_label->set_markup("[unknown user]");
}
+
m_label->set_halign(Gtk::ALIGN_START);
m_box->add(*m_avatar);
+ m_box->add(*m_status_indicator);
m_box->add(*m_label);
m_ev->add(*m_box);
add(*m_ev);
diff --git a/components/memberlist.hpp b/components/memberlist.hpp
index c816b26..856d73c 100644
--- a/components/memberlist.hpp
+++ b/components/memberlist.hpp
@@ -3,8 +3,9 @@
#include
#include
#include "../discord/discord.hpp"
-#include "lazyimage.hpp"
+class LazyImage;
+class StatusIndicator;
class MemberListUserRow : public Gtk::ListBoxRow {
public:
MemberListUserRow(Snowflake guild_id, const UserData *data);
@@ -15,6 +16,7 @@ private:
Gtk::EventBox *m_ev;
Gtk::Box *m_box;
LazyImage *m_avatar;
+ StatusIndicator *m_status_indicator;
Gtk::Label *m_label;
};
diff --git a/components/statusindicator.cpp b/components/statusindicator.cpp
new file mode 100644
index 0000000..abf389c
--- /dev/null
+++ b/components/statusindicator.cpp
@@ -0,0 +1,136 @@
+#include "statusindicator.hpp"
+#include "../abaddon.hpp"
+
+static const constexpr int Diameter = 8;
+static const auto OnlineColor = Gdk::RGBA("#43B581");
+static const auto IdleColor = Gdk::RGBA("#FAA61A");
+static const auto DNDColor = Gdk::RGBA("#982929");
+static const auto OfflineColor = Gdk::RGBA("#808080");
+
+StatusIndicator::StatusIndicator(Snowflake user_id)
+ : Glib::ObjectBase("statusindicator")
+ , Gtk::Widget()
+ , m_id(user_id)
+ , m_color(OfflineColor) {
+ set_has_window(true);
+ set_name("status-indicator");
+
+ Abaddon::Get().GetDiscordClient().signal_guild_member_list_update().connect(sigc::hide(sigc::mem_fun(*this, &StatusIndicator::CheckStatus)));
+ auto cb = [this](Snowflake id, PresenceStatus status) {
+ if (id == m_id) CheckStatus();
+ };
+ Abaddon::Get().GetDiscordClient().signal_presence_update().connect(sigc::track_obj(cb, *this));
+
+ CheckStatus();
+}
+
+StatusIndicator::~StatusIndicator() {
+}
+
+void StatusIndicator::CheckStatus() {
+ const auto status = Abaddon::Get().GetDiscordClient().GetUserStatus(m_id);
+ if (status.has_value()) {
+ switch (*status) {
+ case PresenceStatus::Online:
+ m_color = OnlineColor;
+ break;
+ case PresenceStatus::Offline:
+ m_color = OfflineColor;
+ break;
+ case PresenceStatus::DND:
+ m_color = DNDColor;
+ break;
+ case PresenceStatus::Idle:
+ m_color = IdleColor;
+ break;
+ }
+ } else {
+ m_color = OfflineColor;
+ }
+
+ queue_draw();
+}
+
+Gtk::SizeRequestMode StatusIndicator::get_request_mode_vfunc() const {
+ return Gtk::Widget::get_request_mode_vfunc();
+}
+
+void StatusIndicator::get_preferred_width_vfunc(int &minimum_width, int &natural_width) const {
+ minimum_width = 0;
+ natural_width = Diameter;
+}
+
+void StatusIndicator::get_preferred_height_for_width_vfunc(int width, int &minimum_height, int &natural_height) const {
+ minimum_height = 0;
+ natural_height = Diameter;
+}
+
+void StatusIndicator::get_preferred_height_vfunc(int &minimum_height, int &natural_height) const {
+ minimum_height = 0;
+ natural_height = Diameter;
+}
+
+void StatusIndicator::get_preferred_width_for_height_vfunc(int height, int &minimum_width, int &natural_width) const {
+ minimum_width = 0;
+ natural_width = Diameter;
+}
+
+void StatusIndicator::on_size_allocate(Gtk::Allocation &allocation) {
+ set_allocation(allocation);
+
+ if (m_window)
+ m_window->move_resize(allocation.get_x(), allocation.get_y(), allocation.get_width(), allocation.get_height());
+}
+
+void StatusIndicator::on_map() {
+ Gtk::Widget::on_map();
+}
+
+void StatusIndicator::on_unmap() {
+ Gtk::Widget::on_unmap();
+}
+
+void StatusIndicator::on_realize() {
+ set_realized(true);
+
+ if (!m_window) {
+ GdkWindowAttr attributes;
+ std::memset(&attributes, 0, sizeof(attributes));
+
+ auto allocation = get_allocation();
+
+ attributes.x = allocation.get_x();
+ attributes.y = allocation.get_y();
+ attributes.width = allocation.get_width();
+ attributes.height = allocation.get_height();
+
+ attributes.event_mask = get_events() | Gdk::EXPOSURE_MASK;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+
+ m_window = Gdk::Window::create(get_parent_window(), &attributes, GDK_WA_X | GDK_WA_Y);
+ set_window(m_window);
+
+ m_window->set_user_data(gobj());
+ }
+}
+
+void StatusIndicator::on_unrealize() {
+ m_window.reset();
+
+ Gtk::Widget::on_unrealize();
+}
+
+bool StatusIndicator::on_draw(const Cairo::RefPtr &cr) {
+ const auto allocation = get_allocation();
+ const auto width = allocation.get_width();
+ const auto height = allocation.get_height();
+
+ cr->set_source_rgb(m_color.get_red(), m_color.get_green(), m_color.get_blue());
+ cr->arc(width / 2, height / 2, width / 3, 0.0, 2 * (4 * std::atan(1)));
+ cr->close_path();
+ cr->fill_preserve();
+ cr->stroke();
+
+ return true;
+}
diff --git a/components/statusindicator.hpp b/components/statusindicator.hpp
new file mode 100644
index 0000000..9c7382e
--- /dev/null
+++ b/components/statusindicator.hpp
@@ -0,0 +1,30 @@
+#pragma once
+#include
+#include "../discord/snowflake.hpp"
+
+class StatusIndicator : public Gtk::Widget {
+public:
+ StatusIndicator(Snowflake user_id);
+ virtual ~StatusIndicator();
+
+protected:
+ Gtk::SizeRequestMode get_request_mode_vfunc() const override;
+ void get_preferred_width_vfunc(int &minimum_width, int &natural_width) const override;
+ void get_preferred_height_for_width_vfunc(int width, int &minimum_height, int &natural_height) const override;
+ void get_preferred_height_vfunc(int &minimum_height, int &natural_height) const override;
+ void get_preferred_width_for_height_vfunc(int height, int &minimum_width, int &natural_width) const override;
+ void on_size_allocate(Gtk::Allocation &allocation) override;
+ void on_map() override;
+ void on_unmap() override;
+ void on_realize() override;
+ void on_unrealize() override;
+ bool on_draw(const Cairo::RefPtr &cr) override;
+
+ Glib::RefPtr m_window;
+
+private:
+ void CheckStatus();
+
+ Snowflake m_id;
+ Gdk::RGBA m_color;
+};
diff --git a/dialogs/setstatus.cpp b/dialogs/setstatus.cpp
index 8fcabf4..5c9656e 100644
--- a/dialogs/setstatus.cpp
+++ b/dialogs/setstatus.cpp
@@ -54,8 +54,17 @@ ActivityType SetStatusDialog::GetActivityType() const {
return static_cast(std::stoul(x));
}
-std::string SetStatusDialog::GetStatusType() const {
- return m_status_combo.get_active_id();
+PresenceStatus SetStatusDialog::GetStatusType() const {
+ const auto &x = m_status_combo.get_active_id();
+ if (x == "online")
+ return PresenceStatus::Online;
+ else if (x == "idle")
+ return PresenceStatus::Idle;
+ else if (x == "dnd")
+ return PresenceStatus::DND;
+ else if (x == "offline")
+ return PresenceStatus::Offline;
+ return PresenceStatus::Online;
}
std::string SetStatusDialog::GetActivityName() const {
diff --git a/dialogs/setstatus.hpp b/dialogs/setstatus.hpp
index 16f0f94..97db906 100644
--- a/dialogs/setstatus.hpp
+++ b/dialogs/setstatus.hpp
@@ -6,7 +6,7 @@ class SetStatusDialog : public Gtk::Dialog {
public:
SetStatusDialog(Gtk::Window &parent);
ActivityType GetActivityType() const;
- std::string GetStatusType() const;
+ PresenceStatus GetStatusType() const;
std::string GetActivityName() const;
protected:
diff --git a/discord/activity.cpp b/discord/activity.cpp
index ff02758..95dda5d 100644
--- a/discord/activity.cpp
+++ b/discord/activity.cpp
@@ -100,9 +100,17 @@ void to_json(nlohmann::json &j, const ActivityData &m) {
JS_IF("flags", m.Flags);
}
+void from_json(const nlohmann::json &j, PresenceData &m) {
+ JS_N("activities", m.Activities);
+ JS_D("status", m.Status);
+}
+
void to_json(nlohmann::json &j, const PresenceData &m) {
j["activities"] = m.Activities;
j["status"] = m.Status;
- j["afk"] = m.IsAFK;
- j["since"] = m.Since;
+ JS_IF("afk", m.IsAFK);
+ if (m.Since.has_value())
+ j["since"] = *m.Since;
+ else
+ j["since"] = 0;
}
diff --git a/discord/activity.hpp b/discord/activity.hpp
index 1e323e3..2cbd5ce 100644
--- a/discord/activity.hpp
+++ b/discord/activity.hpp
@@ -5,6 +5,13 @@
#include "json.hpp"
#include "snowflake.hpp"
+enum class PresenceStatus : uint8_t {
+ Online,
+ Offline,
+ Idle,
+ DND,
+};
+
enum class ActivityType : int {
Game = 0,
Streaming = 1,
@@ -28,8 +35,8 @@ struct Bitwise {
};
struct ActivityTimestamps {
- std::optional Start; // opt
- std::optional End; // opt
+ std::optional Start;
+ std::optional End;
friend void from_json(const nlohmann::json &j, ActivityTimestamps &m);
friend void to_json(nlohmann::json &j, const ActivityTimestamps &m);
@@ -94,8 +101,9 @@ struct ActivityData {
struct PresenceData {
std::vector Activities; // null (but never sent as such)
std::string Status;
- bool IsAFK;
- int Since = 0;
+ std::optional IsAFK;
+ std::optional Since;
+ friend void from_json(const nlohmann::json &j, PresenceData &m);
friend void to_json(nlohmann::json &j, const PresenceData &m);
};
diff --git a/discord/discord.cpp b/discord/discord.cpp
index 382e3ac..df326d8 100644
--- a/discord/discord.cpp
+++ b/discord/discord.cpp
@@ -401,13 +401,26 @@ void DiscordClient::BanUser(Snowflake user_id, Snowflake guild_id) {
m_http.MakePUT("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), "{}", [](auto) {});
}
-void DiscordClient::UpdateStatus(const std::string &status, bool is_afk, const ActivityData &obj) {
+void DiscordClient::UpdateStatus(PresenceStatus status, bool is_afk) {
UpdateStatusMessage msg;
- msg.Presence.Status = status;
- msg.Presence.IsAFK = is_afk;
- msg.Presence.Activities.push_back(obj);
+ msg.Status = status;
+ msg.IsAFK = is_afk;
m_websocket.Send(nlohmann::json(msg));
+ // fake message cuz we dont receive messages for ourself
+ m_user_to_status[m_user_data.ID] = status;
+ m_signal_presence_update.emit(m_user_data.ID, status);
+}
+
+void DiscordClient::UpdateStatus(PresenceStatus status, bool is_afk, const ActivityData &obj) {
+ UpdateStatusMessage msg;
+ msg.Status = status;
+ msg.IsAFK = is_afk;
+ msg.Activities.push_back(obj);
+
+ m_websocket.Send(nlohmann::json(msg));
+ m_user_to_status[m_user_data.ID] = status;
+ m_signal_presence_update.emit(m_user_data.ID, status);
}
void DiscordClient::CreateDM(Snowflake user_id) {
@@ -589,6 +602,14 @@ void DiscordClient::SetUserAgent(std::string agent) {
m_websocket.SetUserAgent(agent);
}
+std::optional DiscordClient::GetUserStatus(Snowflake id) const {
+ auto it = m_user_to_status.find(id);
+ if (it != m_user_to_status.end())
+ return it->second;
+
+ return std::nullopt;
+}
+
void DiscordClient::HandleGatewayMessageRaw(std::string str) {
// handles multiple zlib compressed messages, calling HandleGatewayMessage when a full message is received
std::vector buf(str.begin(), str.end());
@@ -882,11 +903,27 @@ void DiscordClient::HandleGatewayGuildMemberUpdate(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayPresenceUpdate(const GatewayMessage &msg) {
PresenceUpdateMessage data = msg.Data;
- auto cur = m_store.GetUser(data.User.at("id").get());
+ const auto user_id = data.User.at("id").get();
+
+ auto cur = m_store.GetUser(user_id);
if (cur.has_value()) {
- UserData::update_from_json(data.User, *cur);
+ cur->update_from_json(data.User);
m_store.SetUser(cur->ID, *cur);
}
+
+ PresenceStatus e;
+ if (data.StatusMessage == "online")
+ e = PresenceStatus::Online;
+ else if (data.StatusMessage == "offline")
+ e = PresenceStatus::Offline;
+ else if (data.StatusMessage == "idle")
+ e = PresenceStatus::Idle;
+ else if (data.StatusMessage == "dnd")
+ e = PresenceStatus::DND;
+
+ m_user_to_status[user_id] = e;
+
+ m_signal_presence_update.emit(user_id, e);
}
void DiscordClient::HandleGatewayChannelDelete(const GatewayMessage &msg) {
@@ -1178,6 +1215,17 @@ void DiscordClient::HandleGatewayGuildMemberListUpdate(const GatewayMessage &msg
m_store.SetUser(member->User.ID, member->User);
AddUserToGuild(member->User.ID, data.GuildID);
m_store.SetGuildMember(data.GuildID, member->User.ID, member->GetAsMemberData());
+ if (member->Presence.has_value()) {
+ const auto &s = member->Presence->Status;
+ if (s == "online")
+ m_user_to_status[member->User.ID] = PresenceStatus::Online;
+ else if (s == "offline")
+ m_user_to_status[member->User.ID] = PresenceStatus::Offline;
+ else if (s == "idle")
+ m_user_to_status[member->User.ID] = PresenceStatus::Idle;
+ else if (s == "dnd")
+ m_user_to_status[member->User.ID] = PresenceStatus::DND;
+ }
}
}
}
@@ -1476,3 +1524,7 @@ DiscordClient::type_signal_invite_create DiscordClient::signal_invite_create() {
DiscordClient::type_signal_invite_delete DiscordClient::signal_invite_delete() {
return m_signal_invite_delete;
}
+
+DiscordClient::type_signal_presence_update DiscordClient::signal_presence_update() {
+ return m_signal_presence_update;
+}
diff --git a/discord/discord.hpp b/discord/discord.hpp
index cef811e..d585e39 100644
--- a/discord/discord.hpp
+++ b/discord/discord.hpp
@@ -105,7 +105,8 @@ public:
void LeaveGuild(Snowflake id);
void KickUser(Snowflake user_id, Snowflake guild_id);
void BanUser(Snowflake user_id, Snowflake guild_id); // todo: reason, delete messages
- void UpdateStatus(const std::string &status, bool is_afk, const ActivityData &obj);
+ void UpdateStatus(PresenceStatus status, bool is_afk);
+ void UpdateStatus(PresenceStatus status, bool is_afk, const ActivityData &obj);
void CreateDM(Snowflake user_id);
std::optional FindDM(Snowflake user_id); // wont find group dms
void AddReaction(Snowflake id, Glib::ustring param);
@@ -132,6 +133,8 @@ public:
void UpdateToken(std::string token);
void SetUserAgent(std::string agent);
+ std::optional GetUserStatus(Snowflake id) const;
+
private:
static const constexpr int InflateChunkSize = 0x10000;
std::vector m_compressed_buf;
@@ -192,6 +195,8 @@ private:
std::unordered_map> m_guild_to_channels;
+ std::unordered_map m_user_to_status;
+
UserData m_user_data;
UserSettings m_user_settings;
@@ -246,6 +251,7 @@ public:
typedef sigc::signal type_signal_guild_ban_add; // guild id, user id
typedef sigc::signal type_signal_invite_create;
typedef sigc::signal type_signal_invite_delete;
+ typedef sigc::signal type_signal_presence_update;
typedef sigc::signal type_signal_disconnected; // bool true if reconnecting
typedef sigc::signal type_signal_connected;
@@ -271,6 +277,7 @@ public:
type_signal_guild_ban_add signal_guild_ban_add();
type_signal_invite_create signal_invite_create();
type_signal_invite_delete signal_invite_delete(); // safe to assume guild id is set
+ type_signal_presence_update signal_presence_update();
type_signal_disconnected signal_disconnected();
type_signal_connected signal_connected();
@@ -297,6 +304,7 @@ protected:
type_signal_guild_ban_add m_signal_guild_ban_add;
type_signal_invite_create m_signal_invite_create;
type_signal_invite_delete m_signal_invite_delete;
+ type_signal_presence_update m_signal_presence_update;
type_signal_disconnected m_signal_disconnected;
type_signal_connected m_signal_connected;
};
diff --git a/discord/objects.cpp b/discord/objects.cpp
index 4cc03e0..b08f796 100644
--- a/discord/objects.cpp
+++ b/discord/objects.cpp
@@ -44,6 +44,7 @@ void from_json(const nlohmann::json &j, GuildMemberListUpdateMessage::MemberItem
JS_N("hoisted_role", m.HoistedRole);
JS_ON("premium_since", m.PremiumSince);
JS_ON("nick", m.Nickname);
+ JS_ON("presence", m.Presence);
m.m_member_data = j;
}
@@ -85,7 +86,24 @@ void to_json(nlohmann::json &j, const LazyLoadRequestMessage &m) {
void to_json(nlohmann::json &j, const UpdateStatusMessage &m) {
j["op"] = GatewayOp::UpdateStatus;
- j["d"] = m.Presence;
+ j["d"] = nlohmann::json::object();
+ j["d"]["since"] = m.Since;
+ j["d"]["activities"] = m.Activities;
+ j["d"]["afk"] = m.IsAFK;
+ switch (m.Status) {
+ case PresenceStatus::Online:
+ j["d"]["status"] = "online";
+ break;
+ case PresenceStatus::Offline:
+ j["d"]["status"] = "offline";
+ break;
+ case PresenceStatus::Idle:
+ j["d"]["status"] = "idle";
+ break;
+ case PresenceStatus::DND:
+ j["d"]["status"] = "dnd";
+ break;
+ }
}
void from_json(const nlohmann::json &j, ReadyEventData &m) {
@@ -170,7 +188,7 @@ void from_json(const nlohmann::json &j, GuildMemberUpdateMessage &m) {
JS_D("joined_at", m.JoinedAt);
}
-void from_json(const nlohmann::json &j, ClientStatus &m) {
+void from_json(const nlohmann::json &j, ClientStatusData &m) {
JS_O("desktop", m.Desktop);
JS_O("mobile", m.Mobile);
JS_O("web", m.Web);
@@ -180,8 +198,8 @@ void from_json(const nlohmann::json &j, PresenceUpdateMessage &m) {
m.User = j.at("user");
JS_O("guild_id", m.GuildID);
JS_D("status", m.StatusMessage);
- // JS_D("activities", m.Activities);
- JS_D("client_status", m.Status);
+ JS_D("activities", m.Activities);
+ JS_D("client_status", m.ClientStatus);
}
void to_json(nlohmann::json &j, const CreateDMObject &m) {
diff --git a/discord/objects.hpp b/discord/objects.hpp
index e7e574c..0b3e92d 100644
--- a/discord/objects.hpp
+++ b/discord/objects.hpp
@@ -129,15 +129,15 @@ struct GuildMemberListUpdateMessage {
};
struct MemberItem : Item {
- UserData User; //
- std::vector Roles; //
- // PresenceData Presence; //
+ UserData User;
+ std::vector Roles;
+ std::optional Presence;
std::string PremiumSince; // opt
std::string Nickname; // opt
- bool IsMuted; //
- std::string JoinedAt; //
- std::string HoistedRole; // null
- bool IsDefeaned; //
+ bool IsMuted;
+ std::string JoinedAt;
+ std::string HoistedRole; // null
+ bool IsDefeaned;
GuildMember GetAsMemberData() const;
@@ -177,7 +177,10 @@ struct LazyLoadRequestMessage {
};
struct UpdateStatusMessage {
- PresenceData Presence;
+ int Since = 0;
+ std::vector Activities;
+ PresenceStatus Status;
+ bool IsAFK = false;
friend void to_json(nlohmann::json &j, const UpdateStatusMessage &m);
};
@@ -278,20 +281,20 @@ struct GuildMemberUpdateMessage {
friend void from_json(const nlohmann::json &j, GuildMemberUpdateMessage &m);
};
-struct ClientStatus {
- std::string Desktop; // opt
- std::string Mobile; // opt
- std::string Web; // opt
+struct ClientStatusData {
+ std::optional Desktop;
+ std::optional Mobile;
+ std::optional Web;
- friend void from_json(const nlohmann::json &j, ClientStatus &m);
+ friend void from_json(const nlohmann::json &j, ClientStatusData &m);
};
struct PresenceUpdateMessage {
nlohmann::json User; // the client updates an existing object from this data
- Snowflake GuildID; // opt
+ std::optional GuildID;
std::string StatusMessage;
- // std::vector Activities;
- ClientStatus Status;
+ std::vector Activities;
+ ClientStatusData ClientStatus;
friend void from_json(const nlohmann::json &j, PresenceUpdateMessage &m);
};
diff --git a/discord/user.cpp b/discord/user.cpp
index 443365d..fc7995e 100644
--- a/discord/user.cpp
+++ b/discord/user.cpp
@@ -68,21 +68,21 @@ void to_json(nlohmann::json &j, const UserData &m) {
JS_IF("phone", m.Phone);
}
-void UserData::update_from_json(const nlohmann::json &j, UserData &m) {
- JS_RD("username", m.Username);
- JS_RD("discriminator", m.Discriminator);
- JS_RD("avatar", m.Avatar);
- JS_RD("bot", m.IsBot);
- JS_RD("system", m.IsSystem);
- JS_RD("mfa_enabled", m.IsMFAEnabled);
- JS_RD("locale", m.Locale);
- JS_RD("verified", m.IsVerified);
- JS_RD("email", m.Email);
- JS_RD("flags", m.Flags);
- JS_RD("premium_type", m.PremiumType);
- JS_RD("public_flags", m.PublicFlags);
- JS_RD("desktop", m.IsDesktop);
- JS_RD("mobile", m.IsMobile);
- JS_RD("nsfw_allowed", m.IsNSFWAllowed);
- JS_RD("phone", m.Phone);
+void UserData::update_from_json(const nlohmann::json &j) {
+ JS_RD("username", Username);
+ JS_RD("discriminator", Discriminator);
+ JS_RD("avatar", Avatar);
+ JS_RD("bot", IsBot);
+ JS_RD("system", IsSystem);
+ JS_RD("mfa_enabled", IsMFAEnabled);
+ JS_RD("locale", Locale);
+ JS_RD("verified", IsVerified);
+ JS_RD("email", Email);
+ JS_RD("flags", Flags);
+ JS_RD("premium_type", PremiumType);
+ JS_RD("public_flags", PublicFlags);
+ JS_RD("desktop", IsDesktop);
+ JS_RD("mobile", IsMobile);
+ JS_RD("nsfw_allowed", IsNSFWAllowed);
+ JS_RD("phone", Phone);
}
diff --git a/discord/user.hpp b/discord/user.hpp
index b82a07b..4e6461e 100644
--- a/discord/user.hpp
+++ b/discord/user.hpp
@@ -26,7 +26,7 @@ struct UserData {
friend void from_json(const nlohmann::json &j, UserData &m);
friend void to_json(nlohmann::json &j, const UserData &m);
- static void update_from_json(const nlohmann::json &j, UserData &m);
+ void update_from_json(const nlohmann::json &j);
bool HasAvatar() const;
bool HasAnimatedAvatar() const;