forked from OpenGamers/abaddon
basic unread indicators for channels
This commit is contained in:
parent
2461406887
commit
af56784797
@ -1,21 +1,21 @@
|
||||
#include "channels.hpp"
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include "abaddon.hpp"
|
||||
#include "imgmanager.hpp"
|
||||
#include "util.hpp"
|
||||
#include "statusindicator.hpp"
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
ChannelList::ChannelList()
|
||||
: Glib::ObjectBase(typeid(ChannelList))
|
||||
, Gtk::ScrolledWindow()
|
||||
, m_model(Gtk::TreeStore::create(m_columns))
|
||||
, m_menu_guild_copy_id("_Copy ID", true)
|
||||
, m_menu_guild_settings("View _Settings", true)
|
||||
, m_menu_guild_leave("_Leave", true)
|
||||
, m_menu_category_copy_id("_Copy ID", true)
|
||||
, m_menu_channel_copy_id("_Copy ID", true)
|
||||
, m_menu_channel_mark_as_read("Mark as _Read", true)
|
||||
, m_menu_dm_copy_id("_Copy ID", true)
|
||||
, m_menu_dm_close("") // changes depending on if group or not
|
||||
, m_menu_thread_copy_id("_Copy ID", true)
|
||||
@ -24,6 +24,7 @@ ChannelList::ChannelList()
|
||||
, m_menu_thread_unarchive("_Unarchive", true) {
|
||||
get_style_context()->add_class("channel-list");
|
||||
|
||||
// todo: move to method
|
||||
const auto cb = [this](const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column) {
|
||||
auto row = *m_model->get_iter(path);
|
||||
const auto type = row[m_columns.m_type];
|
||||
@ -40,7 +41,9 @@ ChannelList::ChannelList()
|
||||
}
|
||||
|
||||
if (type == RenderType::TextChannel || type == RenderType::DM || type == RenderType::Thread) {
|
||||
m_signal_action_channel_item_select.emit(static_cast<Snowflake>(row[m_columns.m_id]));
|
||||
const auto id = static_cast<Snowflake>(row[m_columns.m_id]);
|
||||
m_signal_action_channel_item_select.emit(id);
|
||||
Abaddon::Get().GetDiscordClient().MarkAsRead(id, [](...) {});
|
||||
}
|
||||
};
|
||||
m_view.signal_row_activated().connect(cb, false);
|
||||
@ -77,6 +80,7 @@ ChannelList::ChannelList()
|
||||
column->add_attribute(renderer->property_icon(), m_columns.m_icon);
|
||||
column->add_attribute(renderer->property_icon_animation(), m_columns.m_icon_anim);
|
||||
column->add_attribute(renderer->property_name(), m_columns.m_name);
|
||||
column->add_attribute(renderer->property_id(), m_columns.m_id);
|
||||
column->add_attribute(renderer->property_expanded(), m_columns.m_expanded);
|
||||
column->add_attribute(renderer->property_nsfw(), m_columns.m_nsfw);
|
||||
m_view.append_column(*column);
|
||||
@ -98,13 +102,18 @@ ChannelList::ChannelList()
|
||||
m_menu_category_copy_id.signal_activate().connect([this] {
|
||||
Gtk::Clipboard::get()->set_text(std::to_string((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]));
|
||||
});
|
||||
|
||||
m_menu_category.append(m_menu_category_copy_id);
|
||||
m_menu_category.show_all();
|
||||
|
||||
m_menu_channel_copy_id.signal_activate().connect([this] {
|
||||
Gtk::Clipboard::get()->set_text(std::to_string((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]));
|
||||
});
|
||||
m_menu_channel_mark_as_read.signal_activate().connect([this] {
|
||||
Abaddon::Get().GetDiscordClient().MarkAsRead(static_cast<Snowflake>((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]), [](...) {});
|
||||
});
|
||||
m_menu_channel.append(m_menu_channel_copy_id);
|
||||
m_menu_channel.append(m_menu_channel_mark_as_read);
|
||||
m_menu_channel.show_all();
|
||||
|
||||
m_menu_dm_copy_id.signal_activate().connect([this] {
|
||||
@ -159,6 +168,7 @@ ChannelList::ChannelList()
|
||||
discord.signal_added_to_thread().connect(sigc::mem_fun(*this, &ChannelList::OnThreadJoined));
|
||||
discord.signal_removed_from_thread().connect(sigc::mem_fun(*this, &ChannelList::OnThreadRemoved));
|
||||
discord.signal_guild_update().connect(sigc::mem_fun(*this, &ChannelList::UpdateGuild));
|
||||
discord.signal_message_ack().connect(sigc::mem_fun(*this, &ChannelList::OnMessageAck));
|
||||
}
|
||||
|
||||
void ChannelList::UpdateListing() {
|
||||
@ -658,7 +668,7 @@ void ChannelList::UpdateCreateDMChannel(const ChannelData &dm) {
|
||||
|
||||
std::optional<UserData> top_recipient;
|
||||
const auto recipients = dm.GetDMRecipients();
|
||||
if (recipients.size() > 0)
|
||||
if (!recipients.empty())
|
||||
top_recipient = recipients[0];
|
||||
|
||||
auto iter = m_model->append(header_row->children());
|
||||
@ -682,6 +692,12 @@ void ChannelList::UpdateCreateDMChannel(const ChannelData &dm) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelList::OnMessageAck(const MessageAckData &data) {
|
||||
// trick renderer into redrawing
|
||||
auto iter = GetIteratorForChannelFromID(data.ChannelID);
|
||||
if (iter) m_model->row_changed(m_model->get_path(iter), iter);
|
||||
}
|
||||
|
||||
void ChannelList::OnMessageCreate(const Message &msg) {
|
||||
const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(msg.ChannelID);
|
||||
if (!channel.has_value()) return;
|
||||
|
@ -89,6 +89,8 @@ protected:
|
||||
void AddPrivateChannels();
|
||||
void UpdateCreateDMChannel(const ChannelData &channel);
|
||||
|
||||
void OnMessageAck(const MessageAckData &data);
|
||||
|
||||
void OnMessageCreate(const Message &msg);
|
||||
Gtk::TreeModel::Path m_path_for_menu;
|
||||
|
||||
@ -105,6 +107,7 @@ protected:
|
||||
|
||||
Gtk::Menu m_menu_channel;
|
||||
Gtk::MenuItem m_menu_channel_copy_id;
|
||||
Gtk::MenuItem m_menu_channel_mark_as_read;
|
||||
|
||||
Gtk::Menu m_menu_dm;
|
||||
Gtk::MenuItem m_menu_dm_copy_id;
|
||||
|
@ -1,11 +1,13 @@
|
||||
#include "channelscellrenderer.hpp"
|
||||
#include "abaddon.hpp"
|
||||
#include <gtkmm.h>
|
||||
#include "unreadrenderer.hpp"
|
||||
|
||||
CellRendererChannels::CellRendererChannels()
|
||||
: Glib::ObjectBase(typeid(CellRendererChannels))
|
||||
, Gtk::CellRenderer()
|
||||
, m_property_type(*this, "render-type")
|
||||
, m_property_id(*this, "id")
|
||||
, m_property_name(*this, "name")
|
||||
, m_property_pixbuf(*this, "pixbuf")
|
||||
, m_property_pixbuf_animation(*this, "pixbuf-animation")
|
||||
@ -26,6 +28,10 @@ Glib::PropertyProxy<RenderType> CellRendererChannels::property_type() {
|
||||
return m_property_type.get_proxy();
|
||||
}
|
||||
|
||||
Glib::PropertyProxy<uint64_t> CellRendererChannels::property_id() {
|
||||
return m_property_id.get_proxy();
|
||||
}
|
||||
|
||||
Glib::PropertyProxy<Glib::ustring> CellRendererChannels::property_name() {
|
||||
return m_property_name.get_proxy();
|
||||
}
|
||||
@ -328,6 +334,8 @@ void CellRendererChannels::render_vfunc_channel(const Cairo::RefPtr<Cairo::Conte
|
||||
// setting property_foreground_rgba() sets this to true which makes non-nsfw cells use the property too which is bad
|
||||
// so unset it
|
||||
m_renderer_text.property_foreground_set() = false;
|
||||
|
||||
UnreadRenderer::RenderUnreadOnChannel(m_property_id.get_value(), cr, background_area, cell_area);
|
||||
}
|
||||
|
||||
// thread
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <gdkmm/pixbufanimation.h>
|
||||
#include <glibmm/property.h>
|
||||
#include <map>
|
||||
#include "discord/snowflake.hpp"
|
||||
|
||||
enum class RenderType : uint8_t {
|
||||
Guild,
|
||||
@ -20,6 +21,7 @@ public:
|
||||
virtual ~CellRendererChannels();
|
||||
|
||||
Glib::PropertyProxy<RenderType> property_type();
|
||||
Glib::PropertyProxy<uint64_t> property_id();
|
||||
Glib::PropertyProxy<Glib::ustring> property_name();
|
||||
Glib::PropertyProxy<Glib::RefPtr<Gdk::Pixbuf>> property_icon();
|
||||
Glib::PropertyProxy<Glib::RefPtr<Gdk::PixbufAnimation>> property_icon_animation();
|
||||
@ -106,8 +108,9 @@ protected:
|
||||
private:
|
||||
Gtk::CellRendererText m_renderer_text;
|
||||
|
||||
Glib::Property<RenderType> m_property_type; // all
|
||||
Glib::Property<Glib::ustring> m_property_name; // all
|
||||
Glib::Property<RenderType> m_property_type; // all
|
||||
Glib::Property<Glib::ustring> m_property_name; // all
|
||||
Glib::Property<uint64_t> m_property_id;
|
||||
Glib::Property<Glib::RefPtr<Gdk::Pixbuf>> m_property_pixbuf; // guild, dm
|
||||
Glib::Property<Glib::RefPtr<Gdk::PixbufAnimation>> m_property_pixbuf_animation; // guild
|
||||
Glib::Property<bool> m_property_expanded; // category
|
||||
|
15
src/components/unreadrenderer.cpp
Normal file
15
src/components/unreadrenderer.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "unreadrenderer.hpp"
|
||||
#include "abaddon.hpp"
|
||||
|
||||
void UnreadRenderer::RenderUnreadOnChannel(Snowflake id, const Cairo::RefPtr<Cairo::Context> &cr, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area) {
|
||||
const auto state = Abaddon::Get().GetDiscordClient().GetUnreadStateForChannel(id);
|
||||
if (state >= 0) {
|
||||
cr->set_source_rgb(1.0, 1.0, 1.0);
|
||||
const auto x = cell_area.get_x() + 1;
|
||||
const auto y = cell_area.get_y();
|
||||
const auto w = cell_area.get_width();
|
||||
const auto h = cell_area.get_height();
|
||||
cr->rectangle(x, y, 3, h);
|
||||
cr->fill();
|
||||
}
|
||||
}
|
9
src/components/unreadrenderer.hpp
Normal file
9
src/components/unreadrenderer.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <cairomm/context.h>
|
||||
#include <gdkmm/rectangle.h>
|
||||
#include "discord/snowflake.hpp"
|
||||
|
||||
class UnreadRenderer {
|
||||
public:
|
||||
static void RenderUnreadOnChannel(Snowflake id, const Cairo::RefPtr<Cairo::Context> &cr, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area);
|
||||
};
|
@ -1,8 +1,8 @@
|
||||
#include "discord.hpp"
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include "util.hpp"
|
||||
#include "abaddon.hpp"
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
|
||||
DiscordClient::DiscordClient(bool mem_store)
|
||||
: m_decompress_buf(InflateChunkSize)
|
||||
@ -874,6 +874,17 @@ void DiscordClient::UnArchiveThread(Snowflake channel_id, sigc::slot<void(Discor
|
||||
});
|
||||
}
|
||||
|
||||
void DiscordClient::MarkAsRead(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback) {
|
||||
const auto iter = m_last_message_id.find(channel_id);
|
||||
if (iter == m_last_message_id.end()) return;
|
||||
m_http.MakePOST("/channels/" + std::to_string(channel_id) + "/messages/" + std::to_string(iter->second) + "/ack", "{\"token\":null}", [this, callback](const http::response_type &response) {
|
||||
if (CheckCode(response))
|
||||
callback(DiscordError::NONE);
|
||||
else
|
||||
callback(GetCodeFromResponse(response));
|
||||
});
|
||||
}
|
||||
|
||||
void DiscordClient::FetchPinned(Snowflake id, sigc::slot<void(std::vector<Message>, DiscordError code)> callback) {
|
||||
// return from db if we know the pins have already been requested
|
||||
if (m_channels_pinned_requested.find(id) != m_channels_pinned_requested.end()) {
|
||||
@ -1060,6 +1071,12 @@ void DiscordClient::SetUserAgent(std::string agent) {
|
||||
m_websocket.SetUserAgent(agent);
|
||||
}
|
||||
|
||||
int DiscordClient::GetUnreadStateForChannel(Snowflake id) const noexcept {
|
||||
const auto iter = m_unread.find(id);
|
||||
if (iter == m_unread.end()) return -1; // todo: no magic number
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
PresenceStatus DiscordClient::GetUserStatus(Snowflake id) const {
|
||||
auto it = m_user_to_status.find(id);
|
||||
if (it != m_user_to_status.end())
|
||||
@ -1290,6 +1307,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) {
|
||||
case GatewayEvent::THREAD_MEMBER_LIST_UPDATE: {
|
||||
HandleGatewayThreadMemberListUpdate(m);
|
||||
} break;
|
||||
case GatewayEvent::MESSAGE_ACK: {
|
||||
HandleGatewayMessageAck(m);
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
@ -1411,6 +1431,9 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
|
||||
m_session_id = data.SessionID;
|
||||
m_user_data = data.SelfUser;
|
||||
m_user_settings = data.Settings;
|
||||
|
||||
HandleReadyReadState(data);
|
||||
|
||||
m_signal_gateway_ready.emit();
|
||||
}
|
||||
|
||||
@ -1419,6 +1442,7 @@ void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) {
|
||||
StoreMessageData(data);
|
||||
if (data.GuildID.has_value())
|
||||
AddUserToGuild(data.Author.ID, *data.GuildID);
|
||||
m_last_message_id[data.ChannelID] = data.ID;
|
||||
m_signal_message_create.emit(data);
|
||||
}
|
||||
|
||||
@ -1778,6 +1802,12 @@ void DiscordClient::HandleGatewayThreadMemberListUpdate(const GatewayMessage &ms
|
||||
m_signal_thread_member_list_update.emit(data);
|
||||
}
|
||||
|
||||
void DiscordClient::HandleGatewayMessageAck(const GatewayMessage &msg) {
|
||||
MessageAckData data = msg.Data;
|
||||
m_unread.erase(data.ChannelID);
|
||||
m_signal_message_ack.emit(data);
|
||||
}
|
||||
|
||||
void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) {
|
||||
ReadySupplementalData data = msg.Data;
|
||||
for (const auto &p : data.MergedPresences.Friends) {
|
||||
@ -2105,6 +2135,24 @@ void DiscordClient::StoreMessageData(Message &msg) {
|
||||
StoreMessageData(**msg.ReferencedMessage);
|
||||
}
|
||||
|
||||
// some notes for myself
|
||||
// a read channel is determined by checking if the channel object's last message id is equal to the read state's last message id
|
||||
// here the absence of an entry in m_unread indicates a read channel and the value is only the mention count since the message doesnt matter
|
||||
// no entry.id cannot be a guild even though sometimes it looks like it
|
||||
void DiscordClient::HandleReadyReadState(const ReadyEventData &data) {
|
||||
for (const auto &guild : data.Guilds)
|
||||
for (const auto &channel : *guild.Channels)
|
||||
if (channel.Type == ChannelType::GUILD_TEXT || channel.Type == ChannelType::GUILD_NEWS && channel.LastMessageID.has_value())
|
||||
m_last_message_id[channel.ID] = *channel.LastMessageID;
|
||||
|
||||
for (const auto &entry : data.ReadState.Entries) {
|
||||
const auto it = m_last_message_id.find(entry.ID);
|
||||
if (it == m_last_message_id.end()) continue;
|
||||
if (it->second > entry.LastMessageID)
|
||||
m_unread[entry.ID] = entry.MentionCount;
|
||||
}
|
||||
}
|
||||
|
||||
void DiscordClient::LoadEventMap() {
|
||||
m_event_map["READY"] = GatewayEvent::READY;
|
||||
m_event_map["MESSAGE_CREATE"] = GatewayEvent::MESSAGE_CREATE;
|
||||
@ -2147,6 +2195,7 @@ void DiscordClient::LoadEventMap() {
|
||||
m_event_map["THREAD_MEMBER_UPDATE"] = GatewayEvent::THREAD_MEMBER_UPDATE;
|
||||
m_event_map["THREAD_UPDATE"] = GatewayEvent::THREAD_UPDATE;
|
||||
m_event_map["THREAD_MEMBER_LIST_UPDATE"] = GatewayEvent::THREAD_MEMBER_LIST_UPDATE;
|
||||
m_event_map["MESSAGE_ACK"] = GatewayEvent::MESSAGE_ACK;
|
||||
}
|
||||
|
||||
DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() {
|
||||
@ -2309,6 +2358,10 @@ DiscordClient::type_signal_thread_member_list_update DiscordClient::signal_threa
|
||||
return m_signal_thread_member_list_update;
|
||||
}
|
||||
|
||||
DiscordClient::type_signal_message_ack DiscordClient::signal_message_ack() {
|
||||
return m_signal_message_ack;
|
||||
}
|
||||
|
||||
DiscordClient::type_signal_added_to_thread DiscordClient::signal_added_to_thread() {
|
||||
return m_signal_added_to_thread;
|
||||
}
|
||||
|
@ -138,6 +138,7 @@ public:
|
||||
void LeaveThread(Snowflake channel_id, const std::string &location, sigc::slot<void(DiscordError code)> callback);
|
||||
void ArchiveThread(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback);
|
||||
void UnArchiveThread(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback);
|
||||
void MarkAsRead(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback);
|
||||
|
||||
bool CanModifyRole(Snowflake guild_id, Snowflake role_id) const;
|
||||
bool CanModifyRole(Snowflake guild_id, Snowflake role_id, Snowflake user_id) const;
|
||||
@ -182,6 +183,8 @@ public:
|
||||
void UpdateToken(std::string token);
|
||||
void SetUserAgent(std::string agent);
|
||||
|
||||
int GetUnreadStateForChannel(Snowflake id) const noexcept;
|
||||
|
||||
PresenceStatus GetUserStatus(Snowflake id) const;
|
||||
|
||||
std::map<Snowflake, RelationshipType> GetRelationships() const;
|
||||
@ -244,6 +247,7 @@ private:
|
||||
void HandleGatewayThreadMemberUpdate(const GatewayMessage &msg);
|
||||
void HandleGatewayThreadUpdate(const GatewayMessage &msg);
|
||||
void HandleGatewayThreadMemberListUpdate(const GatewayMessage &msg);
|
||||
void HandleGatewayMessageAck(const GatewayMessage &msg);
|
||||
void HandleGatewayReadySupplemental(const GatewayMessage &msg);
|
||||
void HandleGatewayReconnect(const GatewayMessage &msg);
|
||||
void HandleGatewayInvalidSession(const GatewayMessage &msg);
|
||||
@ -259,6 +263,8 @@ private:
|
||||
|
||||
void StoreMessageData(Message &msg);
|
||||
|
||||
void HandleReadyReadState(const ReadyEventData &data);
|
||||
|
||||
std::string m_token;
|
||||
|
||||
void AddUserToGuild(Snowflake user_id, Snowflake guild_id);
|
||||
@ -269,6 +275,8 @@ private:
|
||||
std::map<Snowflake, RelationshipType> m_user_relationships;
|
||||
std::set<Snowflake> m_joined_threads;
|
||||
std::map<Snowflake, std::vector<Snowflake>> m_thread_members;
|
||||
std::map<Snowflake, Snowflake> m_last_message_id;
|
||||
std::unordered_map<Snowflake, int> m_unread;
|
||||
|
||||
UserData m_user_data;
|
||||
UserSettings m_user_settings;
|
||||
@ -343,6 +351,7 @@ public:
|
||||
typedef sigc::signal<void, ThreadMembersUpdateData> type_signal_thread_members_update;
|
||||
typedef sigc::signal<void, ThreadUpdateData> type_signal_thread_update;
|
||||
typedef sigc::signal<void, ThreadMemberListUpdateData> type_signal_thread_member_list_update;
|
||||
typedef sigc::signal<void, MessageAckData> type_signal_message_ack;
|
||||
|
||||
// not discord dispatch events
|
||||
typedef sigc::signal<void, Snowflake> type_signal_added_to_thread;
|
||||
@ -393,6 +402,7 @@ public:
|
||||
type_signal_thread_members_update signal_thread_members_update();
|
||||
type_signal_thread_update signal_thread_update();
|
||||
type_signal_thread_member_list_update signal_thread_member_list_update();
|
||||
type_signal_message_ack signal_message_ack();
|
||||
|
||||
type_signal_added_to_thread signal_added_to_thread();
|
||||
type_signal_removed_from_thread signal_removed_from_thread();
|
||||
@ -440,6 +450,7 @@ protected:
|
||||
type_signal_thread_members_update m_signal_thread_members_update;
|
||||
type_signal_thread_update m_signal_thread_update;
|
||||
type_signal_thread_member_list_update m_signal_thread_member_list_update;
|
||||
type_signal_message_ack m_signal_message_ack;
|
||||
|
||||
type_signal_removed_from_thread m_signal_removed_from_thread;
|
||||
type_signal_added_to_thread m_signal_added_to_thread;
|
||||
|
@ -119,6 +119,18 @@ void to_json(nlohmann::json &j, const UpdateStatusMessage &m) {
|
||||
}
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json &j, ReadStateEntry &m) {
|
||||
JS_ON("mention_count", m.MentionCount);
|
||||
JS_ON("last_message_id", m.LastMessageID);
|
||||
JS_D("id", m.ID);
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json &j, ReadStateData &m) {
|
||||
JS_ON("version", m.Version);
|
||||
JS_ON("partial", m.IsPartial);
|
||||
JS_ON("entries", m.Entries);
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json &j, ReadyEventData &m) {
|
||||
JS_D("v", m.GatewayVersion);
|
||||
JS_D("user", m.SelfUser);
|
||||
@ -132,6 +144,7 @@ void from_json(const nlohmann::json &j, ReadyEventData &m) {
|
||||
JS_ON("merged_members", m.MergedMembers);
|
||||
JS_O("relationships", m.Relationships);
|
||||
JS_O("guild_join_requests", m.GuildJoinRequests);
|
||||
JS_O("read_state", m.ReadState);
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json &j, MergedPresence &m) {
|
||||
@ -532,3 +545,9 @@ void to_json(nlohmann::json &j, const ModifyChannelObject &m) {
|
||||
JS_IF("archived", m.Archived);
|
||||
JS_IF("locked", m.Locked);
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json &j, MessageAckData &m) {
|
||||
// JS_D("version", m.Version);
|
||||
JS_D("message_id", m.MessageID);
|
||||
JS_D("channel_id", m.ChannelID);
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ enum class GatewayEvent : int {
|
||||
THREAD_MEMBER_UPDATE,
|
||||
THREAD_MEMBERS_UPDATE,
|
||||
THREAD_MEMBER_LIST_UPDATE,
|
||||
MESSAGE_ACK,
|
||||
};
|
||||
|
||||
enum class GatewayCloseCode : uint16_t {
|
||||
@ -224,6 +225,23 @@ struct UpdateStatusMessage {
|
||||
friend void to_json(nlohmann::json &j, const UpdateStatusMessage &m);
|
||||
};
|
||||
|
||||
struct ReadStateEntry {
|
||||
int MentionCount;
|
||||
Snowflake LastMessageID;
|
||||
Snowflake ID;
|
||||
// std::string LastPinTimestamp; iso
|
||||
|
||||
friend void from_json(const nlohmann::json &j, ReadStateEntry &m);
|
||||
};
|
||||
|
||||
struct ReadStateData {
|
||||
int Version;
|
||||
bool IsPartial;
|
||||
std::vector<ReadStateEntry> Entries;
|
||||
|
||||
friend void from_json(const nlohmann::json &j, ReadStateData &m);
|
||||
};
|
||||
|
||||
struct ReadyEventData {
|
||||
int GatewayVersion;
|
||||
UserData SelfUser;
|
||||
@ -239,6 +257,7 @@ struct ReadyEventData {
|
||||
std::optional<std::vector<std::vector<GuildMember>>> MergedMembers;
|
||||
std::optional<std::vector<RelationshipData>> Relationships;
|
||||
std::optional<std::vector<GuildApplicationData>> GuildJoinRequests;
|
||||
ReadStateData ReadState;
|
||||
// std::vector<Unknown> ConnectedAccounts; // opt
|
||||
// std::map<std::string, Unknown> Consents; // opt
|
||||
// std::vector<Unknown> Experiments; // opt
|
||||
@ -745,3 +764,11 @@ struct ModifyChannelObject {
|
||||
|
||||
friend void to_json(nlohmann::json &j, const ModifyChannelObject &m);
|
||||
};
|
||||
|
||||
struct MessageAckData {
|
||||
// int Version; // what is this ?!?!?!!?
|
||||
Snowflake MessageID;
|
||||
Snowflake ChannelID;
|
||||
|
||||
friend void from_json(const nlohmann::json &j, MessageAckData &m);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user