summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/abaddon.cpp14
-rw-r--r--src/audio/ma_impl.cpp3
-rw-r--r--src/components/channels.cpp82
-rw-r--r--src/components/channels.hpp1
-rw-r--r--src/components/chatinput.cpp6
-rw-r--r--src/constants.hpp2
-rw-r--r--src/discord/chatsubmitparams.hpp1
-rw-r--r--src/discord/discord.cpp80
-rw-r--r--src/discord/discord.hpp3
-rw-r--r--src/discord/message.hpp26
-rw-r--r--src/discord/objects.cpp6
-rw-r--r--src/discord/objects.hpp43
-rw-r--r--src/discord/snowflake.cpp4
-rw-r--r--src/discord/snowflake.hpp1
-rw-r--r--src/discord/voiceclient.cpp4
-rw-r--r--src/notifications/notifications.cpp2
-rw-r--r--src/settings.cpp2
-rw-r--r--src/settings.hpp3
-rw-r--r--src/windows/voicesettingswindow.cpp12
-rw-r--r--src/windows/voicesettingswindow.hpp6
-rw-r--r--src/windows/voicewindow.cpp5
21 files changed, 232 insertions, 74 deletions
diff --git a/src/abaddon.cpp b/src/abaddon.cpp
index e22afde..92cc494 100644
--- a/src/abaddon.cpp
+++ b/src/abaddon.cpp
@@ -252,6 +252,12 @@ int Abaddon::StartGTK() {
}
#endif
+#ifdef _WIN32
+ if (m_settings.GetSettings().HideConsole) {
+ ShowWindow(GetConsoleWindow(), SW_HIDE);
+ }
+#endif
+
// store must be checked before this can be called
m_main_window->UpdateComponents();
@@ -914,8 +920,14 @@ void Abaddon::ActionChatLoadHistory(Snowflake id) {
}
void Abaddon::ActionChatInputSubmit(ChatSubmitParams data) {
- if (data.Message.substr(0, 7) == "/shrug " || data.Message == "/shrug")
+ if (data.Message.substr(0, 7) == "/shrug " || data.Message == "/shrug") {
data.Message = data.Message.substr(6) + "\xC2\xAF\x5C\x5F\x28\xE3\x83\x84\x29\x5F\x2F\xC2\xAF"; // this is important
+ }
+
+ if (data.Message.substr(0, 8) == "@silent " || (data.Message.substr(0, 7) == "@silent" && !data.Attachments.empty())) {
+ data.Silent = true;
+ data.Message = data.Message.substr(7);
+ }
if (!m_discord.HasChannelPermission(m_discord.GetUserData().ID, data.ChannelID, Permission::VIEW_CHANNEL)) return;
diff --git a/src/audio/ma_impl.cpp b/src/audio/ma_impl.cpp
index a83ddaf..531b24f 100644
--- a/src/audio/ma_impl.cpp
+++ b/src/audio/ma_impl.cpp
@@ -1,4 +1,7 @@
#ifdef WITH_MINIAUDIO
#define MINIAUDIO_IMPLEMENTATION
+ #ifdef __APPLE__
+ #define MA_NO_RUNTIME_LINKING
+ #endif
#include <miniaudio.h>
#endif
diff --git a/src/components/channels.cpp b/src/components/channels.cpp
index 15a8348..26f3259 100644
--- a/src/components/channels.cpp
+++ b/src/components/channels.cpp
@@ -42,7 +42,7 @@ ChannelList::ChannelList()
const auto type = row[m_columns.m_type];
// text channels should not be allowed to be collapsed
// maybe they should be but it seems a little difficult to handle expansion to permit this
- if (type != RenderType::TextChannel) {
+ if (type != RenderType::TextChannel && type != RenderType::DM) {
if (row[m_columns.m_expanded]) {
m_view.collapse_row(path);
row[m_columns.m_expanded] = false;
@@ -527,6 +527,7 @@ void ChannelList::OnThreadListSync(const ThreadListSyncData &data) {
#ifdef WITH_VOICE
void ChannelList::OnVoiceUserConnect(Snowflake user_id, Snowflake channel_id) {
auto parent_iter = GetIteratorForRowFromIDOfType(channel_id, RenderType::VoiceChannel);
+ if (!parent_iter) parent_iter = GetIteratorForRowFromIDOfType(channel_id, RenderType::DM);
if (!parent_iter) return;
const auto user = Abaddon::Get().GetDiscordClient().GetUser(user_id);
if (!user.has_value()) return;
@@ -1015,20 +1016,17 @@ void ChannelList::AddPrivateChannels() {
row[m_columns.m_name] = Glib::Markup::escape_text(dm->GetDisplayName());
row[m_columns.m_sort] = static_cast<int64_t>(-(dm->LastMessageID.has_value() ? *dm->LastMessageID : dm_id));
row[m_columns.m_icon] = img.GetPlaceholder(DMIconSize);
+ row[m_columns.m_expanded] = true;
- if (dm->HasIcon()) {
- const auto cb = [this, iter](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
- if (iter)
- (*iter)[m_columns.m_icon] = pb->scale_simple(DMIconSize, DMIconSize, Gdk::INTERP_BILINEAR);
- };
- img.LoadFromURL(dm->GetIconURL(), sigc::track_obj(cb, *this));
- } else if (top_recipient.has_value()) {
- const auto cb = [this, iter](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
- if (iter)
- (*iter)[m_columns.m_icon] = pb->scale_simple(DMIconSize, DMIconSize, Gdk::INTERP_BILINEAR);
- };
- img.LoadFromURL(top_recipient->GetAvatarURL("png", "32"), sigc::track_obj(cb, *this));
+#ifdef WITH_VOICE
+ for (auto user_id : discord.GetUsersInVoiceChannel(dm_id)) {
+ if (const auto user = discord.GetUser(user_id); user.has_value()) {
+ CreateVoiceParticipantRow(*user, row->children());
+ }
}
+#endif
+
+ SetDMChannelIcon(iter, *dm);
}
}
@@ -1036,11 +1034,6 @@ void ChannelList::UpdateCreateDMChannel(const ChannelData &dm) {
auto header_row = m_model->get_iter(m_dm_header);
auto &img = Abaddon::Get().GetImageManager();
- std::optional<UserData> top_recipient;
- const auto recipients = dm.GetDMRecipients();
- if (!recipients.empty())
- top_recipient = recipients[0];
-
auto iter = m_model->append(header_row->children());
auto row = *iter;
row[m_columns.m_type] = RenderType::DM;
@@ -1049,12 +1042,63 @@ void ChannelList::UpdateCreateDMChannel(const ChannelData &dm) {
row[m_columns.m_sort] = static_cast<int64_t>(-(dm.LastMessageID.has_value() ? *dm.LastMessageID : dm.ID));
row[m_columns.m_icon] = img.GetPlaceholder(DMIconSize);
- if (top_recipient.has_value()) {
+ SetDMChannelIcon(iter, dm);
+}
+
+void ChannelList::SetDMChannelIcon(Gtk::TreeIter iter, const ChannelData &dm) {
+ auto &img = Abaddon::Get().GetImageManager();
+
+ std::optional<UserData> top_recipient;
+ const auto recipients = dm.GetDMRecipients();
+ if (!recipients.empty())
+ top_recipient = recipients[0];
+
+ if (dm.HasIcon()) {
+ const auto cb = [this, iter](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
+ if (iter)
+ (*iter)[m_columns.m_icon] = pb->scale_simple(DMIconSize, DMIconSize, Gdk::INTERP_BILINEAR);
+ };
+ img.LoadFromURL(dm.GetIconURL(), sigc::track_obj(cb, *this));
+ } else if (dm.Type == ChannelType::DM && top_recipient.has_value()) {
const auto cb = [this, iter](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
if (iter)
(*iter)[m_columns.m_icon] = pb->scale_simple(DMIconSize, DMIconSize, Gdk::INTERP_BILINEAR);
};
img.LoadFromURL(top_recipient->GetAvatarURL("png", "32"), sigc::track_obj(cb, *this));
+ } else { // GROUP_DM
+ std::string hash;
+ switch (dm.ID.GetUnixMilliseconds() % 8) {
+ case 0:
+ hash = "ee9275c5a437f7dc7f9430ba95f12ebd";
+ break;
+ case 1:
+ hash = "9baf45aac2a0ec2e2dab288333acb9d9";
+ break;
+ case 2:
+ hash = "7ba11ffb1900fa2b088cb31324242047";
+ break;
+ case 3:
+ hash = "f90fca70610c4898bc57b58bce92f587";
+ break;
+ case 4:
+ hash = "e2779af34b8d9126b77420e5f09213ce";
+ break;
+ case 5:
+ hash = "c6851bd0b03f1cca5a8c1e720ea6ea17";
+ break;
+ case 6:
+ hash = "f7e38ac976a2a696161c923502a8345b";
+ break;
+ case 7:
+ default:
+ hash = "3cb840d03313467838d658bbec801fcd";
+ break;
+ }
+ const auto cb = [this, iter](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
+ if (iter)
+ (*iter)[m_columns.m_icon] = pb->scale_simple(DMIconSize, DMIconSize, Gdk::INTERP_BILINEAR);
+ };
+ img.LoadFromURL("https://discord.com/assets/" + hash + ".png", sigc::track_obj(cb, *this));
}
}
diff --git a/src/components/channels.hpp b/src/components/channels.hpp
index 7a23b3d..d561737 100644
--- a/src/components/channels.hpp
+++ b/src/components/channels.hpp
@@ -114,6 +114,7 @@ protected:
void AddPrivateChannels();
void UpdateCreateDMChannel(const ChannelData &channel);
+ void SetDMChannelIcon(Gtk::TreeIter iter, const ChannelData &dm);
void OnMessageAck(const MessageAckData &data);
diff --git a/src/components/chatinput.cpp b/src/components/chatinput.cpp
index d19ac4b..28ed1ea 100644
--- a/src/components/chatinput.cpp
+++ b/src/components/chatinput.cpp
@@ -41,9 +41,15 @@ bool ChatInputText::ProcessKeyPress(GdkEventKey *event) {
return true;
}
+#ifdef __APPLE__
+ if ((event->state & GDK_MOD2_MASK) && event->keyval == GDK_KEY_v) {
+ return CheckHandleClipboardPaste();
+ }
+#else
if ((event->state & GDK_CONTROL_MASK) && event->keyval == GDK_KEY_v) {
return CheckHandleClipboardPaste();
}
+#endif
if (event->keyval == GDK_KEY_Return) {
if (event->state & GDK_SHIFT_MASK)
diff --git a/src/constants.hpp b/src/constants.hpp
index 256f85e..5ed123c 100644
--- a/src/constants.hpp
+++ b/src/constants.hpp
@@ -4,7 +4,7 @@
constexpr static uint64_t SnowflakeSplitDifference = 600;
constexpr static int MaxMessagesForChatCull = 50; // this has to be 50 (for now) cuz that magic number is used in a couple other places and i dont feel like replacing them
constexpr static int AttachmentItemSize = 120;
-constexpr static int BaseAttachmentSizeLimit = 8 * 1024 * 1024;
+constexpr static int BaseAttachmentSizeLimit = 25 * 1024 * 1024;
constexpr static int NitroClassicAttachmentSizeLimit = 50 * 1024 * 1024;
constexpr static int NitroAttachmentSizeLimit = 100 * 1024 * 1024;
constexpr static int BoostLevel2AttachmentSizeLimit = 50 * 1024 * 1024;
diff --git a/src/discord/chatsubmitparams.hpp b/src/discord/chatsubmitparams.hpp
index 6199634..24c6f50 100644
--- a/src/discord/chatsubmitparams.hpp
+++ b/src/discord/chatsubmitparams.hpp
@@ -17,6 +17,7 @@ struct ChatSubmitParams {
std::string Filename;
};
+ bool Silent = false;
Snowflake ChannelID;
Snowflake InReplyToID;
Glib::ustring Message;
diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp
index 2a25a26..817aca8 100644
--- a/src/discord/discord.cpp
+++ b/src/discord/discord.cpp
@@ -461,8 +461,13 @@ void DiscordClient::SendChatMessageNoAttachments(const ChatSubmitParams &params,
CreateMessageObject obj;
obj.Content = params.Message;
obj.Nonce = nonce;
- if (params.InReplyToID.IsValid())
+ if (params.Silent) {
+ obj.Flags |= MessageFlags::SUPPRESS_NOTIFICATIONS;
+ }
+
+ if (params.InReplyToID.IsValid()) {
obj.MessageReference.emplace().MessageID = params.InReplyToID;
+ }
m_http.MakePOST("/channels/" + std::to_string(params.ChannelID) + "/messages",
nlohmann::json(obj).dump(),
@@ -494,8 +499,13 @@ void DiscordClient::SendChatMessageAttachments(const ChatSubmitParams &params, c
CreateMessageObject obj;
obj.Content = params.Message;
obj.Nonce = nonce;
- if (params.InReplyToID.IsValid())
+ if (params.Silent) {
+ obj.Flags |= MessageFlags::SUPPRESS_NOTIFICATIONS;
+ }
+
+ if (params.InReplyToID.IsValid()) {
obj.MessageReference.emplace().MessageID = params.InReplyToID;
+ }
auto req = m_http.CreateRequest(http::REQUEST_POST, "/channels/" + std::to_string(params.ChannelID) + "/messages");
m_progress_cb_timer.start();
@@ -545,10 +555,11 @@ void DiscordClient::SendChatMessageAttachments(const ChatSubmitParams &params, c
}
void DiscordClient::SendChatMessage(const ChatSubmitParams &params, const sigc::slot<void(DiscordError)> &callback) {
- if (params.Attachments.empty())
+ if (params.Attachments.empty()) {
SendChatMessageNoAttachments(params, callback);
- else
+ } else {
SendChatMessageAttachments(params, callback);
+ }
}
void DiscordClient::DeleteMessage(Snowflake channel_id, Snowflake id) {
@@ -1579,6 +1590,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) {
case GatewayEvent::VOICE_SERVER_UPDATE: {
HandleGatewayVoiceServerUpdate(m);
} break;
+ case GatewayEvent::CALL_CREATE: {
+ HandleGatewayCallCreate(m);
+ } break;
#endif
}
} break;
@@ -2253,8 +2267,39 @@ void DiscordClient::HandleGatewayGuildMembersChunk(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayVoiceStateUpdate(const GatewayMessage &msg) {
spdlog::get("discord")->trace("VOICE_STATE_UPDATE");
- VoiceState data = msg.Data;
+ CheckVoiceState(msg.Data);
+}
+void DiscordClient::HandleGatewayVoiceServerUpdate(const GatewayMessage &msg) {
+ spdlog::get("discord")->trace("VOICE_SERVER_UPDATE");
+
+ VoiceServerUpdateData data = msg.Data;
+ spdlog::get("discord")->debug("Voice server endpoint: {}", data.Endpoint);
+ spdlog::get("discord")->debug("Voice token: {}", data.Token);
+ m_voice.SetEndpoint(data.Endpoint);
+ m_voice.SetToken(data.Token);
+ if (data.GuildID.has_value()) {
+ m_voice.SetServerID(*data.GuildID);
+ } else if (data.ChannelID.has_value()) {
+ m_voice.SetServerID(*data.ChannelID);
+ } else {
+ spdlog::get("discord")->error("No guild or channel ID in voice server?");
+ }
+ m_voice.SetUserID(m_user_data.ID);
+ m_voice.Start();
+}
+
+void DiscordClient::HandleGatewayCallCreate(const GatewayMessage &msg) {
+ CallCreateData data = msg.Data;
+
+ spdlog::get("discord")->debug("CALL_CREATE: {}", data.ChannelID);
+
+ for (const auto &state : data.VoiceStates) {
+ CheckVoiceState(state);
+ }
+}
+
+void DiscordClient::CheckVoiceState(const VoiceState &data) {
if (data.UserID == m_user_data.ID) {
spdlog::get("discord")->debug("Voice session ID: {}", data.SessionID);
m_voice.SetSessionID(data.SessionID);
@@ -2292,25 +2337,6 @@ void DiscordClient::HandleGatewayVoiceStateUpdate(const GatewayMessage &msg) {
}
}
}
-
-void DiscordClient::HandleGatewayVoiceServerUpdate(const GatewayMessage &msg) {
- spdlog::get("discord")->trace("VOICE_SERVER_UPDATE");
-
- VoiceServerUpdateData data = msg.Data;
- spdlog::get("discord")->debug("Voice server endpoint: {}", data.Endpoint);
- spdlog::get("discord")->debug("Voice token: {}", data.Token);
- m_voice.SetEndpoint(data.Endpoint);
- m_voice.SetToken(data.Token);
- if (data.GuildID.has_value()) {
- m_voice.SetServerID(*data.GuildID);
- } else if (data.ChannelID.has_value()) {
- m_voice.SetServerID(*data.ChannelID);
- } else {
- spdlog::get("discord")->error("No guild or channel ID in voice server?");
- }
- m_voice.SetUserID(m_user_data.ID);
- m_voice.Start();
-}
#endif
void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) {
@@ -2556,7 +2582,7 @@ void DiscordClient::HeartbeatThread() {
void DiscordClient::SendIdentify() {
IdentifyMessage msg;
msg.Token = m_token;
- msg.Capabilities = 509; // no idea what this is
+ msg.Capabilities = 4605; // bit 12 is necessary for CALL_CREATE... apparently? need to get this in sync with official client
msg.Properties.OS = "Windows";
msg.Properties.Browser = "Chrome";
msg.Properties.Device = "";
@@ -2575,9 +2601,6 @@ void DiscordClient::SendIdentify() {
msg.Presence.Since = 0;
msg.Presence.IsAFK = false;
msg.DoesSupportCompression = false;
- msg.ClientState.HighestLastMessageID = "0";
- msg.ClientState.ReadStateVersion = 0;
- msg.ClientState.UserGuildSettingsVersion = -1;
SetSuperPropertiesFromIdentity(msg);
const bool b = m_websocket.GetPrintMessages();
m_websocket.SetPrintMessages(false);
@@ -2893,6 +2916,7 @@ void DiscordClient::LoadEventMap() {
m_event_map["GUILD_MEMBERS_CHUNK"] = GatewayEvent::GUILD_MEMBERS_CHUNK;
m_event_map["VOICE_STATE_UPDATE"] = GatewayEvent::VOICE_STATE_UPDATE;
m_event_map["VOICE_SERVER_UPDATE"] = GatewayEvent::VOICE_SERVER_UPDATE;
+ m_event_map["CALL_CREATE"] = GatewayEvent::CALL_CREATE;
}
DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() {
diff --git a/src/discord/discord.hpp b/src/discord/discord.hpp
index 7f7518c..d2435dd 100644
--- a/src/discord/discord.hpp
+++ b/src/discord/discord.hpp
@@ -291,6 +291,9 @@ private:
#ifdef WITH_VOICE
void HandleGatewayVoiceStateUpdate(const GatewayMessage &msg);
void HandleGatewayVoiceServerUpdate(const GatewayMessage &msg);
+ void HandleGatewayCallCreate(const GatewayMessage &msg);
+
+ void CheckVoiceState(const VoiceState &data);
#endif
void HeartbeatThread();
diff --git a/src/discord/message.hpp b/src/discord/message.hpp
index df2cb38..5028104 100644
--- a/src/discord/message.hpp
+++ b/src/discord/message.hpp
@@ -8,6 +8,7 @@
#include "emoji.hpp"
#include "member.hpp"
#include "interactions.hpp"
+#include "misc/bitwise.hpp"
enum class MessageType {
DEFAULT = 0, // yep
@@ -35,14 +36,23 @@ enum class MessageType {
enum class MessageFlags {
NONE = 0,
- CROSSPOSTED = 1 << 0, // this message has been published to subscribed channels (via Channel Following)
- IS_CROSSPOST = 1 << 1, // this message originated from a message in another channel (via Channel Following)
- SUPPRESS_EMBEDS = 1 << 2, // do not include any embeds when serializing this message
- SOURCE_MESSAGE_DELETE = 1 << 3, // the source message for this crosspost has been deleted (via Channel Following)
- URGENT = 1 << 4, // this message came from the urgent message system
- HAS_THREAD = 1 << 5, // this message has an associated thread, with the same id as the message
- EPHEMERAL = 1 << 6, // this message is only visible to the user who invoked the Interaction
- LOADING = 1 << 7, // this message is an Interaction Response and the bot is "thinking"
+ CROSSPOSTED = 1 << 0, // this message has been published to subscribed channels (via Channel Following)
+ IS_CROSSPOST = 1 << 1, // this message originated from a message in another channel (via Channel Following)
+ SUPPRESS_EMBEDS = 1 << 2, // do not include any embeds when serializing this message
+ SOURCE_MESSAGE_DELETE = 1 << 3, // the source message for this crosspost has been deleted (via Channel Following)
+ URGENT = 1 << 4, // this message came from the urgent message system
+ HAS_THREAD = 1 << 5, // this message has an associated thread, with the same id as the message
+ EPHEMERAL = 1 << 6, // this message is only visible to the user who invoked the Interaction
+ LOADING = 1 << 7, // this message is an Interaction Response and the bot is "thinking"
+ FAILED_TO_MENTION_SOME_ROLES_IN_THREAD = 1 << 8, // this message failed to mention some roles and add their members to the thread
+ SHOULD_SHOW_LINK_NOT_DISCORD_WARNING = 1 << 10, //
+ SUPPRESS_NOTIFICATIONS = 1 << 12, // this message will not trigger push and desktop notifications
+ IS_VOICE_MESSAGE = 1 << 13, // this message is a voice message
+};
+
+template<>
+struct Bitwise<MessageFlags> {
+ static const bool enable = true;
};
struct EmbedFooterData {
diff --git a/src/discord/objects.cpp b/src/discord/objects.cpp
index 715ae14..63bd43f 100644
--- a/src/discord/objects.cpp
+++ b/src/discord/objects.cpp
@@ -308,6 +308,7 @@ void to_json(nlohmann::json &j, const HeartbeatMessage &m) {
void to_json(nlohmann::json &j, const CreateMessageObject &m) {
j["content"] = m.Content;
+ j["flags"] = m.Flags;
JS_IF("message_reference", m.MessageReference);
JS_IF("nonce", m.Nonce);
}
@@ -687,6 +688,11 @@ void from_json(const nlohmann::json &j, VoiceServerUpdateData &m) {
JS_ON("guild_id", m.GuildID);
JS_ON("channel_id", m.ChannelID);
}
+
+void from_json(const nlohmann::json &j, CallCreateData &m) {
+ JS_D("channel_id", m.ChannelID);
+ JS_D("voice_states", m.VoiceStates);
+}
#endif
void from_json(const nlohmann::json &j, VoiceState &m) {
diff --git a/src/discord/objects.hpp b/src/discord/objects.hpp
index 4d56417..305ac65 100644
--- a/src/discord/objects.hpp
+++ b/src/discord/objects.hpp
@@ -102,6 +102,7 @@ enum class GatewayEvent : int {
GUILD_MEMBERS_CHUNK,
VOICE_STATE_UPDATE,
VOICE_SERVER_UPDATE,
+ CALL_CREATE,
};
enum class GatewayCloseCode : uint16_t {
@@ -427,6 +428,7 @@ struct HeartbeatMessage : GatewayMessage {
struct CreateMessageObject {
std::string Content;
+ MessageFlags Flags = MessageFlags::NONE;
std::optional<MessageReferenceData> MessageReference;
std::optional<std::string> Nonce;
@@ -887,6 +889,23 @@ struct GuildMembersChunkData {
friend void from_json(const nlohmann::json &j, GuildMembersChunkData &m);
};
+struct VoiceState {
+ std::optional<Snowflake> ChannelID;
+ bool IsDeafened;
+ bool IsMuted;
+ std::optional<Snowflake> GuildID;
+ std::optional<GuildMember> Member;
+ bool IsSelfDeafened;
+ bool IsSelfMuted;
+ bool IsSelfVideo;
+ bool IsSelfStream = false;
+ std::string SessionID;
+ bool IsSuppressed;
+ Snowflake UserID;
+
+ friend void from_json(const nlohmann::json &j, VoiceState &m);
+};
+
#ifdef WITH_VOICE
struct VoiceStateUpdateMessage {
std::optional<Snowflake> GuildID;
@@ -907,21 +926,15 @@ struct VoiceServerUpdateData {
friend void from_json(const nlohmann::json &j, VoiceServerUpdateData &m);
};
-#endif
-struct VoiceState {
- std::optional<Snowflake> ChannelID;
- bool IsDeafened;
- bool IsMuted;
- std::optional<Snowflake> GuildID;
- std::optional<GuildMember> Member;
- bool IsSelfDeafened;
- bool IsSelfMuted;
- bool IsSelfVideo;
- bool IsSelfStream = false;
- std::string SessionID;
- bool IsSuppressed;
- Snowflake UserID;
+struct CallCreateData {
+ Snowflake ChannelID;
+ std::vector<VoiceState> VoiceStates;
+ // Snowflake MessageID;
+ // std::string Region;
+ // std::vector<?> Ringing;
+ // std::vector<?> EmbeddedActivities;
- friend void from_json(const nlohmann::json &j, VoiceState &m);
+ friend void from_json(const nlohmann::json &j, CallCreateData &m);
};
+#endif
diff --git a/src/discord/snowflake.cpp b/src/discord/snowflake.cpp
index 15dacae..680d4da 100644
--- a/src/discord/snowflake.cpp
+++ b/src/discord/snowflake.cpp
@@ -60,6 +60,10 @@ Glib::ustring Snowflake::GetLocalTimestamp() const {
return tmp.data();
}
+uint64_t Snowflake::GetUnixMilliseconds() const noexcept {
+ return (m_num >> 22) + DiscordEpochSeconds * 1000;
+}
+
void from_json(const nlohmann::json &j, Snowflake &s) {
if (j.is_string()) {
std::string tmp;
diff --git a/src/discord/snowflake.hpp b/src/discord/snowflake.hpp
index 2ced46b..68cb5ea 100644
--- a/src/discord/snowflake.hpp
+++ b/src/discord/snowflake.hpp
@@ -16,6 +16,7 @@ struct Snowflake {
[[nodiscard]] bool IsValid() const;
[[nodiscard]] Glib::ustring GetLocalTimestamp() const;
+ [[nodiscard]] uint64_t GetUnixMilliseconds() const noexcept;
bool operator==(const Snowflake &s) const noexcept {
return m_num == s.m_num;
diff --git a/src/discord/voiceclient.cpp b/src/discord/voiceclient.cpp
index 524d930..e9814b6 100644
--- a/src/discord/voiceclient.cpp
+++ b/src/discord/voiceclient.cpp
@@ -112,8 +112,8 @@ void UDPSocket::ReadThread() {
sockaddr_in from;
socklen_t addrlen = sizeof(from);
- tv.tv_sec = 0;
- tv.tv_usec = 1000000;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
fd_set read_fds;
FD_ZERO(&read_fds);
diff --git a/src/notifications/notifications.cpp b/src/notifications/notifications.cpp
index 3c88c44..e95c1c0 100644
--- a/src/notifications/notifications.cpp
+++ b/src/notifications/notifications.cpp
@@ -88,6 +88,8 @@ bool CheckGuildMessage(const Message &message) {
void Notifications::CheckMessage(const Message &message) {
if (!Abaddon::Get().GetSettings().NotificationsEnabled) return;
+ // ignore if silent message
+ if (message.Flags.has_value() && ((*message.Flags & MessageFlags::SUPPRESS_NOTIFICATIONS) == MessageFlags::SUPPRESS_NOTIFICATIONS)) return;
// ignore if our status is do not disturb
if (IsDND()) return;
auto &discord = Abaddon::Get().GetDiscordClient();
diff --git a/src/settings.cpp b/src/settings.cpp
index 82401f5..0b868da 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -70,6 +70,7 @@ void SettingsManager::ReadSettings() {
SMSTR("style", "unreadcolor", UnreadIndicatorColor);
SMBOOL("notifications", "enabled", NotificationsEnabled);
SMBOOL("notifications", "playsound", NotificationsPlaySound);
+ SMBOOL("windows", "hideconsole", HideConsole);
#ifdef WITH_KEYCHAIN
keychain::Error error {};
@@ -153,6 +154,7 @@ void SettingsManager::Close() {
SMSTR("style", "unreadcolor", UnreadIndicatorColor);
SMBOOL("notifications", "enabled", NotificationsEnabled);
SMBOOL("notifications", "playsound", NotificationsPlaySound);
+ SMBOOL("windows", "hideconsole", HideConsole);
#ifdef WITH_KEYCHAIN
keychain::Error error {};
diff --git a/src/settings.hpp b/src/settings.hpp
index 53f3423..40cb1d3 100644
--- a/src/settings.hpp
+++ b/src/settings.hpp
@@ -52,6 +52,9 @@ public:
bool NotificationsEnabled { true };
#endif
bool NotificationsPlaySound { true };
+
+ // [windows]
+ bool HideConsole { false };
};
SettingsManager(const std::string &filename);
diff --git a/src/windows/voicesettingswindow.cpp b/src/windows/voicesettingswindow.cpp
index c009cbf..3749986 100644
--- a/src/windows/voicesettingswindow.cpp
+++ b/src/windows/voicesettingswindow.cpp
@@ -110,9 +110,17 @@ VoiceSettingsWindow::VoiceSettingsWindow()
}
});
+ m_gain.set_increments(1.0, 5.0);
+ m_gain.set_range(0.0, 6969696969.0);
+ m_gain.set_value(Abaddon::Get().GetAudio().GetCaptureGain() * 100.0);
+ m_gain.signal_value_changed().connect([this]() {
+ m_signal_gain.emit(m_gain.get_value() / 100.0);
+ });
+
m_main.add(m_encoding_mode);
m_main.add(m_signal);
m_main.add(m_bitrate);
+ m_main.add(m_gain);
add(m_main);
show_all_children();
@@ -122,4 +130,8 @@ VoiceSettingsWindow::VoiceSettingsWindow()
});
}
+VoiceSettingsWindow::type_signal_gain VoiceSettingsWindow::signal_gain() {
+ return m_signal_gain;
+}
+
#endif
diff --git a/src/windows/voicesettingswindow.hpp b/src/windows/voicesettingswindow.hpp
index cf6b477..9b3498e 100644
--- a/src/windows/voicesettingswindow.hpp
+++ b/src/windows/voicesettingswindow.hpp
@@ -18,8 +18,14 @@ public:
Gtk::ComboBoxText m_encoding_mode;
Gtk::ComboBoxText m_signal;
Gtk::Scale m_bitrate;
+ Gtk::SpinButton m_gain;
private:
+ using type_signal_gain = sigc::signal<void(double)>;
+ type_signal_gain m_signal_gain;
+
+public:
+ type_signal_gain signal_gain();
};
#endif
diff --git a/src/windows/voicewindow.cpp b/src/windows/voicewindow.cpp
index 35ba8c7..a4677c6 100644
--- a/src/windows/voicewindow.cpp
+++ b/src/windows/voicewindow.cpp
@@ -163,6 +163,11 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
m_menu_view_sub.append(m_menu_view_settings);
m_menu_view_settings.signal_activate().connect([this]() {
auto *window = new VoiceSettingsWindow;
+ const auto cb = [this](double gain) {
+ m_capture_gain.set_value(gain * 100.0);
+ m_signal_gain.emit(gain);
+ };
+ window->signal_gain().connect(sigc::track_obj(cb, *this));
window->show();
});