From eac2ace1c14c1ae0564d757b26a359c6bd4b754a Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 25 Sep 2020 04:15:17 +0200 Subject: Matrix: fetch previous messages when reaching the top --- src/QuickMedia.cpp | 75 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 26 deletions(-) (limited to 'src/QuickMedia.cpp') diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index e367ae0..c701c14 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -3188,12 +3188,13 @@ namespace QuickMedia { std::vector tabs; int selected_tab = 0; - size_t room_message_index = 0; ChatTab messages_tab; messages_tab.type = ChatTabType::MESSAGES; messages_tab.body = std::make_unique(this, font.get(), bold_font.get(), cjk_font.get()); messages_tab.body->draw_thumbnails = true; + messages_tab.body->thumbnail_resize_target_size.x = 600; + messages_tab.body->thumbnail_resize_target_size.y = 337; //messages_tab.body->line_seperator_color = sf::Color::Transparent; messages_tab.text = sf::Text("Messages", *font, tab_text_size); tabs.push_back(std::move(messages_tab)); @@ -3216,6 +3217,8 @@ namespace QuickMedia { fprintf(stderr, "Loaded matrix sync from cache, num items: %zu\n", tabs[MESSAGES_TAB_INDEX].body->items.size()); } */ + // This is needed to get initial data, with joined rooms etc. TODO: Remove this once its cached + // and allow asynchronous update of rooms if(matrix->sync() != PluginResult::OK) { show_notification("QuickMedia", "Intial matrix sync failed", Urgency::CRITICAL); current_page = Page::EXIT; @@ -3234,9 +3237,11 @@ namespace QuickMedia { if(!tabs[ROOMS_TAB_INDEX].body->items.empty()) current_room_id = tabs[ROOMS_TAB_INDEX].body->items[0]->url; - // TODO: Allow empty initial room (if the user hasn't joined any room yet) + // TODO: Allow empty initial room (if the user hasn't joined any room yet). assert(!current_room_id.empty()); + // get_all_room_messages is not needed here because its done in the loop, where the initial timeout is 0ms + { std::string plugin_logo_path = resources_root + "images/matrix_logo.png"; if(!plugin_logo.loadFromFile(plugin_logo_path)) { @@ -3249,13 +3254,16 @@ namespace QuickMedia { SearchBar chat_input(*font, &plugin_logo, "Send a message..."); chat_input.set_background_color(sf::Color::Transparent); + chat_input.padding_vertical = 10.0f; + + // TODO: Scroll to bottom when receiving new messages, but only if we are already at the bottom? // TODO: Filer for rooms and settings chat_input.onTextUpdateCallback = nullptr; // TODO: Show post message immediately, instead of waiting for sync. Otherwise it can take a while until we receive the message, // which happens when uploading an image. - chat_input.onTextSubmitCallback = [this, matrix, &tabs, &selected_tab, &room_message_index, ¤t_room_id](const std::string &text) -> bool { + chat_input.onTextSubmitCallback = [this, matrix, &tabs, &selected_tab, ¤t_room_id](const std::string &text) -> bool { if(tabs[selected_tab].type == ChatTabType::MESSAGES) { if(text.empty()) return false; @@ -3299,17 +3307,12 @@ namespace QuickMedia { if(selected_item) { current_room_id = selected_item->url; selected_tab = MESSAGES_TAB_INDEX; - room_message_index = 0; tabs[MESSAGES_TAB_INDEX].body->clear_items(); - size_t num_new_messages = 0; BodyItems new_items; // TODO: Make asynchronous - if(matrix->get_room_messages(current_room_id, 0, new_items, num_new_messages) == PluginResult::OK) { - room_message_index += num_new_messages; + if(matrix->get_all_synced_room_messages(current_room_id, new_items) == PluginResult::OK) { tabs[MESSAGES_TAB_INDEX].body->append_items(std::move(new_items)); - if(!tabs[MESSAGES_TAB_INDEX].body->items.empty() && num_new_messages > 0) - tabs[MESSAGES_TAB_INDEX].body->set_selected_item(tabs[MESSAGES_TAB_INDEX].body->items.size() - 1); } else { std::string err_msg = "Failed to get messages in room: " + current_room_id; show_notification("QuickMedia", err_msg, Urgency::CRITICAL); @@ -3320,17 +3323,16 @@ namespace QuickMedia { return false; }; - struct SyncFutureResult { - BodyItems body_items; - size_t num_new_messages; - }; - - std::future sync_future; + std::future sync_future; bool sync_running = false; std::string sync_future_room_id; sf::Clock sync_timer; sf::Int32 sync_min_time_ms = 0; // Sync immediately the first time + std::future previous_messages_future; + bool fetching_previous_messages_running = false; + std::string previous_messages_future_room_id; + const float tab_spacer_height = 0.0f; sf::Vector2f body_pos; sf::Vector2f body_size; @@ -3350,7 +3352,19 @@ namespace QuickMedia { redraw = true; } else if(event.type == sf::Event::KeyPressed) { if(event.key.code == sf::Keyboard::Up) { - tabs[selected_tab].body->select_previous_item(); + bool item_changed = tabs[selected_tab].body->select_previous_item(); + // Top hit + if(!item_changed && !fetching_previous_messages_running) { + fetching_previous_messages_running = true; + previous_messages_future_room_id = current_room_id; + previous_messages_future = std::async(std::launch::async, [this, &previous_messages_future_room_id]() { + Matrix *matrix = static_cast(current_plugin); + BodyItems result_items; + if(matrix->get_previous_room_messages(previous_messages_future_room_id, result_items) != PluginResult::OK) + fprintf(stderr, "Failed to get previous matrix messages in room: %s\n", previous_messages_future_room_id.c_str()); + return result_items; + }); + } } else if(event.key.code == sf::Keyboard::Down) { tabs[selected_tab].body->select_next_item(); } else if(event.key.code == sf::Keyboard::Escape) { @@ -3420,36 +3434,45 @@ namespace QuickMedia { sync_running = true; sync_timer.restart(); sync_future_room_id = current_room_id; - sync_future = std::async(std::launch::async, [this, &sync_future_room_id, room_message_index]() { + sync_future = std::async(std::launch::async, [this, &sync_future_room_id]() { Matrix *matrix = static_cast(current_plugin); - SyncFutureResult result; - result.num_new_messages = 0; + BodyItems result_items; if(matrix->sync() == PluginResult::OK) { fprintf(stderr, "Synced matrix\n"); - if(matrix->get_room_messages(sync_future_room_id, room_message_index, result.body_items, result.num_new_messages) != 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 { fprintf(stderr, "Failed to sync matrix\n"); } - return result; + return result_items; }); } if(sync_future.valid() && sync_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - SyncFutureResult sync_future_result = sync_future.get(); + BodyItems new_body_items = sync_future.get(); // 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) { - room_message_index += sync_future_result.num_new_messages; - tabs[MESSAGES_TAB_INDEX].body->append_items(std::move(sync_future_result.body_items)); - if(!tabs[MESSAGES_TAB_INDEX].body->items.empty() && sync_future_result.num_new_messages > 0) - tabs[MESSAGES_TAB_INDEX].body->set_selected_item(tabs[MESSAGES_TAB_INDEX].body->items.size() - 1); + tabs[MESSAGES_TAB_INDEX].body->append_items(std::move(new_body_items)); } sync_running = false; } + if(previous_messages_future.valid() && previous_messages_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + BodyItems new_body_items = previous_messages_future.get(); + fprintf(stderr, "Finished fetching older messages, num new messages: %zu\n", new_body_items.size()); + // Ignore finished fetch of messages if it happened in another room. When we navigate back to the room we will get the messages again + if(previous_messages_future_room_id == current_room_id) { + size_t num_new_messages = new_body_items.size(); + int selected_item_index = tabs[MESSAGES_TAB_INDEX].body->get_selected_item(); + tabs[MESSAGES_TAB_INDEX].body->prepend_items(std::move(new_body_items)); + tabs[MESSAGES_TAB_INDEX].body->set_selected_item(selected_item_index + num_new_messages); + } + fetching_previous_messages_running = false; + } + chat_input.update(); window.clear(back_color); -- cgit v1.2.3