From a29f310b8ad0b088860fe05a5499bccef963a503 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 22 Sep 2020 01:42:51 +0200 Subject: Add ctrl+i to view attached images/videos to matrix posts --- README.md | 3 ++- plugins/Matrix.hpp | 11 +++++++- src/Body.cpp | 2 +- src/QuickMedia.cpp | 15 +++++++++++ src/plugins/Matrix.cpp | 73 ++++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 87 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 0578f8f..b52b382 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,8 @@ Press `I` to switch between single image and scroll image view mode when reading Press `Middle mouse button` to "autoscroll" in scrolling image view mode.\ Press `Tab` to autocomplete a search when autocomplete is available (currently only available for youtube).\ Press `Tab` to switch between username/password field in login panel.\ -Press `Ctrl + V` to paste the content of your clipboard into the search bar. +Press `Ctrl + V` to paste the content of your clipboard into the search bar.\ +Press `Ctrl + I` to view image/video attached to matrix message. ## Video controls Press `space` to pause/unpause video. `Double-click` video to fullscreen or leave fullscreen. # Mangadex diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index c7cb154..b2e1711 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -10,10 +10,19 @@ namespace QuickMedia { std::string avatar_url; }; + enum class MessageType { + TEXT, + IMAGE, + VIDEO + }; + struct Message { // Index into |RoomData.user_info| size_t user_id; - std::string msg; + std::string body; + std::string url; + std::string thumbnail_url; + MessageType type; }; struct RoomData { diff --git a/src/Body.cpp b/src/Body.cpp index ab68a61..20911de 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -146,7 +146,7 @@ namespace QuickMedia { } BodyItem* Body::get_selected() const { - if(items.empty() || !items[selected_item]->visible) + if(selected_item < 0 || selected_item >= (int)items.size() || !items[selected_item]->visible) return nullptr; return items[selected_item].get(); } diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index d756b98..f57b674 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -3159,6 +3159,21 @@ namespace QuickMedia { selected_tab = std::min((int)tabs.size() - 1, selected_tab + 1); search_bar->clear(); } + + if(tabs[selected_tab].type == ChatTabType::MESSAGES && event.key.control && event.key.code == sf::Keyboard::I) { + BodyItem *selected_item = tabs[selected_tab].body->get_selected(); + if(!selected_item) + continue; + + if(selected_item->url.empty()) + continue; + + page_stack.push(Page::CHAT); + watched_videos.clear(); + content_url = selected_item->url; + current_page = Page::VIDEO_CONTENT; + video_content_page(); + } } } diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index ad0dfea..8c6d07d 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -9,8 +9,12 @@ // Send read receipt to server and receive notifications in /sync and show the notifications. // Delete messages. // Edit messages. -// Show embedded images/videos. +// Show images/videos inline. // TODO: Verify if buffer of size 512 is enough for endpoints +// TODO: POST /_matrix/client/r0/rooms/{roomId}/read_markers after 5 seconds of receiving a message when the client is focused +// to mark messages as read +// When reaching top/bottom message, show older/newer messages. +// Remove older messages (outside screen) to save memory. Reload them when the selected body item is the top/bottom one. namespace QuickMedia { Matrix::Matrix() : Plugin("matrix") { @@ -179,15 +183,17 @@ namespace QuickMedia { size_t prev_user_id = -1; for(auto it = room_it->second->messages.begin() + start_index, end = room_it->second->messages.end(); it != end; ++it) { const UserInfo &user_info = room_it->second->user_info[it->user_id]; - if(it->user_id == prev_user_id) { + if(it->user_id == prev_user_id && it->url.empty()) { assert(!result_items.empty()); result_items.back()->append_description("\n"); - result_items.back()->append_description(it->msg); + result_items.back()->append_description(it->body); } else { auto body_item = std::make_unique(""); body_item->author = user_info.display_name; - body_item->set_description(it->msg); + body_item->set_description(it->body); body_item->thumbnail_url = user_info.avatar_url; + // TODO: Show image thumbnail inline instead of url to image + body_item->url = it->url; result_items.push_back(std::move(body_item)); prev_user_id = it->user_id; } @@ -261,6 +267,7 @@ namespace QuickMedia { room_it->second->prev_batch = prev_batch_json.asString(); const Json::Value &events_json = timeline_json["events"]; + events_add_user_info(events_json, room_it->second.get()); events_add_messages(events_json, room_it->second.get(), MessageDirection::AFTER); events_set_room_name(events_json, room_it->second.get()); } @@ -307,7 +314,7 @@ namespace QuickMedia { UserInfo user_info; user_info.avatar_url = avatar_url_json.asString(); - if(user_info.avatar_url.size() >= 6) + if(strncmp(user_info.avatar_url.c_str(), "mxc://", 6) == 0) user_info.avatar_url.erase(user_info.avatar_url.begin(), user_info.avatar_url.begin() + 6); // TODO: What if the user hasn't selected an avatar? user_info.avatar_url = homeserver + "/_matrix/media/r0/thumbnail/" + user_info.avatar_url + "?width=32&height=32&method=crop"; @@ -342,11 +349,7 @@ namespace QuickMedia { continue; const Json::Value &content_type = content_json["msgtype"]; - if(!content_type.isString() || strcmp(content_type.asCString(), "m.text") != 0) - continue; - - const Json::Value &body_json = content_json["body"]; - if(!body_json.isString()) + if(!content_type.isString()) continue; auto user_it = room_data->user_info_by_user_id.find(sender_json_str); @@ -355,10 +358,52 @@ namespace QuickMedia { continue; } - Message message; - message.user_id = user_it->second; - message.msg = body_json.asString(); - new_messages.push_back(std::move(message)); + const Json::Value &body_json = content_json["body"]; + if(!body_json.isString()) + continue; + + if(strcmp(content_type.asCString(), "m.text") == 0) { + Message message; + message.user_id = user_it->second; + message.body = body_json.asString(); + message.type = MessageType::TEXT; + new_messages.push_back(std::move(message)); + } else if(strcmp(content_type.asCString(), "m.image") == 0) { + const Json::Value &url_json = content_json["url"]; + if(!url_json.isString() || strncmp(url_json.asCString(), "mxc://", 6) != 0) + continue; + + Message message; + message.user_id = user_it->second; + message.body = body_json.asString(); + message.url = homeserver + "/_matrix/media/r0/download/" + url_json.asString().substr(6); + message.type = MessageType::IMAGE; + new_messages.push_back(std::move(message)); + } else if(strcmp(content_type.asCString(), "m.video") == 0) { + const Json::Value &url_json = content_json["url"]; + if(!url_json.isString() || strncmp(url_json.asCString(), "mxc://", 6) != 0) + continue; + + Message message; + + const Json::Value &info_json = content_json["info"]; + if(info_json.isString()) { + const Json::Value &thumbnail_url_json = info_json["thumbnail_url"]; + if(thumbnail_url_json.isString()) { + std::string thumbnail_str = thumbnail_url_json.asString(); + if(strncmp(thumbnail_str.c_str(), "mxc://", 6) == 0) { + thumbnail_str.erase(thumbnail_str.begin(), thumbnail_str.begin() + 6); + message.thumbnail_url = homeserver + "/_matrix/media/r0/download/" + std::move(thumbnail_str); + } + } + } + + message.user_id = user_it->second; + message.body = body_json.asString(); + message.url = homeserver + "/_matrix/media/r0/download/" + url_json.asString().substr(6); + message.type = MessageType::VIDEO; + new_messages.push_back(std::move(message)); + } } if(message_dir == MessageDirection::BEFORE) { -- cgit v1.2.3