diff options
-rw-r--r-- | abaddon.cpp | 4 | ||||
-rw-r--r-- | abaddon.hpp | 1 | ||||
-rw-r--r-- | components/chatmessage.cpp | 32 | ||||
-rw-r--r-- | components/chatmessage.hpp | 12 | ||||
-rw-r--r-- | components/chatwindow.cpp | 26 | ||||
-rw-r--r-- | components/chatwindow.hpp | 4 | ||||
-rw-r--r-- | discord/discord.cpp | 24 | ||||
-rw-r--r-- | discord/discord.hpp | 2 | ||||
-rw-r--r-- | discord/objects.cpp | 19 | ||||
-rw-r--r-- | discord/objects.hpp | 2 | ||||
-rw-r--r-- | windows/mainwindow.cpp | 5 | ||||
-rw-r--r-- | windows/mainwindow.hpp | 1 |
12 files changed, 124 insertions, 8 deletions
diff --git a/abaddon.cpp b/abaddon.cpp index 18990e5..954814a 100644 --- a/abaddon.cpp +++ b/abaddon.cpp @@ -87,6 +87,10 @@ void Abaddon::DiscordNotifyMessageDelete(Snowflake id, Snowflake channel_id) { m_main_window->UpdateChatMessageDeleted(id, channel_id); } +void Abaddon::DiscordNotifyMessageUpdateContent(Snowflake id, Snowflake channel_id) { + m_main_window->UpdateChatMessageEditContent(id, channel_id); +} + void Abaddon::ActionConnect() { if (!m_discord.IsStarted()) StartDiscord(); diff --git a/abaddon.hpp b/abaddon.hpp index 8fad286..4f804f0 100644 --- a/abaddon.hpp +++ b/abaddon.hpp @@ -37,6 +37,7 @@ public: void DiscordNotifyChannelListFullRefresh(); void DiscordNotifyMessageCreate(Snowflake id); void DiscordNotifyMessageDelete(Snowflake id, Snowflake channel_id); + void DiscordNotifyMessageUpdateContent(Snowflake id, Snowflake channel_id); private: DiscordClient m_discord; diff --git a/components/chatmessage.cpp b/components/chatmessage.cpp index 6ac4a99..c7cf21b 100644 --- a/components/chatmessage.cpp +++ b/components/chatmessage.cpp @@ -104,6 +104,8 @@ void ChatMessageItem::AddMenuItem(Gtk::MenuItem *item) { } ChatMessageTextItem::ChatMessageTextItem(const MessageData *data) { + m_content = data->Content; + set_can_focus(false); set_editable(false); set_wrap_mode(Gtk::WRAP_WORD_CHAR); @@ -118,14 +120,38 @@ ChatMessageTextItem::ChatMessageTextItem(const MessageData *data) { m_menu_copy_content->signal_activate().connect(sigc::mem_fun(*this, &ChatMessageTextItem::on_menu_copy_content)); } +void ChatMessageTextItem::EditContent(std::string content) { + m_content = content; + get_buffer()->set_text(content); + UpdateAttributes(); +} + void ChatMessageTextItem::on_menu_copy_content() { - auto *data = m_abaddon->GetDiscordClient().GetMessage(ID); - Gtk::Clipboard::get()->set_text(data->Content); + Gtk::Clipboard::get()->set_text(m_content); } void ChatMessageTextItem::MarkAsDeleted() { + m_was_deleted = true; + UpdateAttributes(); +} + +void ChatMessageTextItem::MarkAsEdited() { + m_was_edited = true; + UpdateAttributes(); +} + +void ChatMessageTextItem::UpdateAttributes() { + bool deleted = m_was_deleted; + bool edited = m_was_edited && !m_was_deleted; + auto buf = get_buffer(); + buf->set_text(m_content); Gtk::TextBuffer::iterator start, end; buf->get_bounds(start, end); - buf->insert_markup(end, "<span color='#ff0000'> [deleted]</span>"); + + if (deleted) { + buf->insert_markup(end, "<span color='#ff0000'> [deleted]</span>"); + } else if (edited) { + buf->insert_markup(end, "<span color='#999999'> [edited]</span>"); + } } diff --git a/components/chatmessage.hpp b/components/chatmessage.hpp index dc967af..82f4504 100644 --- a/components/chatmessage.hpp +++ b/components/chatmessage.hpp @@ -37,6 +37,7 @@ public: virtual void ShowMenu(const GdkEvent *event); void AddMenuItem(Gtk::MenuItem *item); virtual void MarkAsDeleted() = 0; + virtual void MarkAsEdited() = 0; protected: void AttachMenuHandler(Gtk::Widget *widget); @@ -55,9 +56,20 @@ class ChatMessageTextItem , public ChatMessageItem { public: ChatMessageTextItem(const MessageData *data); + + void EditContent(std::string content); + virtual void MarkAsDeleted(); + virtual void MarkAsEdited(); protected: + void UpdateAttributes(); + + std::string m_content; + + bool m_was_deleted = false; + bool m_was_edited = false; + void on_menu_copy_content(); Gtk::MenuItem *m_menu_copy_content; Gtk::MenuItem *m_menu_delete_message; diff --git a/components/chatwindow.cpp b/components/chatwindow.cpp index 647d5b2..e3ceb88 100644 --- a/components/chatwindow.cpp +++ b/components/chatwindow.cpp @@ -7,6 +7,7 @@ ChatWindow::ChatWindow() { m_new_message_dispatch.connect(sigc::mem_fun(*this, &ChatWindow::AddNewMessageInternal)); m_new_history_dispatch.connect(sigc::mem_fun(*this, &ChatWindow::AddNewHistoryInternal)); m_message_delete_dispatch.connect(sigc::mem_fun(*this, &ChatWindow::DeleteMessageInternal)); + m_message_edit_dispatch.connect(sigc::mem_fun(*this, &ChatWindow::UpdateMessageContentInternal)); m_main = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); m_listbox = Gtk::manage(new Gtk::ListBox); @@ -182,6 +183,12 @@ void ChatWindow::DeleteMessage(Snowflake id) { m_message_delete_dispatch.emit(); } +void ChatWindow::UpdateMessageContent(Snowflake id) { + std::scoped_lock<std::mutex> guard(m_update_mutex); + m_message_edit_queue.push(id); + m_message_edit_dispatch.emit(); +} + void ChatWindow::ClearMessages() { std::scoped_lock<std::mutex> guard(m_update_mutex); m_message_set_queue.push(std::unordered_set<const MessageData *>()); @@ -241,6 +248,25 @@ void ChatWindow::DeleteMessageInternal() { item->MarkAsDeleted(); } +void ChatWindow::UpdateMessageContentInternal() { + Snowflake id; + { + std::scoped_lock<std::mutex> guard(m_update_mutex); + id = m_message_edit_queue.front(); + m_message_edit_queue.pop(); + } + + if (m_id_to_widget.find(id) == m_id_to_widget.end()) + return; + + auto *msg = m_abaddon->GetDiscordClient().GetMessage(id); + auto *item = dynamic_cast<ChatMessageTextItem *>(m_id_to_widget.at(id)); + if (item != nullptr) { + item->EditContent(msg->Content); + item->MarkAsEdited(); + } +} + void ChatWindow::SetMessagesInternal() { auto children = m_listbox->get_children(); auto it = children.begin(); diff --git a/components/chatwindow.hpp b/components/chatwindow.hpp index 5054a85..f5342e9 100644 --- a/components/chatwindow.hpp +++ b/components/chatwindow.hpp @@ -19,6 +19,7 @@ public: void AddNewMessage(Snowflake id); void AddNewHistory(const std::vector<MessageData> &msgs); void DeleteMessage(Snowflake id); + void UpdateMessageContent(Snowflake id); void ClearMessages(); protected: @@ -27,6 +28,7 @@ protected: void AddNewMessageInternal(); void AddNewHistoryInternal(); void DeleteMessageInternal(); + void UpdateMessageContentInternal(); ChatDisplayType GetMessageDisplayType(const MessageData *data); void ProcessMessage(const MessageData *data, bool prepend = false); int m_num_rows = 0; // youd think thered be a Gtk::ListBox::get_row_count or something but nope @@ -45,6 +47,8 @@ protected: std::queue<std::vector<Snowflake>> m_new_history_queue; Glib::Dispatcher m_message_delete_dispatch; std::queue<Snowflake> m_message_delete_queue; + Glib::Dispatcher m_message_edit_dispatch; + std::queue<Snowflake> m_message_edit_queue; std::mutex m_update_mutex; Snowflake m_active_channel; diff --git a/discord/discord.cpp b/discord/discord.cpp index 6c61be2..37ac59f 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -177,10 +177,6 @@ void DiscordClient::UpdateToken(std::string token) { m_http.SetAuth(token); } -std::string DiscordClient::DecompressGatewayMessage(std::string str) { - return std::string(); -} - void DiscordClient::HandleGatewayMessageRaw(std::string str) { // handles multiple zlib compressed messages, calling HandleGatewayMessage when a full message is received std::vector<uint8_t> buf(str.begin(), str.end()); @@ -254,6 +250,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) { case GatewayEvent::MESSAGE_DELETE: { HandleGatewayMessageDelete(m); } break; + case GatewayEvent::MESSAGE_UPDATE: { + HandleGatewayMessageUpdate(m); + } break; } } break; default: @@ -289,11 +288,27 @@ void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) { StoreMessage(data.ID, data); m_abaddon->DiscordNotifyMessageCreate(data.ID); } + void DiscordClient::HandleGatewayMessageDelete(const GatewayMessage &msg) { MessageDeleteData data = msg.Data; m_abaddon->DiscordNotifyMessageDelete(data.ID, data.ChannelID); } +void DiscordClient::HandleGatewayMessageUpdate(const GatewayMessage &msg) { + // less than stellar way of doing this probably + MessageData data; + data.from_json_edited(msg.Data); + + if (m_messages.find(data.ID) == m_messages.end()) return; + + auto ¤t = m_messages.at(data.ID); + + if (data.Content != current.Content) { + current.Content = data.Content; + m_abaddon->DiscordNotifyMessageUpdateContent(data.ID, data.ChannelID); + } +} + void DiscordClient::StoreGuild(Snowflake id, const GuildData &g) { assert(id.IsValid() && id == g.ID); m_guilds[id] = g; @@ -355,4 +370,5 @@ void DiscordClient::LoadEventMap() { m_event_map["READY"] = GatewayEvent::READY; m_event_map["MESSAGE_CREATE"] = GatewayEvent::MESSAGE_CREATE; m_event_map["MESSAGE_DELETE"] = GatewayEvent::MESSAGE_DELETE; + m_event_map["MESSAGE_UPDATE"] = GatewayEvent::MESSAGE_UPDATE; } diff --git a/discord/discord.hpp b/discord/discord.hpp index 54ffe78..87e09f4 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -78,12 +78,12 @@ private: std::vector<uint8_t> m_compressed_buf; std::vector<uint8_t> m_decompress_buf; z_stream m_zstream; - std::string DecompressGatewayMessage(std::string str); void HandleGatewayMessageRaw(std::string str); void HandleGatewayMessage(std::string str); void HandleGatewayReady(const GatewayMessage &msg); void HandleGatewayMessageCreate(const GatewayMessage &msg); void HandleGatewayMessageDelete(const GatewayMessage &msg); + void HandleGatewayMessageUpdate(const GatewayMessage &msg); void HeartbeatThread(); void SendIdentify(); diff --git a/discord/objects.cpp b/discord/objects.cpp index 8de0c68..ed556f4 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -155,6 +155,25 @@ void from_json(const nlohmann::json &j, MessageData &m) { JS_O("flags", m.Flags); } +// probably gonna need to return present keys +void MessageData::from_json_edited(const nlohmann::json &j) { + JS_D("id", ID); + JS_D("channel_id", ChannelID); + JS_O("guild_id", GuildID); + JS_O("author", Author); + JS_O("content", Content); + JS_O("timestamp", Timestamp); + JS_ON("edited_timestamp", EditedTimestamp); + JS_O("tts", IsTTS); + JS_O("mention_everyone", DoesMentionEveryone); + JS_O("mentions", Mentions); + JS_O("nonce", Nonce); + JS_O("pinned", IsPinned); + JS_O("webhook_id", WebhookID); + JS_O("type", Type); + JS_O("flags", Flags); +} + void from_json(const nlohmann::json &j, MessageDeleteData &m) { JS_D("id", m.ID); JS_D("channel_id", m.ChannelID); diff --git a/discord/objects.hpp b/discord/objects.hpp index c56b766..a8bf082 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -63,6 +63,7 @@ enum class GatewayEvent : int { READY, MESSAGE_CREATE, MESSAGE_DELETE, + MESSAGE_UPDATE, }; struct GatewayMessage { @@ -359,6 +360,7 @@ struct MessageData { MessageFlags Flags = MessageFlags::NONE; // opt friend void from_json(const nlohmann::json &j, MessageData &m); + void from_json_edited(const nlohmann::json &j); // for MESSAGE_UPDATE }; struct MessageDeleteData { diff --git a/windows/mainwindow.cpp b/windows/mainwindow.cpp index 24f39f3..6f0bfaa 100644 --- a/windows/mainwindow.cpp +++ b/windows/mainwindow.cpp @@ -115,6 +115,11 @@ void MainWindow::UpdateChatMessageDeleted(Snowflake id, Snowflake channel_id) { m_chat.DeleteMessage(id); } +void MainWindow::UpdateChatMessageEditContent(Snowflake id, Snowflake channel_id) { + if (channel_id == GetChatActiveChannel()) + m_chat.UpdateMessageContent(id); +} + void MainWindow::UpdateChatPrependHistory(const std::vector<MessageData> &msgs) { m_chat.AddNewHistory(msgs); } diff --git a/windows/mainwindow.hpp b/windows/mainwindow.hpp index 10d897c..43dd540 100644 --- a/windows/mainwindow.hpp +++ b/windows/mainwindow.hpp @@ -17,6 +17,7 @@ public: Snowflake GetChatActiveChannel() const; void UpdateChatNewMessage(Snowflake id); void UpdateChatMessageDeleted(Snowflake id, Snowflake channel_id); + void UpdateChatMessageEditContent(Snowflake id, Snowflake channel_id); void UpdateChatPrependHistory(const std::vector<MessageData> &msgs); protected: |