From e68ff632e2f54c705ae1d69033e58a8f2d1ca00c Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 16 Nov 2020 13:32:49 +0100 Subject: Matrix: show provisional messages as the message is being sent and received --- src/Body.cpp | 19 +++- src/QuickMedia.cpp | 282 +++++++++++++++++++++++++++++++++++-------------- src/Text.cpp | 6 -- src/plugins/Matrix.cpp | 37 +++++-- 4 files changed, 242 insertions(+), 102 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index 2cf6f78..b456841 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -260,7 +260,7 @@ namespace QuickMedia { // TODO: Optimize by resizing |items| before insert void Body::insert_items_by_timestamps(BodyItems new_items) { for(auto &new_item : new_items) { - insert_item_by_timestamp(std::move(new_item)); + insert_item_by_timestamp(new_item); } } @@ -435,8 +435,8 @@ namespace QuickMedia { pos.y += page_scroll; - last_item_fully_visible = true; - items_cut_off = false; + bool last_item_fully_visible_set = false; + bool items_cut_off_set = false; sf::Vector2u window_size = window.getSize(); @@ -453,8 +453,10 @@ namespace QuickMedia { float item_height = get_item_height(item.get(), size.x); prev_pos.y -= (item_height + spacing_y); - if(prev_pos.y < start_y) + if(prev_pos.y < start_y) { items_cut_off = true; + items_cut_off_set = true; + } if(prev_pos.y + item_height + spacing_y <= start_y) break; @@ -480,6 +482,8 @@ namespace QuickMedia { if(after_pos.y - start_y >= size.y) { last_item_fully_visible = false; items_cut_off = true; + last_item_fully_visible_set = true; + items_cut_off_set = true; break; } @@ -497,6 +501,8 @@ namespace QuickMedia { if(after_pos.y - start_y > size.y) { last_item_fully_visible = false; items_cut_off = true; + last_item_fully_visible_set = true; + items_cut_off_set = true; } else { last_fully_visible_item = i; } @@ -507,6 +513,11 @@ namespace QuickMedia { offset_to_bottom = size.y - (after_pos.y - start_y); + if(!last_item_fully_visible_set) + last_item_fully_visible = true; + if(!items_cut_off_set) + items_cut_off = false; + for(auto it = item_thumbnail_textures.begin(); it != item_thumbnail_textures.end();) { if(!it->second->referenced) it = item_thumbnail_textures.erase(it); diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index c01ce59..5c97c2d 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -3199,41 +3199,50 @@ namespace QuickMedia { bool redraw = true; // TODO: Optimize with hash map? - auto find_body_item_by_event_id = [](std::shared_ptr *body_items, size_t num_body_items, const std::string &event_id) -> std::shared_ptr { + auto find_body_item_by_event_id = [](std::shared_ptr *body_items, size_t num_body_items, const std::string &event_id, size_t *index_result = nullptr) -> std::shared_ptr { for(size_t i = 0; i < num_body_items; ++i) { auto &body_item = body_items[i]; - if(static_cast(body_item->userdata)->event_id == event_id) + if(static_cast(body_item->userdata)->event_id == event_id) { + if(index_result) + *index_result = i; return body_item; + } } return nullptr; }; // TODO: What if these never end up referencing events? clean up automatically after a while? - std::unordered_map unreferenced_event_by_room; + Messages unreferenced_events; auto set_body_as_deleted = [¤t_room](Message *message, BodyItem *body_item) { body_item->embedded_item = nullptr; body_item->embedded_item_status = FetchStatus::NONE; + message->type = MessageType::REDACTION; + message->related_event_id.clear(); + message->related_event_type = RelatedEventType::NONE; body_item->thumbnail_url = current_room->get_user_avatar_url(message->user); body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; + body_item->set_description("Message deleted"); body_item->set_description_color(sf::Color::White); body_item->thumbnail_size = sf::Vector2i(32, 32); }; // TODO: Optimize with hash map? - auto resolve_unreferenced_events_with_body_items = [&set_body_as_deleted, &unreferenced_event_by_room, ¤t_room, &find_body_item_by_event_id](std::shared_ptr *body_items, size_t num_body_items) { - auto &unreferenced_events = unreferenced_event_by_room[current_room]; + auto resolve_unreferenced_events_with_body_items = [&set_body_as_deleted, &unreferenced_events, &find_body_item_by_event_id](std::shared_ptr *body_items, size_t num_body_items) { for(auto it = unreferenced_events.begin(); it != unreferenced_events.end(); ) { auto &message = *it; // TODO: Make redacted/edited events as (redacted)/(edited) in the body if(message->related_event_type == RelatedEventType::REDACTION || message->related_event_type == RelatedEventType::EDIT) { auto body_item = find_body_item_by_event_id(body_items, num_body_items, message->related_event_id); if(body_item) { - body_item->set_description(message_get_body_remove_formatting(message.get())); // TODO: Append the new message to the body item so the body item should have a list of edit events //body_item->userdata = message.get(); - if(message->related_event_type == RelatedEventType::REDACTION) + if(message->related_event_type == RelatedEventType::REDACTION) { set_body_as_deleted(message.get(), body_item.get()); + } else { + body_item->set_description(message_get_body_remove_formatting(message.get())); + body_item->set_description_color(sf::Color::White); + } it = unreferenced_events.erase(it); } else { ++it; @@ -3245,22 +3254,24 @@ namespace QuickMedia { }; // TODO: Optimize with hash map? - auto modify_related_messages_in_current_room = [&set_body_as_deleted, &unreferenced_event_by_room, ¤t_room, &find_body_item_by_event_id, &tabs](Messages &messages) { + auto modify_related_messages_in_current_room = [&set_body_as_deleted, &unreferenced_events, &find_body_item_by_event_id, &tabs](Messages &messages) { if(messages.empty()) return; - auto &unreferenced_events = unreferenced_event_by_room[current_room]; auto &body_items = tabs[MESSAGES_TAB_INDEX].body->items; for(auto &message : messages) { // TODO: Make redacted/edited events as (redacted)/(edited) in the body if(message->related_event_type == RelatedEventType::REDACTION || message->related_event_type == RelatedEventType::EDIT) { auto body_item = find_body_item_by_event_id(body_items.data(), body_items.size(), message->related_event_id); if(body_item) { - body_item->set_description(message_get_body_remove_formatting(message.get())); // TODO: Append the new message to the body item so the body item should have a list of edit events //body_item->userdata = message.get(); - if(message->related_event_type == RelatedEventType::REDACTION) + if(message->related_event_type == RelatedEventType::REDACTION) { set_body_as_deleted(message.get(), body_item.get()); + } else { + body_item->set_description(message_get_body_remove_formatting(message.get())); + body_item->set_description_color(sf::Color::White); + } } else { unreferenced_events.push_back(message); } @@ -3350,18 +3361,64 @@ namespace QuickMedia { chat_input.draw_background = false; chat_input.set_editable(false); - MessageQueue> post_task_queue; - auto post_thread_handler = [&post_task_queue]() { + struct ProvisionalMessage { + std::shared_ptr body_item; + std::shared_ptr message; + std::string event_id; + }; + + std::vector unresolved_provisional_messages; // |event_id| is always empty in this. Use |message->event_id| instead + std::optional provisional_message; + MessageQueue provisional_message_queue; + MessageQueue> post_task_queue; + auto post_thread_handler = [&provisional_message_queue, &post_task_queue]() { while(true) { - std::optional> post_task_opt = post_task_queue.pop_wait(); + std::optional> post_task_opt = post_task_queue.pop_wait(); if(!post_task_opt) break; - post_task_opt.value()(); + provisional_message_queue.push(post_task_opt.value()()); } }; std::thread post_thread(post_thread_handler); - chat_input.on_submit_callback = [this, &chat_input, &selected_tab, ¤t_room, &new_page, &chat_state, ¤tly_operating_on_item, &post_task_queue](std::string text) mutable { + auto resolve_provisional_messages = [&unresolved_provisional_messages](Messages &messages) { + if(messages.empty() || unresolved_provisional_messages.empty()) + return; + + for(auto it = unresolved_provisional_messages.begin(); it != unresolved_provisional_messages.end();) { + auto find_it = std::find_if(messages.cbegin(), messages.cend(), [&it](const std::shared_ptr &message) { + return message->event_id == it->message->event_id; + }); + if(find_it != messages.end()) { + it->body_item->set_description_color(sf::Color::White); + it->body_item->userdata = find_it->get(); // This is ok because the message is added to |all_messages| + it = unresolved_provisional_messages.erase(it); + messages.erase(find_it); + } else { + ++it; + } + } + }; + + auto upload_file = [this, &tabs, ¤t_room](const std::string &filepath) { + TaskResult post_file_result = run_task_with_loading_screen([this, ¤t_room, filepath]() { + std::string event_id_response; + std::string err_msg; + if(matrix->post_file(current_room, filepath, event_id_response, err_msg) == PluginResult::OK) { + return true; + } else { + show_notification("QuickMedia", "Failed to upload media to room, error: " + err_msg, Urgency::CRITICAL); + return false; + } + }); + + if(post_file_result == TaskResult::TRUE) { + if(tabs[MESSAGES_TAB_INDEX].body->is_last_item_fully_visible()) + tabs[MESSAGES_TAB_INDEX].body->select_last_item(); + } + }; + + chat_input.on_submit_callback = [this, &tabs, &me, &chat_input, &selected_tab, ¤t_room, &new_page, &chat_state, ¤tly_operating_on_item, &post_task_queue, &unreferenced_events, &find_body_item_by_event_id](std::string text) mutable { if(!current_room) return false; @@ -3400,34 +3457,82 @@ namespace QuickMedia { } } + auto message = std::make_shared(); + message->user = matrix->get_me(current_room); + message->body = text; + message->type = MessageType::TEXT; + message->timestamp = time(NULL) * 1000; + + const sf::Color provisional_message_color(171, 175, 180); + + int num_items = tabs[MESSAGES_TAB_INDEX].body->items.size(); + bool scroll_to_end = num_items == 0; + if(tabs[MESSAGES_TAB_INDEX].body->is_selected_item_last_visible_item() && selected_tab == MESSAGES_TAB_INDEX) + scroll_to_end = true; + if(chat_state == ChatState::TYPING_MESSAGE) { - post_task_queue.push([this, ¤t_room, text, msgtype]() { - if(matrix->post_message(current_room, text, std::nullopt, std::nullopt, msgtype) != PluginResult::OK) + auto body_item = message_to_body_item(current_room, message.get(), current_room->get_user_avatar_url(me), me->user_id); + body_item->set_description_color(provisional_message_color); + tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps({body_item}); + post_task_queue.push([this, ¤t_room, text, msgtype, body_item, message]() { + ProvisionalMessage provisional_message; + provisional_message.body_item = body_item; + provisional_message.message = message; + if(matrix->post_message(current_room, text, provisional_message.event_id, std::nullopt, std::nullopt, msgtype) != PluginResult::OK) fprintf(stderr, "Failed to post matrix message\n"); + return provisional_message; }); chat_input.set_editable(false); chat_state = ChatState::NAVIGATING; + if(scroll_to_end) + tabs[MESSAGES_TAB_INDEX].body->select_last_item(); return true; } else if(chat_state == ChatState::REPLYING) { void *related_to_message = currently_operating_on_item->userdata; - post_task_queue.push([this, ¤t_room, text, related_to_message]() { - if(matrix->post_reply(current_room, text, related_to_message) != PluginResult::OK) + message->related_event_type = RelatedEventType::REPLY; + message->related_event_id = static_cast(related_to_message)->event_id; + auto body_item = message_to_body_item(current_room, message.get(), current_room->get_user_avatar_url(me), me->user_id); + body_item->set_description_color(provisional_message_color); + tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps({body_item}); + post_task_queue.push([this, ¤t_room, text, related_to_message, body_item, message]() { + ProvisionalMessage provisional_message; + provisional_message.body_item = body_item; + provisional_message.message = message; + if(matrix->post_reply(current_room, text, related_to_message, provisional_message.event_id) != PluginResult::OK) fprintf(stderr, "Failed to post matrix reply\n"); + return provisional_message; }); chat_input.set_editable(false); chat_state = ChatState::NAVIGATING; currently_operating_on_item = nullptr; + if(scroll_to_end) + tabs[MESSAGES_TAB_INDEX].body->select_last_item(); return true; } else if(chat_state == ChatState::EDITING) { void *related_to_message = currently_operating_on_item->userdata; - post_task_queue.push([this, ¤t_room, text, related_to_message]() { - if(matrix->post_edit(current_room, text, related_to_message) != PluginResult::OK) - fprintf(stderr, "Failed to post matrix edit\n"); - }); - chat_input.set_editable(false); - chat_state = ChatState::NAVIGATING; - currently_operating_on_item = nullptr; - return true; + message->related_event_type = RelatedEventType::EDIT; + message->related_event_id = static_cast(related_to_message)->event_id; + auto body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), message->related_event_id); + if(body_item) { + body_item->set_description(text); + body_item->set_description_color(provisional_message_color); + unreferenced_events.push_back(message); + post_task_queue.push([this, ¤t_room, text, related_to_message, message]() { + ProvisionalMessage provisional_message; + provisional_message.message = message; + if(matrix->post_edit(current_room, text, related_to_message, provisional_message.event_id) != PluginResult::OK) + fprintf(stderr, "Failed to post matrix edit\n"); + return provisional_message; + }); + + chat_input.set_editable(false); + chat_state = ChatState::NAVIGATING; + currently_operating_on_item = nullptr; + return true; + } else { + show_notification("QuickMedia", "Failed to edit message. Message refers to a non-existing message", Urgency::CRITICAL); + return false; + } } } return false; @@ -3567,10 +3672,10 @@ namespace QuickMedia { bool fetched_enough_messages = false; bool initial_prev_messages_fetch = true; - auto fetch_more_previous_messages_if_needed = [this, &all_messages, ¤t_room, &fetched_enough_messages, &previous_messages_future, &initial_prev_messages_fetch]() { + auto fetch_more_previous_messages_if_needed = [this, &tabs, ¤t_room, &fetched_enough_messages, &previous_messages_future, &initial_prev_messages_fetch]() { if(!fetched_enough_messages && !previous_messages_future.ready()) { bool fetch_latest_messages = !matrix->is_initial_sync_finished() && initial_prev_messages_fetch; - if(all_messages.size() < 10) { + if(!tabs[MESSAGES_TAB_INDEX].body->is_body_full_with_items()) { previous_messages_future = [this, ¤t_room, fetch_latest_messages]() { Messages messages; if(matrix->get_previous_room_messages(current_room, messages, fetch_latest_messages) != PluginResult::OK) @@ -3794,7 +3899,7 @@ namespace QuickMedia { } }; - auto cleanup_tasks = [&set_read_marker_future, &fetch_message_future, &typing_state_queue, &typing_state_thread, &post_task_queue, &post_thread, &tabs]() { + auto cleanup_tasks = [&set_read_marker_future, &fetch_message_future, &typing_state_queue, &typing_state_thread, &post_task_queue, &provisional_message_queue, &post_thread, &tabs]() { set_read_marker_future.cancel(); fetch_message_future.cancel(); typing_state_queue.close(); @@ -3807,6 +3912,7 @@ namespace QuickMedia { program_kill_in_thread(post_thread.get_id()); post_thread.join(); } + provisional_message_queue.clear(); //unreferenced_event_by_room.clear(); @@ -3940,20 +4046,7 @@ namespace QuickMedia { if(event.key.control && event.key.code == sf::Keyboard::V) { frame_skip_text_entry = true; // TODO: Upload multiple files. - std::string selected_file = sf::Clipboard::getString(); - TaskResult post_file_result = run_task_with_loading_screen([this, ¤t_room, selected_file]() { - std::string err_msg; - if(matrix->post_file(current_room, selected_file, err_msg) == PluginResult::OK) { - return true; - } else { - show_notification("QuickMedia", "Failed to upload media to room, error: " + err_msg, Urgency::CRITICAL); - return false; - } - }); - if(post_file_result == TaskResult::TRUE) { - if(tabs[MESSAGES_TAB_INDEX].body->is_last_item_fully_visible()) - tabs[MESSAGES_TAB_INDEX].body->select_last_item(); - } + upload_file(sf::Clipboard::getString()); } if(event.key.code == sf::Keyboard::R) { @@ -3961,10 +4054,15 @@ namespace QuickMedia { std::shared_ptr selected = tabs[selected_tab].body->get_selected_shared(); if(selected) { if(!is_state_message_type(static_cast(selected->userdata))) { - chat_state = ChatState::REPLYING; - currently_operating_on_item = selected; - chat_input.set_editable(true); - replying_to_text.setString("Replying to:"); + if(static_cast(selected->userdata)->event_id.empty()) { + // TODO: Show inline notification + show_notification("QuickMedia", "You can't reply to a message that hasn't been sent yet"); + } else { + chat_state = ChatState::REPLYING; + currently_operating_on_item = selected; + chat_input.set_editable(true); + replying_to_text.setString("Replying to:"); + } } } else { // TODO: Show inline notification @@ -3977,9 +4075,12 @@ namespace QuickMedia { std::shared_ptr selected = tabs[selected_tab].body->get_selected_shared(); if(selected) { if(!is_state_message_type(static_cast(selected->userdata))) { - if(!selected->url.empty()) { // cant edit messages that are image/video posts + if(static_cast(selected->userdata)->event_id.empty()) { + // TODO: Show inline notification + show_notification("QuickMedia", "You can't edit a message that hasn't been sent yet"); + } else if(!selected->url.empty()) { // cant edit messages that are image/video posts // TODO: Show inline notification - show_notification("QuickMedia", "You can only edit messages with no file attached to it"); + show_notification("QuickMedia", "You can't edit messages with files attached to them"); } else if(!matrix->was_message_posted_by_me(selected->userdata)) { // TODO: Show inline notification show_notification("QuickMedia", "You can't edit a message that was posted by somebody else"); @@ -4003,14 +4104,22 @@ namespace QuickMedia { BodyItem *selected = tabs[selected_tab].body->get_selected(); if(selected) { if(!is_state_message_type(static_cast(selected->userdata))) { - void *selected_message = selected->userdata; - post_task_queue.push([this, ¤t_room, selected_message]() { - std::string err_msg; - if(matrix->delete_message(current_room, selected_message, err_msg) != PluginResult::OK) { - // TODO: Show inline notification - fprintf(stderr, "Failed to delete message, reason: %s\n", err_msg.c_str()); - } - }); + if(static_cast(selected->userdata)->event_id.empty()) { + // TODO: Show inline notification + show_notification("QuickMedia", "You can't delete a message that hasn't been sent yet"); + } else { + set_body_as_deleted(static_cast(selected->userdata), selected); + void *selected_message = selected->userdata; + post_task_queue.push([this, ¤t_room, selected_message]() { + ProvisionalMessage provisional_message; + std::string err_msg; + if(matrix->delete_message(current_room, selected_message, err_msg) != PluginResult::OK) { + // TODO: Show inline notification + fprintf(stderr, "Failed to delete message, reason: %s\n", err_msg.c_str()); + } + return provisional_message; + }); + } } } else { // TODO: Show inline notification @@ -4106,19 +4215,7 @@ namespace QuickMedia { fprintf(stderr, "No files selected!\n"); } else { // TODO: Upload multiple files. - TaskResult post_file_result = run_task_with_loading_screen([this, ¤t_room]() { - std::string err_msg; - if(matrix->post_file(current_room, selected_files[0], err_msg) == PluginResult::OK) { - return true; - } else { - show_notification("QuickMedia", "Failed to upload media to room, error: " + err_msg, Urgency::CRITICAL); - return false; - } - }); - if(post_file_result == TaskResult::TRUE) { - if(tabs[MESSAGES_TAB_INDEX].body->is_last_item_fully_visible()) - tabs[MESSAGES_TAB_INDEX].body->select_last_item(); - } + upload_file(selected_files[0]); } redraw = true; } @@ -4128,7 +4225,7 @@ namespace QuickMedia { previous_messages_future.cancel(); cleanup_tasks(); tabs.clear(); - unreferenced_event_by_room.clear(); + unreferenced_events.clear(); all_messages.clear(); new_page = PageType::CHAT; matrix->stop_sync(); @@ -4223,10 +4320,25 @@ namespace QuickMedia { logo_sprite.setPosition(logo_padding_x, std::floor(window_size.y - chat_input_shade.getSize().y * 0.5f - logo_size.y * 0.5f)); } + while((provisional_message = provisional_message_queue.pop_if_available()) != std::nullopt) { + if(!provisional_message->body_item || !provisional_message->message) + continue; + + if(!provisional_message->event_id.empty()) { + provisional_message->message->event_id = std::move(provisional_message->event_id); + unresolved_provisional_messages.push_back(provisional_message.value()); + } else if(provisional_message->body_item) { + provisional_message->body_item->set_description("Failed to send: " + provisional_message->body_item->get_description()); + provisional_message->body_item->set_description_color(sf::Color::Red); + } + } + sync_data.messages.clear(); + sync_data.pinned_events = std::nullopt; matrix->get_room_sync_data(current_room, sync_data); if(!sync_data.messages.empty()) { all_messages.insert(all_messages.end(), sync_data.messages.begin(), sync_data.messages.end()); + resolve_provisional_messages(sync_data.messages); filter_existing_messages(sync_data.messages); } add_new_messages_to_current_room(sync_data.messages); @@ -4242,7 +4354,7 @@ namespace QuickMedia { if(previous_messages_future.ready()) { Messages new_messages = previous_messages_future.get(); all_messages.insert(all_messages.end(), new_messages.begin(), new_messages.end()); - if(new_messages.empty() || all_messages.size() >= 10) + if(new_messages.empty()) fetched_enough_messages = true; filter_existing_messages(new_messages); fprintf(stderr, "Finished fetching older messages, num new messages: %zu\n", new_messages.size()); @@ -4254,7 +4366,7 @@ namespace QuickMedia { BodyItem *selected_item = tabs[MESSAGES_TAB_INDEX].body->get_selected(); BodyItems new_body_items = messages_to_body_items(current_room, new_messages, current_room->get_user_display_name(me), me->user_id); size_t num_new_body_items = new_body_items.size(); - tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(std::move(new_body_items)); + tabs[MESSAGES_TAB_INDEX].body->prepend_items(std::move(new_body_items)); // TODO: Insert by timestamp? then make sure num_new_body_items matches the first items blabla if(selected_item) { int selected_item_index = tabs[MESSAGES_TAB_INDEX].body->get_index_by_body_item(selected_item); if(selected_item_index != -1) @@ -4430,7 +4542,7 @@ namespace QuickMedia { if(is_window_focused && chat_state != ChatState::URL_SELECTION && current_room && last_visible_item && !setting_read_marker && read_marker_timer.getElapsedTime().asMilliseconds() >= read_marker_timeout_ms) { Message *message = (Message*)last_visible_item->userdata; // TODO: What if two messages have the same timestamp? - if(message->timestamp > current_room->last_read_message_timestamp) { + if(message && !message->event_id.empty() && message->timestamp > current_room->last_read_message_timestamp) { //read_marker_timeout_ms = read_marker_timeout_ms_default; current_room->last_read_message_timestamp = message->timestamp; // TODO: What if the message is no longer valid? @@ -4464,7 +4576,6 @@ namespace QuickMedia { if(matrix_chat_page->should_clear_data) { matrix_chat_page->should_clear_data = false; - cleanup_tasks(); std::string err_msg; while(!matrix->is_initial_sync_finished()) { @@ -4478,13 +4589,22 @@ namespace QuickMedia { current_room = matrix->get_room_by_id(current_room->id); if(current_room) { + all_messages.clear(); + tabs[MESSAGES_TAB_INDEX].body->clear_items(); + + matrix->get_all_synced_room_messages(current_room, all_messages); + for(auto &message : all_messages) { + fetched_messages_set.insert(message->event_id); + } + auto me = matrix->get_me(current_room); + resolve_provisional_messages(all_messages); + add_new_messages_to_current_room(all_messages); + modify_related_messages_in_current_room(all_messages); + std::vector pinned_events; matrix->get_all_pinned_events(current_room, pinned_events); process_pinned_events(std::move(pinned_events)); - typing_state_queue.restart(); - typing_state_thread = std::thread(typing_state_handler); - post_task_queue.restart(); - post_thread = std::thread(post_thread_handler); + fetch_more_previous_messages_if_needed(); } else { go_to_previous_page = true; diff --git a/src/Text.cpp b/src/Text.cpp index 9c6bc86..b463f92 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -615,11 +615,8 @@ namespace QuickMedia int Text::getStartOfWord(int startIndex) const { assert(!dirty && !dirtyText); - int start_line = get_vertex_line(startIndex); bool start_is_special_char = is_special_character(get_vertex_codepoint(startIndex - 1)); for(int i = startIndex - 1; i >= 0; --i) { - if(get_vertex_line(i) != start_line) - return i + 1; bool is_special_char = is_special_character(vertices_linear[i].codepoint); if(is_special_char != start_is_special_char) return i + 1; @@ -630,11 +627,8 @@ namespace QuickMedia int Text::getEndOfWord(int startIndex) const { assert(!dirty && !dirtyText); const int num_vertices = vertices_linear.size(); - int start_line = get_vertex_line(startIndex); bool start_is_special_char = is_special_character(get_vertex_codepoint(startIndex)); for(int i = startIndex + 1; i < num_vertices; ++i) { - if(get_vertex_line(i) != start_line) - return i - 1; bool is_special_char = is_special_character(vertices_linear[i].codepoint); if(is_special_char != start_is_special_char) return i; diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 4b78978..446cdf1 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -1056,10 +1056,8 @@ namespace QuickMedia { } } - if(next_batch.empty()) { - additional_messages_queue.push(true); + if(next_batch.empty()) clear_sync_cache_for_new_sync(); - } result = parse_sync_response(json_root, false); if(result != PluginResult::OK) { @@ -1067,6 +1065,9 @@ namespace QuickMedia { goto sync_end; } + if(next_batch.empty()) + additional_messages_queue.push(true); + next_batch_json = &GetMember(json_root, "next_batch"); if(next_batch_json->IsString()) { set_next_batch(next_batch_json->GetString()); @@ -2376,7 +2377,7 @@ namespace QuickMedia { return "m.file"; } - PluginResult Matrix::post_message(RoomData *room, const std::string &body, const std::optional &file_info, const std::optional &thumbnail_info, const std::string &msgtype) { + PluginResult Matrix::post_message(RoomData *room, const std::string &body, std::string &event_id_response, const std::optional &file_info, const std::optional &thumbnail_info, const std::string &msgtype) { char random_characters[18]; if(!generate_random_characters(random_characters, sizeof(random_characters))) return PluginResult::ERR; @@ -2473,6 +2474,7 @@ namespace QuickMedia { return PluginResult::ERR; fprintf(stderr, "Matrix post message, response event id: %s\n", event_id_json.GetString()); + event_id_response = std::string(event_id_json.GetString(), event_id_json.GetStringLength()); return PluginResult::OK; } @@ -2557,7 +2559,7 @@ namespace QuickMedia { } // TODO: Support greentext - PluginResult Matrix::post_reply(RoomData *room, const std::string &body, void *relates_to) { + PluginResult Matrix::post_reply(RoomData *room, const std::string &body, void *relates_to, std::string &event_id_response) { // TODO: Store shared_ptr instead of raw pointer... Message *relates_to_message_raw = (Message*)relates_to; @@ -2609,10 +2611,11 @@ namespace QuickMedia { return PluginResult::ERR; fprintf(stderr, "Matrix post reply, response event id: %s\n", event_id_json.GetString()); + event_id_response = std::string(event_id_json.GetString(), event_id_json.GetStringLength()); return PluginResult::OK; } - PluginResult Matrix::post_edit(RoomData *room, const std::string &body, void *relates_to) { + 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; char random_characters[18]; @@ -2693,6 +2696,7 @@ namespace QuickMedia { return PluginResult::ERR; fprintf(stderr, "Matrix post edit, response event id: %s\n", event_id_json.GetString()); + event_id_response = std::string(event_id_json.GetString(), event_id_json.GetStringLength()); return PluginResult::OK; } @@ -2704,7 +2708,7 @@ namespace QuickMedia { auto fetched_message_it = room->fetched_messages_by_event_id.find(event_id); if(fetched_message_it != room->fetched_messages_by_event_id.end()) return fetched_message_it->second; - +#if 0 rapidjson::Document request_data(rapidjson::kObjectType); request_data.AddMember("lazy_load_members", true, request_data.GetAllocator()); @@ -2720,7 +2724,14 @@ namespace QuickMedia { char url[512]; snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/context/%s?limit=0&filter=%s", homeserver.c_str(), room->id.c_str(), event_id.c_str(), filter.c_str()); +#else + std::vector additional_args = { + { "-H", "Authorization: Bearer " + access_token } + }; + char url[512]; + snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/event/%s", homeserver.c_str(), room->id.c_str(), event_id.c_str()); +#endif std::string err_msg; rapidjson::Document json_root; DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true, &err_msg); @@ -2738,13 +2749,17 @@ namespace QuickMedia { room->fetched_messages_by_event_id.insert(std::make_pair(event_id, nullptr)); return nullptr; } - +#if 0 const rapidjson::Value &state_json = GetMember(json_root, "state"); events_add_user_info(state_json, room); +#endif //events_set_room_name(state_json, room); - +#if 0 const rapidjson::Value &event_json = GetMember(json_root, "event"); std::shared_ptr new_message = parse_message_event(event_json, room); +#else + std::shared_ptr new_message = parse_message_event(json_root, room); +#endif room->fetched_messages_by_event_id.insert(std::make_pair(event_id, new_message)); return new_message; } @@ -2756,7 +2771,7 @@ namespace QuickMedia { return filepath.c_str() + index + 1; } - PluginResult Matrix::post_file(RoomData *room, const std::string &filepath, std::string &err_msg) { + PluginResult Matrix::post_file(RoomData *room, const std::string &filepath, std::string &event_id_response, std::string &err_msg) { UploadInfo file_info; UploadInfo thumbnail_info; PluginResult upload_file_result = upload_file(room, filepath, file_info, thumbnail_info, err_msg); @@ -2769,7 +2784,7 @@ namespace QuickMedia { thumbnail_info_opt = std::move(thumbnail_info); const char *filename = file_get_filename(filepath); - return post_message(room, filename, file_info_opt, thumbnail_info_opt); + return post_message(room, filename, event_id_response, file_info_opt, thumbnail_info_opt); } PluginResult Matrix::upload_file(RoomData *room, const std::string &filepath, UploadInfo &file_info, UploadInfo &thumbnail_info, std::string &err_msg) { -- cgit v1.2.3