aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-11-16 13:32:49 +0100
committerdec05eba <dec05eba@protonmail.com>2020-11-16 13:32:49 +0100
commite68ff632e2f54c705ae1d69033e58a8f2d1ca00c (patch)
tree24f6d1b220767dd393b7ee62b9267ac958d521a2 /src
parentf9608af936c39c57633129a62472d315aef62d9c (diff)
Matrix: show provisional messages as the message is being sent and received
Diffstat (limited to 'src')
-rw-r--r--src/Body.cpp19
-rw-r--r--src/QuickMedia.cpp282
-rw-r--r--src/Text.cpp6
-rw-r--r--src/plugins/Matrix.cpp37
4 files changed, 242 insertions, 102 deletions
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<BodyItem> *body_items, size_t num_body_items, const std::string &event_id) -> std::shared_ptr<BodyItem> {
+ auto find_body_item_by_event_id = [](std::shared_ptr<BodyItem> *body_items, size_t num_body_items, const std::string &event_id, size_t *index_result = nullptr) -> std::shared_ptr<BodyItem> {
for(size_t i = 0; i < num_body_items; ++i) {
auto &body_item = body_items[i];
- if(static_cast<Message*>(body_item->userdata)->event_id == event_id)
+ if(static_cast<Message*>(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<RoomData*, Messages> unreferenced_event_by_room;
+ Messages unreferenced_events;
auto set_body_as_deleted = [&current_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, &current_room, &find_body_item_by_event_id](std::shared_ptr<BodyItem> *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<BodyItem> *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, &current_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<std::function<void()>> post_task_queue;
- auto post_thread_handler = [&post_task_queue]() {
+ struct ProvisionalMessage {
+ std::shared_ptr<BodyItem> body_item;
+ std::shared_ptr<Message> message;
+ std::string event_id;
+ };
+
+ std::vector<ProvisionalMessage> unresolved_provisional_messages; // |event_id| is always empty in this. Use |message->event_id| instead
+ std::optional<ProvisionalMessage> provisional_message;
+ MessageQueue<ProvisionalMessage> provisional_message_queue;
+ MessageQueue<std::function<ProvisionalMessage()>> post_task_queue;
+ auto post_thread_handler = [&provisional_message_queue, &post_task_queue]() {
while(true) {
- std::optional<std::function<void()>> post_task_opt = post_task_queue.pop_wait();
+ std::optional<std::function<ProvisionalMessage()>> 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, &current_room, &new_page, &chat_state, &currently_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> &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, &current_room](const std::string &filepath) {
+ TaskResult post_file_result = run_task_with_loading_screen([this, &current_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, &current_room, &new_page, &chat_state, &currently_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>();
+ 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, &current_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, &current_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, &current_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<Message*>(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, &current_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, &current_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<Message*>(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, &current_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, &current_room, &fetched_enough_messages, &previous_messages_future, &initial_prev_messages_fetch]() {
+ auto fetch_more_previous_messages_if_needed = [this, &tabs, &current_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, &current_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, &current_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<BodyItem> selected = tabs[selected_tab].body->get_selected_shared();
if(selected) {
if(!is_state_message_type(static_cast<Message*>(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<Message*>(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<BodyItem> selected = tabs[selected_tab].body->get_selected_shared();
if(selected) {
if(!is_state_message_type(static_cast<Message*>(selected->userdata))) {
- if(!selected->url.empty()) { // cant edit messages that are image/video posts
+ if(static_cast<Message*>(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<Message*>(selected->userdata))) {
- void *selected_message = selected->userdata;
- post_task_queue.push([this, &current_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<Message*>(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<Message*>(selected->userdata), selected);
+ void *selected_message = selected->userdata;
+ post_task_queue.push([this, &current_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, &current_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<std::string> 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<UploadInfo> &file_info, const std::optional<UploadInfo> &thumbnail_info, const std::string &msgtype) {
+ PluginResult Matrix::post_message(RoomData *room, const std::string &body, std::string &event_id_response, const std::optional<UploadInfo> &file_info, const std::optional<UploadInfo> &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<Message> 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<CommandArg> 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<Message> new_message = parse_message_event(event_json, room);
+#else
+ std::shared_ptr<Message> 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) {