forked from OpenGamers/abaddon
show status indicators in member list, change some other shit with presences
This commit is contained in:
12
abaddon.cpp
12
abaddon.cpp
@@ -484,10 +484,14 @@ void Abaddon::ActionSetStatus() {
|
|||||||
const auto status = dlg.GetStatusType();
|
const auto status = dlg.GetStatusType();
|
||||||
const auto activity_type = dlg.GetActivityType();
|
const auto activity_type = dlg.GetActivityType();
|
||||||
const auto activity_name = dlg.GetActivityName();
|
const auto activity_name = dlg.GetActivityName();
|
||||||
ActivityData activity;
|
if (activity_name == "") {
|
||||||
activity.Name = activity_name;
|
m_discord.UpdateStatus(status, false);
|
||||||
activity.Type = activity_type;
|
} else {
|
||||||
m_discord.UpdateStatus(status, false, activity);
|
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) {
|
void Abaddon::ActionReactionAdd(Snowflake id, const Glib::ustring ¶m) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "memberlist.hpp"
|
#include "memberlist.hpp"
|
||||||
#include "../abaddon.hpp"
|
#include "../abaddon.hpp"
|
||||||
#include "../util.hpp"
|
#include "../util.hpp"
|
||||||
|
#include "lazyimage.hpp"
|
||||||
|
#include "statusindicator.hpp"
|
||||||
|
|
||||||
MemberListUserRow::MemberListUserRow(Snowflake guild_id, const UserData *data) {
|
MemberListUserRow::MemberListUserRow(Snowflake guild_id, const UserData *data) {
|
||||||
ID = data->ID;
|
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_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
|
||||||
m_label = Gtk::manage(new Gtk::Label);
|
m_label = Gtk::manage(new Gtk::Label);
|
||||||
m_avatar = Gtk::manage(new LazyImage(16, 16));
|
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())
|
if (data->HasAvatar())
|
||||||
m_avatar->SetURL(data->GetAvatarURL("png"));
|
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_use_markup(true);
|
||||||
m_label->set_markup("<i>[unknown user]</i>");
|
m_label->set_markup("<i>[unknown user]</i>");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_label->set_halign(Gtk::ALIGN_START);
|
m_label->set_halign(Gtk::ALIGN_START);
|
||||||
m_box->add(*m_avatar);
|
m_box->add(*m_avatar);
|
||||||
|
m_box->add(*m_status_indicator);
|
||||||
m_box->add(*m_label);
|
m_box->add(*m_label);
|
||||||
m_ev->add(*m_box);
|
m_ev->add(*m_box);
|
||||||
add(*m_ev);
|
add(*m_ev);
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "../discord/discord.hpp"
|
#include "../discord/discord.hpp"
|
||||||
#include "lazyimage.hpp"
|
|
||||||
|
|
||||||
|
class LazyImage;
|
||||||
|
class StatusIndicator;
|
||||||
class MemberListUserRow : public Gtk::ListBoxRow {
|
class MemberListUserRow : public Gtk::ListBoxRow {
|
||||||
public:
|
public:
|
||||||
MemberListUserRow(Snowflake guild_id, const UserData *data);
|
MemberListUserRow(Snowflake guild_id, const UserData *data);
|
||||||
@@ -15,6 +16,7 @@ private:
|
|||||||
Gtk::EventBox *m_ev;
|
Gtk::EventBox *m_ev;
|
||||||
Gtk::Box *m_box;
|
Gtk::Box *m_box;
|
||||||
LazyImage *m_avatar;
|
LazyImage *m_avatar;
|
||||||
|
StatusIndicator *m_status_indicator;
|
||||||
Gtk::Label *m_label;
|
Gtk::Label *m_label;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
136
components/statusindicator.cpp
Normal file
136
components/statusindicator.cpp
Normal file
@@ -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<Cairo::Context> &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;
|
||||||
|
}
|
||||||
30
components/statusindicator.hpp
Normal file
30
components/statusindicator.hpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <gtkmm.h>
|
||||||
|
#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<Cairo::Context> &cr) override;
|
||||||
|
|
||||||
|
Glib::RefPtr<Gdk::Window> m_window;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CheckStatus();
|
||||||
|
|
||||||
|
Snowflake m_id;
|
||||||
|
Gdk::RGBA m_color;
|
||||||
|
};
|
||||||
@@ -54,8 +54,17 @@ ActivityType SetStatusDialog::GetActivityType() const {
|
|||||||
return static_cast<ActivityType>(std::stoul(x));
|
return static_cast<ActivityType>(std::stoul(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SetStatusDialog::GetStatusType() const {
|
PresenceStatus SetStatusDialog::GetStatusType() const {
|
||||||
return m_status_combo.get_active_id();
|
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 {
|
std::string SetStatusDialog::GetActivityName() const {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class SetStatusDialog : public Gtk::Dialog {
|
|||||||
public:
|
public:
|
||||||
SetStatusDialog(Gtk::Window &parent);
|
SetStatusDialog(Gtk::Window &parent);
|
||||||
ActivityType GetActivityType() const;
|
ActivityType GetActivityType() const;
|
||||||
std::string GetStatusType() const;
|
PresenceStatus GetStatusType() const;
|
||||||
std::string GetActivityName() const;
|
std::string GetActivityName() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -100,9 +100,17 @@ void to_json(nlohmann::json &j, const ActivityData &m) {
|
|||||||
JS_IF("flags", m.Flags);
|
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) {
|
void to_json(nlohmann::json &j, const PresenceData &m) {
|
||||||
j["activities"] = m.Activities;
|
j["activities"] = m.Activities;
|
||||||
j["status"] = m.Status;
|
j["status"] = m.Status;
|
||||||
j["afk"] = m.IsAFK;
|
JS_IF("afk", m.IsAFK);
|
||||||
j["since"] = m.Since;
|
if (m.Since.has_value())
|
||||||
|
j["since"] = *m.Since;
|
||||||
|
else
|
||||||
|
j["since"] = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,13 @@
|
|||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#include "snowflake.hpp"
|
#include "snowflake.hpp"
|
||||||
|
|
||||||
|
enum class PresenceStatus : uint8_t {
|
||||||
|
Online,
|
||||||
|
Offline,
|
||||||
|
Idle,
|
||||||
|
DND,
|
||||||
|
};
|
||||||
|
|
||||||
enum class ActivityType : int {
|
enum class ActivityType : int {
|
||||||
Game = 0,
|
Game = 0,
|
||||||
Streaming = 1,
|
Streaming = 1,
|
||||||
@@ -28,8 +35,8 @@ struct Bitwise<ActivityFlags> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ActivityTimestamps {
|
struct ActivityTimestamps {
|
||||||
std::optional<std::string> Start; // opt
|
std::optional<int> Start;
|
||||||
std::optional<std::string> End; // opt
|
std::optional<int> End;
|
||||||
|
|
||||||
friend void from_json(const nlohmann::json &j, ActivityTimestamps &m);
|
friend void from_json(const nlohmann::json &j, ActivityTimestamps &m);
|
||||||
friend void to_json(nlohmann::json &j, const ActivityTimestamps &m);
|
friend void to_json(nlohmann::json &j, const ActivityTimestamps &m);
|
||||||
@@ -94,8 +101,9 @@ struct ActivityData {
|
|||||||
struct PresenceData {
|
struct PresenceData {
|
||||||
std::vector<ActivityData> Activities; // null (but never sent as such)
|
std::vector<ActivityData> Activities; // null (but never sent as such)
|
||||||
std::string Status;
|
std::string Status;
|
||||||
bool IsAFK;
|
std::optional<bool> IsAFK;
|
||||||
int Since = 0;
|
std::optional<int> Since;
|
||||||
|
|
||||||
|
friend void from_json(const nlohmann::json &j, PresenceData &m);
|
||||||
friend void to_json(nlohmann::json &j, const PresenceData &m);
|
friend void to_json(nlohmann::json &j, const PresenceData &m);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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) {});
|
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;
|
UpdateStatusMessage msg;
|
||||||
msg.Presence.Status = status;
|
msg.Status = status;
|
||||||
msg.Presence.IsAFK = is_afk;
|
msg.IsAFK = is_afk;
|
||||||
msg.Presence.Activities.push_back(obj);
|
|
||||||
|
|
||||||
m_websocket.Send(nlohmann::json(msg));
|
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) {
|
void DiscordClient::CreateDM(Snowflake user_id) {
|
||||||
@@ -589,6 +602,14 @@ void DiscordClient::SetUserAgent(std::string agent) {
|
|||||||
m_websocket.SetUserAgent(agent);
|
m_websocket.SetUserAgent(agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<PresenceStatus> 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) {
|
void DiscordClient::HandleGatewayMessageRaw(std::string str) {
|
||||||
// handles multiple zlib compressed messages, calling HandleGatewayMessage when a full message is received
|
// handles multiple zlib compressed messages, calling HandleGatewayMessage when a full message is received
|
||||||
std::vector<uint8_t> buf(str.begin(), str.end());
|
std::vector<uint8_t> buf(str.begin(), str.end());
|
||||||
@@ -882,11 +903,27 @@ void DiscordClient::HandleGatewayGuildMemberUpdate(const GatewayMessage &msg) {
|
|||||||
|
|
||||||
void DiscordClient::HandleGatewayPresenceUpdate(const GatewayMessage &msg) {
|
void DiscordClient::HandleGatewayPresenceUpdate(const GatewayMessage &msg) {
|
||||||
PresenceUpdateMessage data = msg.Data;
|
PresenceUpdateMessage data = msg.Data;
|
||||||
auto cur = m_store.GetUser(data.User.at("id").get<Snowflake>());
|
const auto user_id = data.User.at("id").get<Snowflake>();
|
||||||
|
|
||||||
|
auto cur = m_store.GetUser(user_id);
|
||||||
if (cur.has_value()) {
|
if (cur.has_value()) {
|
||||||
UserData::update_from_json(data.User, *cur);
|
cur->update_from_json(data.User);
|
||||||
m_store.SetUser(cur->ID, *cur);
|
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) {
|
void DiscordClient::HandleGatewayChannelDelete(const GatewayMessage &msg) {
|
||||||
@@ -1178,6 +1215,17 @@ void DiscordClient::HandleGatewayGuildMemberListUpdate(const GatewayMessage &msg
|
|||||||
m_store.SetUser(member->User.ID, member->User);
|
m_store.SetUser(member->User.ID, member->User);
|
||||||
AddUserToGuild(member->User.ID, data.GuildID);
|
AddUserToGuild(member->User.ID, data.GuildID);
|
||||||
m_store.SetGuildMember(data.GuildID, member->User.ID, member->GetAsMemberData());
|
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() {
|
DiscordClient::type_signal_invite_delete DiscordClient::signal_invite_delete() {
|
||||||
return m_signal_invite_delete;
|
return m_signal_invite_delete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiscordClient::type_signal_presence_update DiscordClient::signal_presence_update() {
|
||||||
|
return m_signal_presence_update;
|
||||||
|
}
|
||||||
|
|||||||
@@ -105,7 +105,8 @@ public:
|
|||||||
void LeaveGuild(Snowflake id);
|
void LeaveGuild(Snowflake id);
|
||||||
void KickUser(Snowflake user_id, Snowflake guild_id);
|
void KickUser(Snowflake user_id, Snowflake guild_id);
|
||||||
void BanUser(Snowflake user_id, Snowflake guild_id); // todo: reason, delete messages
|
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);
|
void CreateDM(Snowflake user_id);
|
||||||
std::optional<Snowflake> FindDM(Snowflake user_id); // wont find group dms
|
std::optional<Snowflake> FindDM(Snowflake user_id); // wont find group dms
|
||||||
void AddReaction(Snowflake id, Glib::ustring param);
|
void AddReaction(Snowflake id, Glib::ustring param);
|
||||||
@@ -132,6 +133,8 @@ public:
|
|||||||
void UpdateToken(std::string token);
|
void UpdateToken(std::string token);
|
||||||
void SetUserAgent(std::string agent);
|
void SetUserAgent(std::string agent);
|
||||||
|
|
||||||
|
std::optional<PresenceStatus> GetUserStatus(Snowflake id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const constexpr int InflateChunkSize = 0x10000;
|
static const constexpr int InflateChunkSize = 0x10000;
|
||||||
std::vector<uint8_t> m_compressed_buf;
|
std::vector<uint8_t> m_compressed_buf;
|
||||||
@@ -192,6 +195,8 @@ private:
|
|||||||
|
|
||||||
std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_guild_to_channels;
|
std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_guild_to_channels;
|
||||||
|
|
||||||
|
std::unordered_map<Snowflake, PresenceStatus> m_user_to_status;
|
||||||
|
|
||||||
UserData m_user_data;
|
UserData m_user_data;
|
||||||
UserSettings m_user_settings;
|
UserSettings m_user_settings;
|
||||||
|
|
||||||
@@ -246,6 +251,7 @@ public:
|
|||||||
typedef sigc::signal<void, Snowflake, Snowflake> type_signal_guild_ban_add; // guild id, user id
|
typedef sigc::signal<void, Snowflake, Snowflake> type_signal_guild_ban_add; // guild id, user id
|
||||||
typedef sigc::signal<void, InviteData> type_signal_invite_create;
|
typedef sigc::signal<void, InviteData> type_signal_invite_create;
|
||||||
typedef sigc::signal<void, InviteDeleteObject> type_signal_invite_delete;
|
typedef sigc::signal<void, InviteDeleteObject> type_signal_invite_delete;
|
||||||
|
typedef sigc::signal<void, Snowflake, PresenceStatus> type_signal_presence_update;
|
||||||
typedef sigc::signal<void, bool, GatewayCloseCode> type_signal_disconnected; // bool true if reconnecting
|
typedef sigc::signal<void, bool, GatewayCloseCode> type_signal_disconnected; // bool true if reconnecting
|
||||||
typedef sigc::signal<void> type_signal_connected;
|
typedef sigc::signal<void> type_signal_connected;
|
||||||
|
|
||||||
@@ -271,6 +277,7 @@ public:
|
|||||||
type_signal_guild_ban_add signal_guild_ban_add();
|
type_signal_guild_ban_add signal_guild_ban_add();
|
||||||
type_signal_invite_create signal_invite_create();
|
type_signal_invite_create signal_invite_create();
|
||||||
type_signal_invite_delete signal_invite_delete(); // safe to assume guild id is set
|
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_disconnected signal_disconnected();
|
||||||
type_signal_connected signal_connected();
|
type_signal_connected signal_connected();
|
||||||
|
|
||||||
@@ -297,6 +304,7 @@ protected:
|
|||||||
type_signal_guild_ban_add m_signal_guild_ban_add;
|
type_signal_guild_ban_add m_signal_guild_ban_add;
|
||||||
type_signal_invite_create m_signal_invite_create;
|
type_signal_invite_create m_signal_invite_create;
|
||||||
type_signal_invite_delete m_signal_invite_delete;
|
type_signal_invite_delete m_signal_invite_delete;
|
||||||
|
type_signal_presence_update m_signal_presence_update;
|
||||||
type_signal_disconnected m_signal_disconnected;
|
type_signal_disconnected m_signal_disconnected;
|
||||||
type_signal_connected m_signal_connected;
|
type_signal_connected m_signal_connected;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ void from_json(const nlohmann::json &j, GuildMemberListUpdateMessage::MemberItem
|
|||||||
JS_N("hoisted_role", m.HoistedRole);
|
JS_N("hoisted_role", m.HoistedRole);
|
||||||
JS_ON("premium_since", m.PremiumSince);
|
JS_ON("premium_since", m.PremiumSince);
|
||||||
JS_ON("nick", m.Nickname);
|
JS_ON("nick", m.Nickname);
|
||||||
|
JS_ON("presence", m.Presence);
|
||||||
m.m_member_data = j;
|
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) {
|
void to_json(nlohmann::json &j, const UpdateStatusMessage &m) {
|
||||||
j["op"] = GatewayOp::UpdateStatus;
|
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) {
|
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);
|
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("desktop", m.Desktop);
|
||||||
JS_O("mobile", m.Mobile);
|
JS_O("mobile", m.Mobile);
|
||||||
JS_O("web", m.Web);
|
JS_O("web", m.Web);
|
||||||
@@ -180,8 +198,8 @@ void from_json(const nlohmann::json &j, PresenceUpdateMessage &m) {
|
|||||||
m.User = j.at("user");
|
m.User = j.at("user");
|
||||||
JS_O("guild_id", m.GuildID);
|
JS_O("guild_id", m.GuildID);
|
||||||
JS_D("status", m.StatusMessage);
|
JS_D("status", m.StatusMessage);
|
||||||
// JS_D("activities", m.Activities);
|
JS_D("activities", m.Activities);
|
||||||
JS_D("client_status", m.Status);
|
JS_D("client_status", m.ClientStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void to_json(nlohmann::json &j, const CreateDMObject &m) {
|
void to_json(nlohmann::json &j, const CreateDMObject &m) {
|
||||||
|
|||||||
@@ -129,15 +129,15 @@ struct GuildMemberListUpdateMessage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MemberItem : Item {
|
struct MemberItem : Item {
|
||||||
UserData User; //
|
UserData User;
|
||||||
std::vector<Snowflake> Roles; //
|
std::vector<Snowflake> Roles;
|
||||||
// PresenceData Presence; //
|
std::optional<PresenceData> Presence;
|
||||||
std::string PremiumSince; // opt
|
std::string PremiumSince; // opt
|
||||||
std::string Nickname; // opt
|
std::string Nickname; // opt
|
||||||
bool IsMuted; //
|
bool IsMuted;
|
||||||
std::string JoinedAt; //
|
std::string JoinedAt;
|
||||||
std::string HoistedRole; // null
|
std::string HoistedRole; // null
|
||||||
bool IsDefeaned; //
|
bool IsDefeaned;
|
||||||
|
|
||||||
GuildMember GetAsMemberData() const;
|
GuildMember GetAsMemberData() const;
|
||||||
|
|
||||||
@@ -177,7 +177,10 @@ struct LazyLoadRequestMessage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateStatusMessage {
|
struct UpdateStatusMessage {
|
||||||
PresenceData Presence;
|
int Since = 0;
|
||||||
|
std::vector<ActivityData> Activities;
|
||||||
|
PresenceStatus Status;
|
||||||
|
bool IsAFK = false;
|
||||||
|
|
||||||
friend void to_json(nlohmann::json &j, const UpdateStatusMessage &m);
|
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);
|
friend void from_json(const nlohmann::json &j, GuildMemberUpdateMessage &m);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClientStatus {
|
struct ClientStatusData {
|
||||||
std::string Desktop; // opt
|
std::optional<std::string> Desktop;
|
||||||
std::string Mobile; // opt
|
std::optional<std::string> Mobile;
|
||||||
std::string Web; // opt
|
std::optional<std::string> Web;
|
||||||
|
|
||||||
friend void from_json(const nlohmann::json &j, ClientStatus &m);
|
friend void from_json(const nlohmann::json &j, ClientStatusData &m);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PresenceUpdateMessage {
|
struct PresenceUpdateMessage {
|
||||||
nlohmann::json User; // the client updates an existing object from this data
|
nlohmann::json User; // the client updates an existing object from this data
|
||||||
Snowflake GuildID; // opt
|
std::optional<Snowflake> GuildID;
|
||||||
std::string StatusMessage;
|
std::string StatusMessage;
|
||||||
// std::vector<ActivityData> Activities;
|
std::vector<ActivityData> Activities;
|
||||||
ClientStatus Status;
|
ClientStatusData ClientStatus;
|
||||||
|
|
||||||
friend void from_json(const nlohmann::json &j, PresenceUpdateMessage &m);
|
friend void from_json(const nlohmann::json &j, PresenceUpdateMessage &m);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,21 +68,21 @@ void to_json(nlohmann::json &j, const UserData &m) {
|
|||||||
JS_IF("phone", m.Phone);
|
JS_IF("phone", m.Phone);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserData::update_from_json(const nlohmann::json &j, UserData &m) {
|
void UserData::update_from_json(const nlohmann::json &j) {
|
||||||
JS_RD("username", m.Username);
|
JS_RD("username", Username);
|
||||||
JS_RD("discriminator", m.Discriminator);
|
JS_RD("discriminator", Discriminator);
|
||||||
JS_RD("avatar", m.Avatar);
|
JS_RD("avatar", Avatar);
|
||||||
JS_RD("bot", m.IsBot);
|
JS_RD("bot", IsBot);
|
||||||
JS_RD("system", m.IsSystem);
|
JS_RD("system", IsSystem);
|
||||||
JS_RD("mfa_enabled", m.IsMFAEnabled);
|
JS_RD("mfa_enabled", IsMFAEnabled);
|
||||||
JS_RD("locale", m.Locale);
|
JS_RD("locale", Locale);
|
||||||
JS_RD("verified", m.IsVerified);
|
JS_RD("verified", IsVerified);
|
||||||
JS_RD("email", m.Email);
|
JS_RD("email", Email);
|
||||||
JS_RD("flags", m.Flags);
|
JS_RD("flags", Flags);
|
||||||
JS_RD("premium_type", m.PremiumType);
|
JS_RD("premium_type", PremiumType);
|
||||||
JS_RD("public_flags", m.PublicFlags);
|
JS_RD("public_flags", PublicFlags);
|
||||||
JS_RD("desktop", m.IsDesktop);
|
JS_RD("desktop", IsDesktop);
|
||||||
JS_RD("mobile", m.IsMobile);
|
JS_RD("mobile", IsMobile);
|
||||||
JS_RD("nsfw_allowed", m.IsNSFWAllowed);
|
JS_RD("nsfw_allowed", IsNSFWAllowed);
|
||||||
JS_RD("phone", m.Phone);
|
JS_RD("phone", Phone);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ struct UserData {
|
|||||||
|
|
||||||
friend void from_json(const nlohmann::json &j, UserData &m);
|
friend void from_json(const nlohmann::json &j, UserData &m);
|
||||||
friend void to_json(nlohmann::json &j, const 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 HasAvatar() const;
|
||||||
bool HasAnimatedAvatar() const;
|
bool HasAnimatedAvatar() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user