diff options
author | dec05eba <dec05eba@protonmail.com> | 2022-11-12 15:07:16 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2022-11-12 15:07:16 +0100 |
commit | 224a5f3b2ed2141a94940fe73fc8ccb4b2f8d962 (patch) | |
tree | 4a51b48205042279d7cdfa065ae55120a09cc9d9 | |
parent | 4197fd3d7aaa84197eb17e700fb27093293f228b (diff) |
Matrix: fix editing reply breaking body and formatted text, edits should always show latest edit, set read marker to proper latest message
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | plugins/Matrix.hpp | 2 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 52 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 60 |
4 files changed, 69 insertions, 49 deletions
@@ -4,7 +4,6 @@ Show progress of manga in the history tab (current chapter out of total chapters Animate page navigation. Add support for special formatting for posts by admins on imageboards. For image boards, track (You)'s and show notification when somebody replies to your post. -Go to next chapter when reaching the end of the chapter in image endless mode. Make code blocks on matrix and 4chan have a background of a different color. Allow deleting watch history with delete key (and show confirmation). Add navigation to nyaa.si submitter torrents. @@ -57,7 +56,6 @@ Handle M_LIMIT_EXCEEDED in matrix Maybe dont clear cache for body items when filtering. Pressing enter on a pinned message should go to the message in the messages tab. Display file list for nyaa. -Remove reply formatting for NOTICE in matrix as well. Implement our own encryption for matrix. This is also needed to make forwarded message work. Pantalaimon ignores them! Modify matrix sync to download and parse json but not handle it, and then add a function to handle the json. This would allow us to remove all the mutex code if we would call that new method from the main thread. Fetch replies/pinned message using multiple threads. @@ -71,7 +69,6 @@ Disable message input in matrix when muted. Preview rooms? Handle matrix token being invalidated while running. Update upload limit if its updated on the server. -Editing a reply removes reply formatting (both in body and formatted_body). Element also does this when you edit a reply twice. This breaks element mobile that is unable to display replied-to messages without correct formatting (doesn't fetch the replied-to message). This also removes the mentioned name which breaks mention for reply. Implement m.room.tombstone. Show a marker when a room uses encryption. Scroll tabs if there are more than 3 tab items and show arrow on left/right side when there are more items to see. @@ -235,7 +232,6 @@ Sort matrix events by timestamp. This is needed to make name change and other si Automatically cleanup old cache files. Download manga pages in parallel. This helps downloading for certain websites such as mangakatana where a single page can take more than 2 seconds but loading 5 at once allows each page to load in 0.4 seconds. Allow pasting a file link (with or without file://) directly into matrix chat to upload a file (if the chat input is empty). This allows replying-with-media to work with ctrl+v. -Matrix image reply to image reply to text reply is a bit broken in the text formatting. The formatting of replying to a message with an image in matrix is a bit weird. The reply image should be below the replied to message instead of on the left side. Add ctrl+h to go back to the front page. Async load textures (not just images). This can be done efficiently by using different opengl contexts in different threads and making the context current right before a heavy opengl operation. All threads need to set their opengl context often. diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index ac4487c..61239fe 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -29,6 +29,7 @@ namespace QuickMedia { // |image_max_size| 0, 0 means no max size std::string message_to_qm_text(Matrix *matrix, const Message *message, bool allow_formatted_text = true, mgl::vec2i image_max_size = mgl::vec2i(0, 0)); std::string pantalaimon_url_to_homeserver_url(Matrix *matrix, const std::string &url); + Message* get_latest_message_in_edit_chain(Message *message); struct TimestampedDisplayData { std::string data; @@ -713,6 +714,7 @@ namespace QuickMedia { void formatted_body_add_line(RoomData *room, std::string &formatted_body, const std::string &line_str, const std::unordered_map<std::string, CustomEmoji> &custom_emojis); void replace_mentions(RoomData *room, std::string &text); std::string create_formatted_body_for_message_reply(RoomData *room, const Message *message, const std::string &body); + std::string create_formatted_body_for_message_edit(RoomData *room, const Message *replied_to_message, const std::string &body); PluginResult set_pinned_events(RoomData *room, const std::vector<std::string> &pinned_events, bool is_add); diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 57f54a4..e8c76d7 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -5630,16 +5630,18 @@ namespace QuickMedia { } else { // TODO: Properly check reply message objects for mention of user instead of message data, but only when synapse fixes that notifications // are not triggered by reply to a message with our display name/user id. - Message *edited_message_ref = static_cast<Message*>(body_item->userdata); - std::string qm_formatted_text = message_to_qm_text(matrix, message.get()); - - body_item->set_description(std::move(qm_formatted_text)); - if(message->user != me && message_contains_user_mention(matrix, message.get(), my_display_name, me->user_id)) - body_item->set_description_color(get_theme().attention_alert_text_color, true); - else - body_item->set_description_color(get_theme().text_color); - message->replaces = edited_message_ref; - edited_message_ref->replaced_by = message; + Message *edited_message_ref = get_latest_message_in_edit_chain(static_cast<Message*>(body_item->userdata)); + if(message->timestamp > edited_message_ref->timestamp) { + std::string qm_formatted_text = message_to_qm_text(matrix, message.get()); + + body_item->set_description(std::move(qm_formatted_text)); + if(message->user != me && message_contains_user_mention(matrix, message.get(), my_display_name, me->user_id)) + body_item->set_description_color(get_theme().attention_alert_text_color, true); + else + body_item->set_description_color(get_theme().text_color); + message->replaces = edited_message_ref; + edited_message_ref->replaced_by = message; + } } it = unreferenced_events.erase(it); } else { @@ -5671,16 +5673,18 @@ namespace QuickMedia { } else { // TODO: Properly check reply message objects for mention of user instead of message data, but only when synapse fixes that notifications // are not triggered by reply to a message with our display name/user id. - Message *edited_message_ref = static_cast<Message*>(body_item->userdata); - std::string qm_formatted_text = formatted_text_to_qm_text(matrix, message->body.c_str(), message->body.size(), true); - - body_item->set_description(std::move(qm_formatted_text)); - if(message->user != me && message_contains_user_mention(matrix, message.get(), my_display_name, me->user_id)) - body_item->set_description_color(get_theme().attention_alert_text_color, true); - else - body_item->set_description_color(get_theme().text_color); - message->replaces = edited_message_ref; - edited_message_ref->replaced_by = message; + Message *edited_message_ref = get_latest_message_in_edit_chain(static_cast<Message*>(body_item->userdata)); + if(message->timestamp > edited_message_ref->timestamp) { + std::string qm_formatted_text = formatted_text_to_qm_text(matrix, message->body.c_str(), message->body.size(), true); + + body_item->set_description(std::move(qm_formatted_text)); + if(message->user != me && message_contains_user_mention(matrix, message.get(), my_display_name, me->user_id)) + body_item->set_description_color(get_theme().attention_alert_text_color, true); + else + body_item->set_description_color(get_theme().text_color); + message->replaces = edited_message_ref; + edited_message_ref->replaced_by = message; + } } } else { unreferenced_events.push_back(message); @@ -7588,8 +7592,8 @@ namespace QuickMedia { // TODO: Only set read marker once every second if the message is not the last message in the room auto body_items = tabs[selected_tab].body->get_items(); int last_timeline_message = (int)body_items.size() - 1; - for(int i = last_timeline_message - 1; i >= 0; --i) { - BodyItem *item = body_items[i].get(); + for(; last_timeline_message >= 0; --last_timeline_message) { + BodyItem *item = body_items[last_timeline_message].get(); Message *message = static_cast<Message*>(item->userdata); if(item->visible && message && message_is_timeline(message)) break; @@ -7604,9 +7608,7 @@ namespace QuickMedia { // TODO: Maybe set this instead when the mention is visible on the screen? current_room->unread_notification_count = 0; - Message *read_message = static_cast<Message*>(body_items[last_timeline_message]->userdata); - if(read_message->replaced_by) - read_message = read_message->replaced_by.get(); + Message *read_message = get_latest_message_in_edit_chain(static_cast<Message*>(body_items[last_timeline_message]->userdata)); // TODO: What if two messages have the same timestamp? if(!read_message->event_id.empty() && read_message->timestamp > current_room->last_read_message_timestamp) { matrix_chat_page->set_room_as_read(current_room); diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 515ef7a..a821158 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -885,7 +885,6 @@ namespace QuickMedia { auto tag_body_item = BodyItem::create(std::move(tag_name)); tag_body_item->url = tag; tag_body_items_by_name.insert(std::make_pair(tag, TagData{tag_body_item, {}})); - // TODO: Sort by tag priority body->append_item(tag_body_item); tag_data = &tag_body_items_by_name[tag]; tag_data->tag_item = tag_body_item; @@ -4051,7 +4050,7 @@ namespace QuickMedia { "</mx-reply>" + std::move(formatted_body); } - static Message* get_latest_message_in_edit_chain(Message *message) { + Message* get_latest_message_in_edit_chain(Message *message) { while(message) { Message *replaced_by = message->replaced_by.get(); if(!replaced_by) @@ -4152,40 +4151,61 @@ namespace QuickMedia { return PluginResult::OK; } + static Message* get_replied_to_message_recursive(Matrix *matrix, RoomData *room, Message *message) { + while(message) { + if(message->related_event_type == RelatedEventType::REPLY && !message->related_event_id.empty()) + return get_latest_message_in_edit_chain(matrix->get_message_by_id(room, message->related_event_id).get()); + else if(message->related_event_type == RelatedEventType::EDIT && !message->related_event_id.empty()) + message = matrix->get_message_by_id(room, message->related_event_id).get(); + else + return nullptr; + } + return nullptr; + } + + static std::string create_body_for_message_edit(Matrix *matrix, const Message *replied_to_message, const std::string &body) { + if(replied_to_message) + return create_body_for_message_reply(matrix, replied_to_message, " * " + body); + else + return " * " + body; + } + + std::string Matrix::create_formatted_body_for_message_edit(RoomData *room, const Message *replied_to_message, const std::string &body) { + if(replied_to_message) + return create_formatted_body_for_message_reply(room, replied_to_message, " * " + body); + else + return body_to_formatted_body(room, " * " + body); + } + PluginResult Matrix::post_edit(RoomData *room, const std::string &body, void *relates_to, std::string &event_id_response) { Message *relates_to_message_raw = (Message*)relates_to; + Message *replied_to_message = get_replied_to_message_recursive(this, room, relates_to_message_raw); std::string transaction_id = create_transaction_id(); if(transaction_id.empty()) return PluginResult::ERR; my_events_transaction_ids.insert(transaction_id); - std::string formatted_body = body_to_formatted_body(room, body); + rapidjson::Document request_data(rapidjson::kObjectType); + const std::string message_edit_body = create_body_for_message_edit(this, replied_to_message, body); + const std::string formatted_message_edit_body = create_formatted_body_for_message_edit(room, replied_to_message, body); + request_data.AddMember("msgtype", "m.text", request_data.GetAllocator()); + request_data.AddMember("body", rapidjson::StringRef(message_edit_body.c_str()), request_data.GetAllocator()); + request_data.AddMember("format", "org.matrix.custom.html", request_data.GetAllocator()); + request_data.AddMember("formatted_body", rapidjson::StringRef(formatted_message_edit_body.c_str()), request_data.GetAllocator()); + + const std::string formatted_body = body_to_formatted_body(room, body); rapidjson::Document new_content_json(rapidjson::kObjectType); new_content_json.AddMember("msgtype", "m.text", new_content_json.GetAllocator()); new_content_json.AddMember("body", rapidjson::StringRef(body.c_str()), new_content_json.GetAllocator()); - if(!formatted_body.empty()) { - new_content_json.AddMember("format", "org.matrix.custom.html", new_content_json.GetAllocator()); - new_content_json.AddMember("formatted_body", rapidjson::StringRef(formatted_body.c_str()), new_content_json.GetAllocator()); - } + new_content_json.AddMember("format", "org.matrix.custom.html", new_content_json.GetAllocator()); + new_content_json.AddMember("formatted_body", rapidjson::StringRef(formatted_body.c_str()), new_content_json.GetAllocator()); + request_data.AddMember("m.new_content", std::move(new_content_json), request_data.GetAllocator()); rapidjson::Document relates_to_json(rapidjson::kObjectType); relates_to_json.AddMember("event_id", rapidjson::StringRef(relates_to_message_raw->event_id.c_str()), relates_to_json.GetAllocator()); relates_to_json.AddMember("rel_type", "m.replace", relates_to_json.GetAllocator()); - - std::string body_edit_str = " * " + body; - std::string formatted_body_edit_str; - - rapidjson::Document request_data(rapidjson::kObjectType); - request_data.AddMember("msgtype", "m.text", request_data.GetAllocator()); - request_data.AddMember("body", rapidjson::StringRef(body_edit_str.c_str()), request_data.GetAllocator()); - if(!formatted_body.empty()) { - formatted_body_edit_str = " * " + formatted_body; - request_data.AddMember("format", "org.matrix.custom.html", request_data.GetAllocator()); - request_data.AddMember("formatted_body", rapidjson::StringRef(formatted_body_edit_str.c_str()), request_data.GetAllocator()); - } - request_data.AddMember("m.new_content", std::move(new_content_json), request_data.GetAllocator()); request_data.AddMember("m.relates_to", std::move(relates_to_json), request_data.GetAllocator()); rapidjson::StringBuffer buffer; |