From e1a8d10b61c5f8ca092ba3aa458b661da29ba447 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 30 Sep 2020 19:07:05 +0200 Subject: Matrix: add message replying with ctrl+r, also use shared_ptr for BodyItem --- src/QuickMedia.cpp | 108 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 23 deletions(-) (limited to 'src/QuickMedia.cpp') diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 8a7cbf6..c3e61fe 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -678,7 +678,7 @@ namespace QuickMedia { if(!timestamp.isNumeric()) continue; - auto body_item = std::make_unique(std::move(title_str)); + auto body_item = BodyItem::create(std::move(title_str)); body_item->url = "https://www.youtube.com/watch?v=" + video_id_str; body_item->thumbnail_url = "https://img.youtube.com/vi/" + video_id_str + "/hqdefault.jpg"; body_item->set_description(timestamp_to_relative_time_str(std::max(0l, time_now - timestamp.asInt64()))); @@ -746,7 +746,7 @@ namespace QuickMedia { if(!recommended_title_json.isString()) continue; - auto body_item = std::make_unique(recommended_title_json.asString()); + auto body_item = BodyItem::create(recommended_title_json.asString()); body_item->url = "https://www.youtube.com/watch?v=" + recommended_item_id; body_item->thumbnail_url = "https://img.youtube.com/vi/" + recommended_item_id + "/hqdefault.jpg"; body_items.push_back(std::move(body_item)); @@ -837,7 +837,7 @@ namespace QuickMedia { const Json::Value &manga_name = body["name"]; if(!filename.empty() && manga_name.isString()) { // TODO: Add thumbnail - auto body_item = std::make_unique(manga_name.asString()); + auto body_item = BodyItem::create(manga_name.asString()); if(plugin->name == "manganelo") body_item->url = "https://manganelo.com/manga/" + base64_decode(filename.string()); else if(plugin->name == "mangadex") @@ -3343,14 +3343,23 @@ namespace QuickMedia { // get_all_room_messages is not needed here because its done in the loop, where the initial timeout is 0ms + enum class ChatState { + NAVIGATING, + TYPING_MESSAGE, + REPLYING + }; + Page new_page = Page::CHAT; - bool typing_message = false; + ChatState chat_state = ChatState::NAVIGATING; + + std::shared_ptr replying_to_message; + sf::Text replying_to_text("Replying to:", *font, 18); sf::Sprite logo_sprite(plugin_logo); Entry chat_input("Press ctrl+m to begin writing a message...", font.get(), cjk_font.get()); chat_input.set_editable(false); - chat_input.on_submit_callback = [matrix, &chat_input, &tabs, &selected_tab, ¤t_room_id, &new_page, &typing_message](const sf::String &text) { + chat_input.on_submit_callback = [matrix, &chat_input, &tabs, &selected_tab, ¤t_room_id, &new_page, &chat_state, &replying_to_message](const sf::String &text) mutable { if(tabs[selected_tab].type == ChatTabType::MESSAGES) { if(text.isEmpty()) return false; @@ -3361,12 +3370,12 @@ namespace QuickMedia { if(command == "/upload") { new_page = Page::FILE_MANAGER; chat_input.set_editable(false); - typing_message = false; + chat_state = ChatState::NAVIGATING; return true; } else if(command == "/logout") { new_page = Page::CHAT_LOGIN; chat_input.set_editable(false); - typing_message = false; + chat_state = ChatState::NAVIGATING; return true; } else { fprintf(stderr, "Error: invalid command: %s, expected /upload\n", command.c_str()); @@ -3374,14 +3383,29 @@ namespace QuickMedia { } } - // TODO: Make asynchronous - if(matrix->post_message(current_room_id, text) == PluginResult::OK) { - chat_input.set_editable(false); - typing_message = false; - return true; - } else { - show_notification("QuickMedia", "Failed to post matrix message", Urgency::CRITICAL); - return false; + tabs[selected_tab].body->select_last_item(); + + if(chat_state == ChatState::TYPING_MESSAGE) { + // TODO: Make asynchronous + if(matrix->post_message(current_room_id, text) == PluginResult::OK) { + chat_input.set_editable(false); + chat_state = ChatState::NAVIGATING; + return true; + } else { + show_notification("QuickMedia", "Failed to post matrix message", Urgency::CRITICAL); + return false; + } + } else if(chat_state == ChatState::REPLYING) { + // TODO: Make asynchronous + if(matrix->post_reply(current_room_id, text, replying_to_message->userdata) == PluginResult::OK) { + chat_input.set_editable(false); + chat_state = ChatState::NAVIGATING; + replying_to_message = nullptr; + return true; + } else { + show_notification("QuickMedia", "Failed to post matrix reply", Urgency::CRITICAL); + return false; + } } } return false; @@ -3437,6 +3461,7 @@ namespace QuickMedia { sf::Clock frame_timer; float prev_chat_height = chat_input.get_height(); + float chat_input_height_full = 0.0f; while (current_page == Page::CHAT) { sf::Int32 frame_time_ms = frame_timer.restart().asMilliseconds(); @@ -3444,7 +3469,7 @@ namespace QuickMedia { base_event_handler(event, Page::EXIT, false, false, false); if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus) { redraw = true; - } else if(event.type == sf::Event::KeyPressed && !typing_message) { + } else if(event.type == sf::Event::KeyPressed && chat_state == ChatState::NAVIGATING) { if(event.key.code == sf::Keyboard::Up || event.key.code == sf::Keyboard::PageUp || event.key.code == sf::Keyboard::Home) { bool hit_top = false; switch(event.key.code) { @@ -3516,15 +3541,25 @@ namespace QuickMedia { current_page = Page::VIDEO_CONTENT; video_content_page(); redraw = true; + } else if(tabs[selected_tab].type == ChatTabType::MESSAGES && event.key.control && event.key.code == sf::Keyboard::R) { + std::shared_ptr selected = tabs[selected_tab].body->get_selected_shared(); + if(selected) { + chat_state = ChatState::REPLYING; + replying_to_message = selected; + chat_input.set_editable(true); + } else { + // TODO: Show inline notification + show_notification("QuickMedia", "No message selected for replying"); + } } } - if(!typing_message && tabs[selected_tab].type == ChatTabType::MESSAGES && event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::M && event.key.control) { + if(chat_state == ChatState::NAVIGATING && tabs[selected_tab].type == ChatTabType::MESSAGES && event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::M && event.key.control) { chat_input.set_editable(true); - typing_message = true; + chat_state = ChatState::TYPING_MESSAGE; } - if(typing_message && tabs[selected_tab].type == ChatTabType::MESSAGES) { + if((chat_state == ChatState::TYPING_MESSAGE || chat_state == ChatState::REPLYING) && tabs[selected_tab].type == ChatTabType::MESSAGES) { if(event.type == sf::Event::TextEntered) { //chat_input.onTextEntered(event.text.unicode); // TODO: Also show typing event when ctrl+v pasting? @@ -3538,7 +3573,8 @@ namespace QuickMedia { } } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) { chat_input.set_editable(false); - typing_message = false; + chat_state = ChatState::NAVIGATING; + replying_to_message = nullptr; } //chat_input.on_event(event); chat_input.process_event(event); @@ -3649,7 +3685,8 @@ namespace QuickMedia { body_padding_horizontal = 0.0f; } - chat_input_shade.setSize(sf::Vector2f(window_size.x, chat_input.get_height() + chat_input_padding_y * 2.0f)); + chat_input_height_full = chat_input.get_height() + chat_input_padding_y * 2.0f; + chat_input_shade.setSize(sf::Vector2f(window_size.x, chat_input_height_full)); chat_input_shade.setPosition(0.0f, window_size.y - chat_input_shade.getSize().y); body_pos = sf::Vector2f(body_padding_horizontal, body_padding_vertical + tab_shade_height); @@ -3675,7 +3712,7 @@ namespace QuickMedia { BodyItems result_items; if(matrix->sync() == PluginResult::OK) { fprintf(stderr, "Synced matrix\n"); - if(matrix->get_new_room_messages(sync_future_room_id, result_items) == PluginResult::OK) { + if(matrix->get_new_room_messages(sync_future_room_id, result_items) != PluginResult::OK) { fprintf(stderr, "Failed to get new matrix messages in room: %s\n", sync_future_room_id.c_str()); } } else { @@ -3691,7 +3728,7 @@ namespace QuickMedia { // Ignore finished sync if it happened in another room. When we navigate back to the room we will get the messages again if(sync_future_room_id == current_room_id) { int num_items = tabs[MESSAGES_TAB_INDEX].body->items.size(); - bool scroll_to_end = (num_items > 0 && tabs[MESSAGES_TAB_INDEX].body->get_selected_item() == num_items - 1); + bool scroll_to_end = (num_items == 0 || (num_items > 0 && tabs[MESSAGES_TAB_INDEX].body->get_selected_item() == num_items - 1)); tabs[MESSAGES_TAB_INDEX].body->append_items(std::move(new_body_items)); if(scroll_to_end) tabs[MESSAGES_TAB_INDEX].body->select_last_item(); @@ -3762,6 +3799,31 @@ namespace QuickMedia { window.draw(gradient_points, 4, sf::Quads); // Note: sf::Quads doesn't work with egl } + if(chat_state == ChatState::REPLYING) { + const float margin = 5.0f; + const float replying_to_text_height = replying_to_text.getLocalBounds().height + margin; + + const float item_height = std::min(body_size.y - replying_to_text_height - margin, tabs[MESSAGES_TAB_INDEX].body->get_item_height(replying_to_message.get()) + margin); + + sf::RectangleShape overlay(sf::Vector2f(window_size.x, window_size.y - tab_shade_height - chat_input_height_full)); + overlay.setPosition(0.0f, tab_shade_height); + overlay.setFillColor(sf::Color(0, 0, 0, 240)); + window.draw(overlay); + + sf::Vector2f body_item_pos(body_pos.x, window_size.y - chat_input_height_full - item_height); + sf::Vector2f body_item_size(body_size.x, item_height); + + sf::RectangleShape item_background(sf::Vector2f(window_size.x, body_item_size.y + replying_to_text_height + margin)); + item_background.setPosition(sf::Vector2f(0.0f, body_item_pos.y - replying_to_text_height - margin)); + item_background.setFillColor(back_color); + window.draw(item_background); + + replying_to_text.setPosition(body_item_pos.x, body_item_pos.y - replying_to_text_height); + window.draw(replying_to_text); + + tabs[MESSAGES_TAB_INDEX].body->draw_item(window, replying_to_message.get(), body_item_pos, body_item_size); + } + if(tabs[selected_tab].type == ChatTabType::MESSAGES && !tabs[selected_tab].body->is_last_item_fully_visible()) { window.draw(more_messages_below_rect); } -- cgit v1.2.3