From 8e79b2e10827f42d76ec61621f2c484f9cdc2551 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 19 May 2021 23:45:27 +0200 Subject: Start on notifications run matrix delegate on main (ui) thread instead of mutex hell --- src/plugins/Matrix.cpp | 486 +++++++++++++++---------------------------------- 1 file changed, 148 insertions(+), 338 deletions(-) (limited to 'src/plugins/Matrix.cpp') diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 4328888..8a0f486 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -349,14 +349,16 @@ namespace QuickMedia { } MatrixQuickMedia::MatrixQuickMedia(Program *program, Matrix *matrix, MatrixRoomsPage *rooms_page, MatrixRoomTagsPage *room_tags_page, MatrixInvitesPage *invites_page) : - program(program), matrix(matrix), rooms_page(rooms_page), room_tags_page(room_tags_page), invites_page(invites_page) + program(program), matrix(matrix), chat_page(nullptr), rooms_page(rooms_page), room_tags_page(room_tags_page), invites_page(invites_page) { rooms_page->matrix_delegate = this; room_tags_page->matrix_delegate = this; } void MatrixQuickMedia::join_room(RoomData *room) { - std::lock_guard lock(room_body_items_mutex); + if(room_body_item_by_room.find(room) != room_body_item_by_room.end()) + return; + std::string room_name = room->get_name(); if(room_name.empty()) room_name = room->id; @@ -368,12 +370,11 @@ namespace QuickMedia { body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; body_item->thumbnail_size = sf::Vector2i(32, 32); room->body_item = body_item; - rooms_page->add_body_item(body_item); room_body_item_by_room[room] = body_item; + rooms_page->add_body_item(body_item); } void MatrixQuickMedia::leave_room(RoomData *room, LeaveType leave_type, const std::string &reason) { - std::lock_guard lock(room_body_items_mutex); room_body_item_by_room.erase(room); rooms_page->remove_body_item_by_room_id(room->id); room_tags_page->remove_body_item_by_room_id(room->id); @@ -382,22 +383,35 @@ namespace QuickMedia { } void MatrixQuickMedia::room_add_tag(RoomData *room, const std::string &tag) { - std::lock_guard lock(room_body_items_mutex); - room_tags_page->add_room_body_item_to_tag(room_body_item_by_room[room], tag); + auto it = room_body_item_by_room.find(room); + if(it == room_body_item_by_room.end()) + return; + room_tags_page->add_room_body_item_to_tag(it->second, tag); } void MatrixQuickMedia::room_remove_tag(RoomData *room, const std::string &tag) { - std::lock_guard lock(room_body_items_mutex); - room_tags_page->remove_room_body_item_from_tag(room_body_item_by_room[room], tag); + auto it = room_body_item_by_room.find(room); + if(it == room_body_item_by_room.end()) + return; + room_tags_page->remove_room_body_item_from_tag(it->second, tag); } void MatrixQuickMedia::room_add_new_messages(RoomData *room, const Messages &messages, bool is_initial_sync, bool sync_is_cache, MessageDirection message_dir) { - std::lock_guard lock(pending_room_messages_mutex); - auto &room_messages_data = pending_room_messages[room]; - room_messages_data.messages.insert(room_messages_data.messages.end(), messages.begin(), messages.end()); - room_messages_data.is_initial_sync = is_initial_sync; - room_messages_data.sync_is_cache = sync_is_cache; - room_messages_data.message_dir = message_dir; + bool is_window_focused = program->is_window_focused(); + RoomData *current_room = program->get_current_chat_room(); + + if(!sync_is_cache && message_dir == MessageDirection::AFTER && !is_initial_sync) { + for(auto &message : messages) { + if(message->notification_mentions_me) { + // TODO: What if the message or username begins with "-"? also make the notification image be the avatar of the user + if((!is_window_focused || room != current_room) && message->related_event_type != RelatedEventType::EDIT && message->related_event_type != RelatedEventType::REDACTION) { + show_notification("QuickMedia matrix - " + extract_first_line_remove_newline_elipses(matrix->message_get_author_displayname(message.get()), AUTHOR_MAX_LENGTH) + " (" + room->get_name() + ")", message->body); + } + } + } + } + + update_room_description(room, messages, is_initial_sync, sync_is_cache); } void MatrixQuickMedia::add_invite(const std::string &room_id, const Invite &invite) { @@ -419,34 +433,11 @@ namespace QuickMedia { invites_page->remove_body_item_by_room_id(room_id); } - void MatrixQuickMedia::add_unread_notification(RoomData *room, std::string event_id, std::string sender, std::string body) { - std::lock_guard lock(room_body_items_mutex); - Notification notification; - notification.event_id = std::move(event_id); - notification.sender = std::move(sender); - notification.body = std::move(body); - unread_notifications[room].push_back(std::move(notification)); + void MatrixQuickMedia::add_unread_notification(RoomData *room, std::string, std::string sender, std::string body) { + show_notification("QuickMedia matrix - " + sender + " (" + room->get_name() + ")", body); } static void sort_room_body_items(std::vector> &room_body_items) { - #if 0 - std::sort(room_body_items.begin(), room_body_items.end(), [](const std::shared_ptr &body_item1, const std::shared_ptr &body_item2) { - return strcasecmp(body_item1->get_title().c_str(), body_item2->get_title().c_str()) < 0; - }); - #if 1 - std::sort(room_body_items.begin(), room_body_items.end(), [](const std::shared_ptr &body_item1, const std::shared_ptr &body_item2) { - RoomData *room1 = static_cast(body_item1->userdata); - RoomData *room2 = static_cast(body_item2->userdata); - int room1_focus_sum = (int)(room1->unread_notification_count > 0) + (int)!room1->last_message_read; - int room2_focus_sum = (int)(room2->unread_notification_count > 0) + (int)!room2->last_message_read; - return room1_focus_sum > room2_focus_sum; - }); - #else - std::sort(room_body_items.begin(), room_body_items.end(), [](const std::shared_ptr &body_item1, const std::shared_ptr &body_item2) { - return strcasecmp(body_item1->get_title().c_str(), body_item2->get_title().c_str()) < 0; - }); - #endif - #endif std::sort(room_body_items.begin(), room_body_items.end(), [](const std::shared_ptr &body_item1, const std::shared_ptr &body_item2) { RoomData *room1 = static_cast(body_item1->userdata); RoomData *room2 = static_cast(body_item2->userdata); @@ -456,6 +447,18 @@ namespace QuickMedia { }); } + static void insert_room_body_item_by_timestamp(BodyItems &body_items, std::shared_ptr new_body_item) { + RoomData *new_room = static_cast(new_body_item->userdata); + for(auto it = body_items.begin(), end = body_items.end(); it != end; ++it) { + RoomData *room = static_cast((*it)->userdata); + if(new_room->last_message_timestamp >= room->last_message_timestamp) { + body_items.insert(it, std::move(new_body_item)); + return; + } + } + body_items.push_back(std::move(new_body_item)); + } + void body_set_selected_item(Body *body, BodyItem *selected_item) { for(size_t i = 0; i < body->items.size(); ++i) { if(body->items[i]->url == selected_item->url) { @@ -466,24 +469,7 @@ namespace QuickMedia { } } - void MatrixQuickMedia::update(MatrixPageType page_type, Body *chat_body, bool messages_tab_visible) { - update_pending_room_messages(page_type, chat_body, messages_tab_visible); - std::lock_guard room_body_lock(room_body_items_mutex); - for(auto &it : unread_notifications) { - for(auto &unread_notification : it.second) { - show_notification("QuickMedia matrix - " + unread_notification.sender + " (" + it.first->get_name() + ")", unread_notification.body); - } - } - //if(!unread_notifications.empty()) { - // rooms_page->sort_rooms(); - // room_tags_page->sort_rooms(); - //} - unread_notifications.clear(); - } - void MatrixQuickMedia::clear_data() { - std::lock_guard lock(pending_room_messages_mutex); - std::lock_guard room_body_lock(room_body_items_mutex); //room_body_item_by_room.clear(); //pending_room_messages.clear(); //rooms_page->clear_data(); @@ -493,22 +479,19 @@ namespace QuickMedia { } static std::shared_ptr get_last_message_by_timestamp(const Messages &messages) { - #if 0 - return *std::max_element(messages.begin(), messages.end(), [](const std::shared_ptr &message1, const std::shared_ptr &message2) { - return message1->timestamp < message2->timestamp; - }); - #else if(messages.empty()) return nullptr; + size_t last_message_index = 0; for(size_t i = 1; i < messages.size(); ++i) { if(message_is_timeline(messages[i].get()) && messages[i]->timestamp >= messages[last_message_index]->timestamp) last_message_index = i; } + if(message_is_timeline(messages[last_message_index].get())) return messages[last_message_index]; + return nullptr; - #endif } static std::string message_to_room_description_text(Message *message) { @@ -523,7 +506,7 @@ namespace QuickMedia { return extract_first_line_remove_newline_elipses(body, 150); } - void MatrixQuickMedia::update_room_description(RoomData *room, Messages &new_messages, bool is_initial_sync, bool sync_is_cache, Body *chat_body, bool messages_tab_visible) { + void MatrixQuickMedia::update_room_description(RoomData *room, const Messages &new_messages, bool is_initial_sync, bool sync_is_cache) { time_t read_marker_message_timestamp = 0; std::shared_ptr me = matrix->get_me(room); std::string my_user_read_marker; @@ -570,7 +553,8 @@ namespace QuickMedia { if(last_unread_message && !sync_is_cache) { bool is_window_focused = program->is_window_focused(); RoomData *current_room = program->get_current_chat_room(); - bool set_room_as_unread = !is_window_focused || room != current_room || (!chat_body || !chat_body->is_last_item_fully_visible()) || !messages_tab_visible; + Body *chat_body = chat_page ? chat_page->chat_body : nullptr; + bool set_room_as_unread = !is_window_focused || room != current_room || (!chat_body || !chat_body->is_last_item_fully_visible()) || (chat_page && !chat_page->messages_tab_visible); std::string room_desc; if(set_room_as_unread) @@ -597,35 +581,7 @@ namespace QuickMedia { } } - void MatrixQuickMedia::update_pending_room_messages(MatrixPageType page_type, Body *chat_body, bool messages_tab_visible) { - std::lock_guard lock(pending_room_messages_mutex); - bool is_window_focused = program->is_window_focused(); - RoomData *current_room = program->get_current_chat_room(); - for(auto &it : pending_room_messages) { - RoomData *room = it.first; - auto &messages = it.second.messages; - bool is_initial_sync = it.second.is_initial_sync; - //auto &room_body_item = room_body_item_by_room[room]; - //std::string room_desc = extract_first_line_remove_newline_elipses(matrix->message_get_author_displayname(it.second.back().get()), AUTHOR_MAX_LENGTH) + ": " + extract_first_line_remove_newline_elipses(it.second.back()->body, 150); - //room_body_item->set_description(std::move(room_desc)); - - if(!it.second.sync_is_cache && it.second.message_dir == MessageDirection::AFTER && !is_initial_sync) { - for(auto &message : messages) { - if(message->notification_mentions_me) { - // TODO: What if the message or username begins with "-"? also make the notification image be the avatar of the user - if((!is_window_focused || room != current_room) && message->related_event_type != RelatedEventType::EDIT && message->related_event_type != RelatedEventType::REDACTION) { - show_notification("QuickMedia matrix - " + extract_first_line_remove_newline_elipses(matrix->message_get_author_displayname(message.get()), AUTHOR_MAX_LENGTH) + " (" + room->get_name() + ")", message->body); - } - } - } - } - - update_room_description(room, messages, is_initial_sync, it.second.sync_is_cache, chat_body, messages_tab_visible); - } - pending_room_messages.clear(); - } - - MatrixRoomsPage::MatrixRoomsPage(Program *program, Body *body, std::string title, MatrixRoomTagsPage *room_tags_page, SearchBar *search_bar) : Page(program), body(body), title(std::move(title)), room_tags_page(room_tags_page), search_bar(search_bar) { + MatrixRoomsPage::MatrixRoomsPage(Program *program, Body *body, std::string title, MatrixRoomTagsPage *room_tags_page) : Page(program), body(body), title(std::move(title)), room_tags_page(room_tags_page) { if(room_tags_page) room_tags_page->set_current_rooms_page(this); } @@ -635,90 +591,19 @@ namespace QuickMedia { room_tags_page->set_current_rooms_page(nullptr); } - PluginResult MatrixRoomsPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - (void)title; + PluginResult MatrixRoomsPage::submit(const std::string&, const std::string &url, std::vector &result_tabs) { auto chat_page = std::make_unique(program, url, this); result_tabs.push_back(Tab{nullptr, std::move(chat_page), nullptr}); return PluginResult::OK; } - void MatrixRoomsPage::on_navigate_to_page(Body *body) { - if(search_bar) - body->filter_search_fuzzy(search_bar->get_text()); - //sort_room_body_items(body->items); - } - - void MatrixRoomsPage::update() { - { - std::lock_guard lock(mutex); - int prev_selected_item = body->get_selected_item(); - if(clear_data_on_update) { - clear_data_on_update = false; - body->clear_items(); - } - - if(!pending_remove_body_items.empty() || !room_body_items.empty()) { - sort_on_update = true; - filter_on_update = true; - } - - for(const std::string &room_id : pending_remove_body_items) { - remove_body_item_by_url(body->items, room_id); - // TODO: There can be a race condition where current_chat_page is set after entering a room and then we will enter a room we left - if(current_chat_page && current_chat_page->room_id == room_id) { - program->set_go_to_previous_page(); - body->select_first_item(); - current_chat_page = nullptr; - } - } - - pending_remove_body_items.clear(); - body->set_selected_item(prev_selected_item, false); - body->clamp_selection(); - body->append_items(std::move(room_body_items)); - } - if(sort_on_update) { - sort_on_update = false; - //BodyItem *selected_item = body->get_selected(); - sort_room_body_items(body->items); - //body_set_selected_item(body, selected_item); - } - matrix_delegate->update(MatrixPageType::ROOM_LIST, nullptr, false); - if(filter_on_update) { - filter_on_update = false; - if(search_bar) - body->filter_search_fuzzy(search_bar->get_text()); - //sort_room_body_items(body->items); - } - } - void MatrixRoomsPage::add_body_item(std::shared_ptr body_item) { - std::lock_guard lock(mutex); - room_body_items.push_back(body_item); + insert_room_body_item_by_timestamp(body->items, body_item); } void MatrixRoomsPage::move_room_to_top(RoomData *room) { // Swap order of rooms in body list to put rooms with mentions at the top and then unread messages and then all the other rooms - // TODO: Optimize with hash map instead of linear search? or cache the index - std::lock_guard lock(mutex); -#if 0 - int room_body_index = body->get_index_by_body_item(room->body_item.get()); - if(room_body_index != -1) { - std::shared_ptr body_item = body->items[room_body_index]; - int body_swap_index = -1; - if(room->unread_notification_count > 0) - body_swap_index = find_top_body_position_for_mentioned_room(body->items, body_item.get()); - else if(!room->last_message_read) - body_swap_index = find_top_body_position_for_unread_room(body->items, body_item.get()); - if(body_swap_index != -1 && body_swap_index != room_body_index) { - body->items.erase(body->items.begin() + room_body_index); - if(body_swap_index <= room_body_index) - body->items.insert(body->items.begin() + body_swap_index, std::move(body_item)); - else - body->items.insert(body->items.begin() + (body_swap_index - 1), std::move(body_item)); - } - } -#else + // TODO: Optimize with binary search of linear search? or cache the index int room_body_index = body->get_index_by_body_item(room->body_item.get()); if(room_body_index == -1) return; @@ -732,6 +617,7 @@ namespace QuickMedia { RoomData *room_i = static_cast(body->items[i]->userdata); if((int)i == room_body_index) return; + if((int)i != selected_item && room_i && room->last_message_timestamp >= room_i->last_message_timestamp) { auto body_item_to_insert = body->items[room_body_index]; body->items.erase(body->items.begin() + room_body_index); @@ -746,35 +632,28 @@ namespace QuickMedia { return; } } -#endif } void MatrixRoomsPage::remove_body_item_by_room_id(const std::string &room_id) { - std::lock_guard lock(mutex); - pending_remove_body_items.push_back(room_id); + remove_body_item_by_url(body->items, room_id); + if(current_chat_page && current_chat_page->room_id == room_id) { + program->set_go_to_previous_page(); + body->select_first_item(); + current_chat_page = nullptr; + } } void MatrixRoomsPage::set_current_chat_page(MatrixChatPage *chat_page) { - std::lock_guard lock(mutex); current_chat_page = chat_page; } void MatrixRoomsPage::clear_data() { - std::lock_guard lock(mutex); - room_body_items.clear(); - pending_remove_body_items.clear(); - clear_data_on_update = true; + body->clear_items(); if(current_chat_page) current_chat_page->should_clear_data = true; } - void MatrixRoomsPage::sort_rooms() { - sort_on_update = true; - } - - PluginResult MatrixRoomTagsPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - (void)title; - std::lock_guard lock(mutex); + PluginResult MatrixRoomTagsPage::submit(const std::string&, const std::string &url, std::vector &result_tabs) { auto body = create_body(); Body *body_ptr = body.get(); TagData &tag_data = tag_body_items_by_name[url]; @@ -782,105 +661,68 @@ namespace QuickMedia { //BodyItem *selected_item = body->get_selected(); sort_room_body_items(body->items); //body_set_selected_item(body.get(), selected_item); - auto search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); - auto rooms_page = std::make_unique(program, body_ptr, tag_data.tag_item->get_title(), this, search_bar.get()); + auto rooms_page = std::make_unique(program, body_ptr, tag_data.tag_item->get_title(), this); rooms_page->matrix_delegate = matrix_delegate; - result_tabs.push_back(Tab{std::move(body), std::move(rooms_page), std::move(search_bar)}); + result_tabs.push_back(Tab{std::move(body), std::move(rooms_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); return PluginResult::OK; } - // TODO: Also add/remove body items to above body (in submit) - void MatrixRoomTagsPage::update() { - { - std::lock_guard lock(mutex); - int prev_selected_item = body->get_selected_item(); - if(clear_data_on_update) { - clear_data_on_update = false; - body->clear_items(); - } - - for(auto &it : remove_room_body_items_by_tags) { - auto tag_body_it = tag_body_items_by_name.find(it.first); - if(tag_body_it == tag_body_items_by_name.end()) - continue; - - for(auto &room_to_remove : it.second) { - auto room_body_item_it = std::find(tag_body_it->second.room_body_items.begin(), tag_body_it->second.room_body_items.end(), room_to_remove); - if(room_body_item_it != tag_body_it->second.room_body_items.end()) - tag_body_it->second.room_body_items.erase(room_body_item_it); - } - - if(tag_body_it->second.room_body_items.empty()) { - auto room_body_item_it = std::find(body->items.begin(), body->items.end(), tag_body_it->second.tag_item); - if(room_body_item_it != body->items.end()) { - body->items.erase(room_body_item_it); - filter_on_update = true; - } - tag_body_items_by_name.erase(tag_body_it); - } + void MatrixRoomTagsPage::add_room_body_item_to_tag(std::shared_ptr body_item, const std::string &tag) { + TagData *tag_data; + auto tag_body_it = tag_body_items_by_name.find(tag); + if(tag_body_it == tag_body_items_by_name.end()) { + std::string tag_name = tag_get_name(tag); + if(tag_name.empty()) { + return; + } else { + auto tag_body_item = BodyItem::create(std::move(tag_name)); + tag_body_item->url = tag; + tag_body_items_by_name.insert(std::make_pair(tag, TagData{tag_body_item, {}})); + // TODO: Sort by tag priority + body->items.push_back(tag_body_item); + body->items_set_dirty(); + tag_data = &tag_body_items_by_name[tag]; + tag_data->tag_item = tag_body_item; } - remove_room_body_items_by_tags.clear(); - - for(auto &it : add_room_body_items_by_tags) { - TagData *tag_data; - auto tag_body_it = tag_body_items_by_name.find(it.first); - if(tag_body_it == tag_body_items_by_name.end()) { - std::string tag_name = tag_get_name(it.first); - if(!tag_name.empty()) { - auto tag_body_item = BodyItem::create(std::move(tag_name)); - tag_body_item->url = it.first; - tag_body_items_by_name.insert(std::make_pair(it.first, TagData{tag_body_item, {}})); - // TODO: Sort by tag priority - body->items.push_back(tag_body_item); - tag_data = &tag_body_items_by_name[it.first]; - tag_data->tag_item = tag_body_item; - filter_on_update = true; - } - } else { - tag_data = &tag_body_it->second; - } + } else { + tag_data = &tag_body_it->second; + } - for(auto &room_body_item : it.second) { - bool already_exists = false; - for(auto &body_it : tag_data->room_body_items) { - if(body_it->userdata == room_body_item->userdata) { - already_exists = true; - break; - } - } - if(!already_exists) - tag_data->room_body_items.push_back(room_body_item); - } + bool already_exists = false; + for(auto &body_it : tag_data->room_body_items) { + if(body_it->userdata == body_item->userdata) { + already_exists = true; + break; } - add_room_body_items_by_tags.clear(); - body->set_selected_item(prev_selected_item, false); } - matrix_delegate->update(MatrixPageType::ROOM_LIST, nullptr, false); - if(filter_on_update) { - filter_on_update = false; - if(search_bar) - body->filter_search_fuzzy(search_bar->get_text()); - } - } - void MatrixRoomTagsPage::add_room_body_item_to_tag(std::shared_ptr body_item, const std::string &tag) { - std::lock_guard lock(mutex); - add_room_body_items_by_tags[tag].push_back(body_item); + if(!already_exists) + tag_data->room_body_items.push_back(body_item); } void MatrixRoomTagsPage::remove_room_body_item_from_tag(std::shared_ptr body_item, const std::string &tag) { - std::lock_guard lock(mutex); - remove_room_body_items_by_tags[tag].push_back(body_item); + auto tag_body_it = tag_body_items_by_name.find(tag); + if(tag_body_it == tag_body_items_by_name.end()) + return; + + auto room_body_item_it = std::find(tag_body_it->second.room_body_items.begin(), tag_body_it->second.room_body_items.end(), body_item); + if(room_body_item_it != tag_body_it->second.room_body_items.end()) + tag_body_it->second.room_body_items.erase(room_body_item_it); + + if(tag_body_it->second.room_body_items.empty()) { + auto room_body_item_it = std::find(body->items.begin(), body->items.end(), tag_body_it->second.tag_item); + if(room_body_item_it != body->items.end()) + body->items.erase(room_body_item_it); + tag_body_items_by_name.erase(tag_body_it); + } } void MatrixRoomTagsPage::move_room_to_top(RoomData *room) { - std::lock_guard lock(mutex); if(current_rooms_page) current_rooms_page->move_room_to_top(room); } void MatrixRoomTagsPage::remove_body_item_by_room_id(const std::string &room_id) { - std::lock_guard lock(mutex); for(auto it = tag_body_items_by_name.begin(); it != tag_body_items_by_name.end();) { remove_body_item_by_url(it->second.room_body_items, room_id); if(it->second.room_body_items.empty()) @@ -888,32 +730,23 @@ namespace QuickMedia { else ++it; } + if(current_rooms_page) current_rooms_page->remove_body_item_by_room_id(room_id); } void MatrixRoomTagsPage::set_current_rooms_page(MatrixRoomsPage *rooms_page) { - std::lock_guard lock(mutex); current_rooms_page = rooms_page; } void MatrixRoomTagsPage::clear_data() { - std::lock_guard lock(mutex); tag_body_items_by_name.clear(); - add_room_body_items_by_tags.clear(); - remove_room_body_items_by_tags.clear(); - clear_data_on_update = true; + body->clear_items(); if(current_rooms_page) current_rooms_page->clear_data(); } - void MatrixRoomTagsPage::sort_rooms() { - std::lock_guard lock(mutex); - if(current_rooms_page) - current_rooms_page->sort_rooms(); - } - - MatrixInvitesPage::MatrixInvitesPage(Program *program, Matrix *matrix, Body *body, SearchBar *search_bar) : Page(program), matrix(matrix), body(body), search_bar(search_bar) { + MatrixInvitesPage::MatrixInvitesPage(Program *program, Matrix *matrix, Body *body) : Page(program), matrix(matrix), body(body) { } @@ -948,71 +781,35 @@ namespace QuickMedia { return PluginResult::OK; } - void MatrixInvitesPage::update() { - std::lock_guard lock(mutex); - - int prev_selected_item = body->get_selected_item(); - if(clear_data_on_update) { - clear_data_on_update = false; - body->clear_items(); - } - - if(!pending_remove_body_items.empty() || !body_items.empty()) - filter_on_update = true; - - for(const std::string &room_id : pending_remove_body_items) { - remove_body_item_by_url(body->items, room_id); - } - pending_remove_body_items.clear(); - body->set_selected_item(prev_selected_item, false); - body->clamp_selection(); - + void MatrixInvitesPage::add_body_item(std::shared_ptr body_item) { // TODO: Insert in reverse order (to show the latest invite at the top?) - body->insert_items_by_timestamps(std::move(body_items)); + body->insert_item_by_timestamp(std::move(body_item)); + body->items_set_dirty(); if(body->items.size() != prev_invite_count) { prev_invite_count = body->items.size(); title = "Invites (" + std::to_string(body->items.size()) + ")"; } - - if(filter_on_update) { - filter_on_update = false; - if(search_bar) - body->filter_search_fuzzy(search_bar->get_text()); - } - } - - void MatrixInvitesPage::add_body_item(std::shared_ptr body_item) { - std::lock_guard lock(mutex); - body_items.push_back(std::move(body_item)); } void MatrixInvitesPage::remove_body_item_by_room_id(const std::string &room_id) { - std::lock_guard lock(mutex); - pending_remove_body_items.push_back(room_id); + remove_body_item_by_url(body->items, room_id); } void MatrixInvitesPage::clear_data() { - std::lock_guard lock(mutex); - body_items.clear(); - pending_remove_body_items.clear(); - title = "Invites (0)"; + body->clear_items(); prev_invite_count = 0; - clear_data_on_update = true; + title = "Invites (0)"; } MatrixChatPage::MatrixChatPage(Program *program, std::string room_id, MatrixRoomsPage *rooms_page) : Page(program), room_id(std::move(room_id)), rooms_page(rooms_page) { assert(rooms_page); rooms_page->set_current_chat_page(this); + rooms_page->matrix_delegate->chat_page = this; } MatrixChatPage::~MatrixChatPage() { rooms_page->set_current_chat_page(nullptr); - } - - void MatrixChatPage::update() { - rooms_page->matrix_delegate->update(MatrixPageType::CHAT, chat_body, messages_tab_visible); - if(rooms_page) - rooms_page->update(); + rooms_page->matrix_delegate->chat_page = nullptr; } PluginResult MatrixRoomDirectoryPage::submit(const std::string &title, const std::string&, std::vector &result_tabs) { @@ -1466,7 +1263,9 @@ namespace QuickMedia { std::string event_id(event_id_json.GetString(), event_id_json.GetStringLength()); std::string sender(sender_json.GetString(), sender_json.GetStringLength()); std::string body(body_json.GetString(), body_json.GetStringLength()); - delegate->add_unread_notification(room, std::move(event_id), std::move(sender), std::move(body)); + ui_thread_tasks.push([this, room, event_id{std::move(event_id)}, sender{std::move(sender)}, body{std::move(body)}] { + delegate->add_unread_notification(room, std::move(event_id), std::move(sender), std::move(body)); + }); } return PluginResult::OK; } @@ -1586,7 +1385,7 @@ namespace QuickMedia { } if(is_new_room) - delegate->join_room(room); + ui_thread_tasks.push([this, room]{ delegate->join_room(room); }); events_add_messages(events_json, room, MessageDirection::AFTER, has_unread_notifications); if(!is_additional_messages_sync) @@ -1600,12 +1399,12 @@ namespace QuickMedia { } if(is_new_room) - delegate->join_room(room); + ui_thread_tasks.push([this, room]{ delegate->join_room(room); }); } if(remove_invite(room_id_str)) { // TODO: Show leave type and reason and who caused the invite to be removed - delegate->remove_invite(room_id_str); + ui_thread_tasks.push([this, room_id_str{std::move(room_id_str)}]{ delegate->remove_invite(room_id_str); }); } if(account_data_json.IsObject()) { @@ -1618,7 +1417,7 @@ namespace QuickMedia { std::set &room_tags = room->get_tags_unsafe(); if(room_tags.empty()) { room_tags.insert(OTHERS_ROOM_TAG); - delegate->room_add_tag(room, OTHERS_ROOM_TAG); + ui_thread_tasks.push([this, room]{ delegate->room_add_tag(room, OTHERS_ROOM_TAG); }); } room->release_room_lock(); } @@ -1637,7 +1436,8 @@ namespace QuickMedia { std::lock_guard lock(room_data_mutex); for(auto &room : rooms) { if(existing_rooms.find(room.get()) == existing_rooms.end()) { - delegate->leave_room(room.get(), LeaveType::LEAVE, ""); + RoomData *room_p = room.get(); + ui_thread_tasks.push([this, room_p]{ delegate->leave_room(room_p, LeaveType::LEAVE, ""); }); remove_room(room->id); } } @@ -1925,8 +1725,13 @@ namespace QuickMedia { } } - if(delegate) - delegate->room_add_new_messages(room_data, new_messages, next_batch.empty(), sync_is_cache, message_dir); + if(delegate) { + bool cache_sync = sync_is_cache; + bool is_initial_sync = next_batch.empty(); + ui_thread_tasks.push([this, room_data, cache_sync, new_messages{std::move(new_messages)}, is_initial_sync, message_dir]{ + delegate->room_add_new_messages(room_data, new_messages, is_initial_sync, cache_sync, message_dir); + }); + } return num_new_messages; } @@ -2472,18 +2277,18 @@ namespace QuickMedia { for(const std::string &room_tag : room_tags) { auto it = new_tags.find(room_tag); if(it == new_tags.end()) - delegate->room_remove_tag(room_data, room_tag); + ui_thread_tasks.push([this, room_data, room_tag]{ delegate->room_remove_tag(room_data, room_tag); }); } for(const std::string &new_tag : new_tags) { auto it = room_tags.find(new_tag); if(it == room_tags.end()) - delegate->room_add_tag(room_data, new_tag); + ui_thread_tasks.push([this, room_data, new_tag]{ delegate->room_add_tag(room_data, new_tag); }); } if(new_tags.empty()) { new_tags.insert(OTHERS_ROOM_TAG); - delegate->room_add_tag(room_data, OTHERS_ROOM_TAG); + ui_thread_tasks.push([this, room_data]{ delegate->room_add_tag(room_data, OTHERS_ROOM_TAG); }); } room_tags = std::move(new_tags); @@ -2556,7 +2361,7 @@ namespace QuickMedia { std::string room_id_str(room_id.GetString(), room_id.GetStringLength()); if(set_invite(room_id_str, invite)) - delegate->add_invite(room_id_str, std::move(invite)); + ui_thread_tasks.push([this, room_id_str{std::move(room_id_str)}, invite{std::move(invite)}]{ delegate->add_invite(room_id_str, std::move(invite)); }); break; } @@ -2579,7 +2384,7 @@ namespace QuickMedia { std::string room_id_str(room_id.GetString(), room_id.GetStringLength()); if(remove_invite(room_id_str)) { // TODO: Show leave type and reason and who caused the invite to be removed - delegate->remove_invite(room_id_str); + ui_thread_tasks.push([this, room_id_str{std::move(room_id_str)}]{ delegate->remove_invite(room_id_str); }); } const rapidjson::Value &timeline_json = GetMember(it.value, "timeline"); @@ -2638,7 +2443,7 @@ namespace QuickMedia { if(!reason_str.empty()) desc += ", reason: " + reason_str; - delegate->leave_room(room, leave_type, desc); + ui_thread_tasks.push([this, room, leave_type, desc{std::move(desc)}]{ delegate->leave_room(room, leave_type, desc); }); remove_room(room_id_str); break; } @@ -3047,9 +2852,7 @@ namespace QuickMedia { "" + std::move(formatted_body); } - // TODO: Support greentext PluginResult Matrix::post_reply(RoomData *room, const std::string &body, void *relates_to, std::string &event_id_response, const std::string &custom_transaction_id) { - // TODO: Store shared_ptr instead of raw pointer... Message *relates_to_message_raw = (Message*)relates_to; std::string transaction_id = custom_transaction_id; @@ -3133,7 +2936,7 @@ namespace QuickMedia { std::string formatted_body_edit_str; rapidjson::Document request_data(rapidjson::kObjectType); - request_data.AddMember("msgtype", "m.text", request_data.GetAllocator()); // TODO: Allow other types of edits + request_data.AddMember("msgtype", "m.text", request_data.GetAllocator()); request_data.AddMember("body", rapidjson::StringRef(body_edit_str.c_str()), request_data.GetAllocator()); if(!formatted_body.empty()) { formatted_body_edit_str = " * " + formatted_body; @@ -3772,12 +3575,12 @@ namespace QuickMedia { room = new_room.get(); add_room(std::move(new_room)); - delegate->join_room(room); + ui_thread_tasks.push([this, room]{ delegate->join_room(room); }); room->acquire_room_lock(); std::set &room_tags = room->get_tags_unsafe(); if(room_tags.empty()) { room_tags.insert(OTHERS_ROOM_TAG); - delegate->room_add_tag(room, OTHERS_ROOM_TAG); + ui_thread_tasks.push([this, room]{ delegate->room_add_tag(room, OTHERS_ROOM_TAG); }); } room->release_room_lock(); } @@ -3799,7 +3602,7 @@ namespace QuickMedia { if(download_result == DownloadResult::OK) { RoomData *room = get_room_by_id(room_id); if(room) { - delegate->leave_room(room, LeaveType::LEAVE, ""); + ui_thread_tasks.push([this, room]{ delegate->leave_room(room, LeaveType::LEAVE, ""); }); remove_room(room_id); } } @@ -4019,7 +3822,7 @@ namespace QuickMedia { // We intentionally dont clear |rooms| here because we want the objects inside it to still be valid. TODO: Clear |rooms| here //room_data_by_id.clear(); invites.clear(); - delegate->clear_data(); + ui_thread_tasks.push([this]{ delegate->clear_data(); }); } std::shared_ptr Matrix::get_user_by_id(RoomData *room, const std::string &user_id, bool *is_new_user, bool create_if_not_found) { @@ -4184,6 +3987,13 @@ namespace QuickMedia { event_queue.clear(); } + void Matrix::update() { + std::optional> task; + while((task = ui_thread_tasks.pop_if_available()) != std::nullopt) { + task.value()(); + } + } + std::unique_ptr Matrix::pop_event() { std::lock_guard lock(event_queue_mutex); if(!current_event_queue_room || event_queue.empty()) -- cgit v1.2.3