diff options
author | dec05eba <dec05eba@protonmail.com> | 2021-05-19 23:45:27 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2021-05-20 01:16:46 +0200 |
commit | 8e79b2e10827f42d76ec61621f2c484f9cdc2551 (patch) | |
tree | 2f55f23bdebace14d4c56d15f72a40cbafd0ca3e /src | |
parent | 6beaa000d590db342bc0198590686cbbd6304eb4 (diff) |
Start on notifications
run matrix delegate on main (ui) thread instead of mutex hell
Diffstat (limited to 'src')
-rw-r--r-- | src/Body.cpp | 12 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 155 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 486 |
3 files changed, 240 insertions, 413 deletions
diff --git a/src/Body.cpp b/src/Body.cpp index 4f2e816..d51ea29 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -314,10 +314,12 @@ namespace QuickMedia { void Body::prepend_items(BodyItems new_items) { items.insert(items.begin(), std::make_move_iterator(new_items.begin()), std::make_move_iterator(new_items.end())); + items_set_dirty(); } void Body::append_items(BodyItems new_items) { items.insert(items.end(), std::make_move_iterator(new_items.begin()), std::make_move_iterator(new_items.end())); + items_set_dirty(); } // TODO: Binary search and use hint to start search from start or end (for example when adding "previous" items or "next" items) @@ -336,6 +338,7 @@ namespace QuickMedia { for(auto &new_item : new_items) { insert_item_by_timestamp(new_item); } + items_set_dirty(); } void Body::clear_cache() { @@ -486,7 +489,8 @@ namespace QuickMedia { void Body::draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size, const Json::Value &content_progress) { if(items_dirty) { items_dirty = false; - filter_search_fuzzy(current_filter); + if(using_filter) + filter_search_fuzzy(current_filter, false); } sf::Vector2f scissor_pos = pos; @@ -1490,7 +1494,7 @@ namespace QuickMedia { return full_match; } - void Body::filter_search_fuzzy(const std::string &text) { + void Body::filter_search_fuzzy(const std::string &text, bool select_first_if_empty) { current_filter = text; if(text.empty()) { @@ -1498,7 +1502,8 @@ namespace QuickMedia { item->visible = true; } - select_first_item(); + if(select_first_if_empty) + select_first_item(); return; } @@ -1507,6 +1512,7 @@ namespace QuickMedia { } select_first_item(); + using_filter = true; } void Body::filter_search_fuzzy_item(const std::string &text, BodyItem *body_item) { diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 297a780..5bbcfd7 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1057,6 +1057,9 @@ namespace QuickMedia { auto history_page = std::make_unique<HistoryPage>(this, tabs.front().page.get(), HistoryType::MANGA); tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "manga") == 0) { + auto mangadex = std::make_unique<MangadexSearchPage>(this); + upgrade_legacy_mangadex_ids(this, mangadex.get()); + auto manganelo = std::make_unique<ManganeloSearchPage>(this); auto manganelos = std::make_unique<MangaGenericSearchPage>(this, "manganelos", "http://manganelos.com/"); add_manganelos_handlers(manganelos.get()); @@ -1067,13 +1070,14 @@ namespace QuickMedia { auto readm = std::make_unique<MangaGenericSearchPage>(this, "readm", "https://readm.org/"); add_readm_handlers(readm.get()); + // TODO: Use async task pool std::vector<MangaPlugin> pages; pages.push_back({std::move(manganelo), "Manganelo", "manganelo", resources_root + "images/" + get_plugin_logo_name("manganelo")}); pages.push_back({std::move(manganelos), "Manganelos", "manganelos", resources_root + "images/" + get_plugin_logo_name("manganelos")}); pages.push_back({std::move(mangatown), "Mangatown", "mangatown", resources_root + "images/" + get_plugin_logo_name("mangatown")}); pages.push_back({std::move(mangakatana), "Mangakatana", "mangakatana", resources_root + "images/" + get_plugin_logo_name("mangakatana")}); pages.push_back({std::move(readm), "Readm", "readm", resources_root + "images/" + get_plugin_logo_name("readm")}); - // TODO: Add mangadex + pages.push_back({std::move(mangadex), "Mangadex", "mangadex", resources_root + "images/" + get_plugin_logo_name("mangadex")}); tabs.push_back(Tab{create_body(), std::make_unique<MangaCombinedSearchPage>(this, std::move(pages)), create_search_bar("Search...", 400)}); } else if(strcmp(plugin_name, "nyaa.si") == 0) { @@ -1478,6 +1482,9 @@ namespace QuickMedia { window.draw(tab_associated_data.search_result_text); } + if(matrix) + matrix->update(); + if(matrix && !matrix->is_initial_sync_finished()) { // if(is_login_sync) { load_sprite.setPosition(body_pos.x + body_size.x * 0.5f, body_pos.y + body_size.y * 0.5f); @@ -1558,10 +1565,18 @@ namespace QuickMedia { std::vector<Tab> new_tabs; auto prev_selected_item = tabs[selected_tab].page->submit_body_item; tabs[selected_tab].page->submit_body_item = selected_item; - TaskResult submit_result = run_task_with_loading_screen([&tabs, selected_tab, &selected_item, &search_text, &new_tabs](){ - PluginResult submit_result = tabs[selected_tab].page->submit(selected_item ? selected_item->get_title() : search_text, selected_item ? selected_item->url : "", new_tabs); - return submit_result == PluginResult::OK; - }); + + auto plugin_submit_handler = [&tabs, selected_tab, &selected_item, &search_text, &new_tabs]() { + PluginResult plugin_result = tabs[selected_tab].page->submit(selected_item ? selected_item->get_title() : search_text, selected_item ? selected_item->url : "", new_tabs); + return plugin_result == PluginResult::OK; + }; + + TaskResult submit_result; + if(tabs[selected_tab].page->submit_is_async()) { + submit_result = run_task_with_loading_screen(std::move(plugin_submit_handler)); + } else { + submit_result = plugin_submit_handler() ? TaskResult::TRUE : TaskResult::FALSE; + } if(submit_result == TaskResult::CANCEL) { return; @@ -1883,8 +1898,6 @@ namespace QuickMedia { for(size_t i = 0; i < tabs.size(); ++i) { TabAssociatedData &associated_data = tab_associated_data[i]; - tabs[i].page->update(); - if(associated_data.fetching_next_page_running && associated_data.next_page_future.ready()) { BodyItems new_body_items = associated_data.next_page_future.get(); fprintf(stderr, "Finished fetching page %d, num new items: %zu\n", associated_data.fetched_page + 1, new_body_items.size()); @@ -4612,7 +4625,7 @@ namespace QuickMedia { // Fetch replied to message if(event_data->status == FetchStatus::FINISHED_LOADING && event_data->message) { - if(event_data->message->related_event_id.empty() || (body_item->embedded_item_status != FetchStatus::NONE && body_item->embedded_item_status != FetchStatus::QUEUED_LOADING)) + if(event_data->message->related_event_id.empty() || event_data->message->related_event_type != RelatedEventType::REPLY || (body_item->embedded_item_status != FetchStatus::NONE && body_item->embedded_item_status != FetchStatus::QUEUED_LOADING)) return; if(load_cached_related_embedded_item(body_item, event_data->message, me, current_room, tabs[MESSAGES_TAB_INDEX].body->items)) @@ -4670,7 +4683,7 @@ namespace QuickMedia { if(message_is_timeline(message) && (!last_visible_timeline_message || message->timestamp > last_visible_timeline_message->timestamp)) last_visible_timeline_message = message; - if(message->related_event_id.empty() || (body_item->embedded_item_status != FetchStatus::NONE && body_item->embedded_item_status != FetchStatus::QUEUED_LOADING)) + if(message->related_event_id.empty() || message->related_event_type != RelatedEventType::REPLY || (body_item->embedded_item_status != FetchStatus::NONE && body_item->embedded_item_status != FetchStatus::QUEUED_LOADING)) return; if(fetch_message_future.valid()) { @@ -5375,37 +5388,66 @@ namespace QuickMedia { update_idle_state(); handle_window_close(); + matrix->update(); mention.update(); - matrix_chat_page->update(); + std::unique_ptr<MatrixEvent> matrix_event; + while((matrix_event = matrix->pop_event()) != nullptr) { + if(matrix_event) { + switch(matrix_event->type) { + case MatrixEvent::Type::ADD_USER: + on_add_user_event(static_cast<MatrixAddUserEvent*>(matrix_event.get())); + break; + case MatrixEvent::Type::REMOVE_USER: + on_remove_user_event(static_cast<MatrixRemoveUserEvent*>(matrix_event.get())); + break; + case MatrixEvent::Type::USER_INFO: + on_user_info_event(static_cast<MatrixUserInfoEvent*>(matrix_event.get())); + break; + } + } + } + + 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); + provisional_message->body_item->set_description_color(sf::Color::White); + sent_messages[provisional_message->message->event_id] = std::move(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); + provisional_message->body_item->userdata = nullptr; + } + } switch(new_page) { case PageType::FILE_MANAGER: { new_page = PageType::CHAT; - if(current_room) { - for(ChatTab &tab : tabs) { - tab.body->clear_cache(); - } + for(ChatTab &tab : tabs) { + tab.body->clear_cache(); + } - auto file_manager_page = std::make_unique<FileManagerPage>(this); - file_manager_page->set_current_directory(get_home_dir().data); - auto file_manager_body = create_body(); - file_manager_page->get_files_in_directory(file_manager_body->items); - std::vector<Tab> file_manager_tabs; - file_manager_tabs.push_back(Tab{std::move(file_manager_body), std::move(file_manager_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + auto file_manager_page = std::make_unique<FileManagerPage>(this); + file_manager_page->set_current_directory(get_home_dir().data); + auto file_manager_body = create_body(); + file_manager_page->get_files_in_directory(file_manager_body->items); + std::vector<Tab> file_manager_tabs; + file_manager_tabs.push_back(Tab{std::move(file_manager_body), std::move(file_manager_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); - selected_files.clear(); - page_loop(file_manager_tabs); + selected_files.clear(); + page_loop(file_manager_tabs); - if(selected_files.empty()) { - fprintf(stderr, "No files selected!\n"); - } else { - // TODO: Upload multiple files. - upload_file(selected_files[0]); - } - redraw = true; + if(selected_files.empty()) { + fprintf(stderr, "No files selected!\n"); + } else { + // TODO: Upload multiple files. + upload_file(selected_files[0]); } + redraw = true; break; } case PageType::CHAT_LOGIN: { @@ -5519,38 +5561,6 @@ namespace QuickMedia { logo_sprite.setPosition(body_pos.x - body_padding_horizontal + logo_padding_x, std::floor(window_size.y - chat_input_height_full * 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); - provisional_message->body_item->set_description_color(sf::Color::White); - sent_messages[provisional_message->message->event_id] = std::move(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); - provisional_message->body_item->userdata = nullptr; - } - } - - std::unique_ptr<MatrixEvent> matrix_event; - while((matrix_event = matrix->pop_event()) != nullptr) { - if(matrix_event) { - switch(matrix_event->type) { - case MatrixEvent::Type::ADD_USER: - on_add_user_event(static_cast<MatrixAddUserEvent*>(matrix_event.get())); - break; - case MatrixEvent::Type::REMOVE_USER: - on_remove_user_event(static_cast<MatrixRemoveUserEvent*>(matrix_event.get())); - break; - case MatrixEvent::Type::USER_INFO: - on_user_info_event(static_cast<MatrixUserInfoEvent*>(matrix_event.get())); - break; - } - } - } - sync_data.messages.clear(); sync_data.pinned_events = std::nullopt; matrix->get_room_sync_data(current_room, sync_data); @@ -5908,17 +5918,17 @@ namespace QuickMedia { if(!window.isOpen()) exit(exit_code); - auto rooms_body = create_body(); - auto matrix_rooms_page_search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); - auto matrix_rooms_page = std::make_unique<MatrixRoomsPage>(this, rooms_body.get(), "All rooms", nullptr, matrix_rooms_page_search_bar.get()); + auto notifications_body = create_body(); + auto matrix_notifications_page = std::make_unique<MatrixNotificationsPage>(this, notifications_body.get()); auto rooms_tags_body = create_body(); - auto matrix_rooms_tage_page_search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); - auto matrix_rooms_tag_page = std::make_unique<MatrixRoomTagsPage>(this, rooms_tags_body.get(), matrix_rooms_tage_page_search_bar.get()); + auto matrix_rooms_tag_page = std::make_unique<MatrixRoomTagsPage>(this, rooms_tags_body.get()); + + auto rooms_body = create_body(); + auto matrix_rooms_page = std::make_unique<MatrixRoomsPage>(this, rooms_body.get(), "All rooms", nullptr); auto invites_body = create_body(); - auto matrix_invites_page_search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); - auto matrix_invites_page = std::make_unique<MatrixInvitesPage>(this, matrix, invites_body.get(), matrix_invites_page_search_bar.get()); + auto matrix_invites_page = std::make_unique<MatrixInvitesPage>(this, matrix, invites_body.get()); auto room_directory_body = create_body(); add_body_item_unique_title(room_directory_body->items, matrix->get_homeserver_domain()); @@ -5948,13 +5958,14 @@ namespace QuickMedia { is_login_sync = !sync_cached; std::vector<Tab> tabs; - tabs.push_back(Tab{std::move(rooms_body), std::move(matrix_rooms_page), std::move(matrix_rooms_page_search_bar)}); - tabs.push_back(Tab{std::move(rooms_tags_body), std::move(matrix_rooms_tag_page), std::move(matrix_rooms_tage_page_search_bar)}); - tabs.push_back(Tab{std::move(invites_body), std::move(matrix_invites_page), std::move(matrix_invites_page_search_bar)}); + tabs.push_back(Tab{std::move(notifications_body), std::move(matrix_notifications_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + tabs.push_back(Tab{std::move(rooms_tags_body), std::move(matrix_rooms_tag_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + tabs.push_back(Tab{std::move(rooms_body), std::move(matrix_rooms_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + tabs.push_back(Tab{std::move(invites_body), std::move(matrix_invites_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); tabs.push_back(Tab{std::move(room_directory_body), std::move(matrix_room_directory_page), create_search_bar("Server to search on...", SEARCH_DELAY_FILTER)}); while(window.isOpen()) { - page_loop(tabs); + page_loop(tabs, 2); } matrix->stop_sync(); 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::shared_ptr<BodyItem>> &room_body_items) { - #if 0 - std::sort(room_body_items.begin(), room_body_items.end(), [](const std::shared_ptr<BodyItem> &body_item1, const std::shared_ptr<BodyItem> &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<BodyItem> &body_item1, const std::shared_ptr<BodyItem> &body_item2) { - RoomData *room1 = static_cast<RoomData*>(body_item1->userdata); - RoomData *room2 = static_cast<RoomData*>(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<BodyItem> &body_item1, const std::shared_ptr<BodyItem> &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<BodyItem> &body_item1, const std::shared_ptr<BodyItem> &body_item2) { RoomData *room1 = static_cast<RoomData*>(body_item1->userdata); RoomData *room2 = static_cast<RoomData*>(body_item2->userdata); @@ -456,6 +447,18 @@ namespace QuickMedia { }); } + static void insert_room_body_item_by_timestamp(BodyItems &body_items, std::shared_ptr<BodyItem> new_body_item) { + RoomData *new_room = static_cast<RoomData*>(new_body_item->userdata); + for(auto it = body_items.begin(), end = body_items.end(); it != end; ++it) { + RoomData *room = static_cast<RoomData*>((*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<std::mutex> 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<std::mutex> lock(pending_room_messages_mutex); - std::lock_guard<std::mutex> 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<Message> get_last_message_by_timestamp(const Messages &messages) { - #if 0 - return *std::max_element(messages.begin(), messages.end(), [](const std::shared_ptr<Message> &message1, const std::shared_ptr<Message> &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<UserInfo> 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<std::mutex> 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<Tab> &result_tabs) { - (void)title; + PluginResult MatrixRoomsPage::submit(const std::string&, const std::string &url, std::vector<Tab> &result_tabs) { auto chat_page = std::make_unique<MatrixChatPage>(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<std::mutex> 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<BodyItem> body_item) { - std::lock_guard<std::mutex> 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<std::mutex> 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<BodyItem> 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<RoomData*>(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<std::mutex> 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<std::mutex> lock(mutex); current_chat_page = chat_page; } void MatrixRoomsPage::clear_data() { - std::lock_guard<std::mutex> 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<Tab> &result_tabs) { - (void)title; - std::lock_guard<std::recursive_mutex> lock(mutex); + PluginResult MatrixRoomTagsPage::submit(const std::string&, const std::string &url, std::vector<Tab> &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<MatrixRoomsPage>(program, body_ptr, tag_data.tag_item->get_title(), this, search_bar.get()); + auto rooms_page = std::make_unique<MatrixRoomsPage>(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<std::recursive_mutex> 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<BodyItem> 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<BodyItem> body_item, const std::string &tag) { - std::lock_guard<std::recursive_mutex> 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<BodyItem> body_item, const std::string &tag) { - std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(mutex); current_rooms_page = rooms_page; } void MatrixRoomTagsPage::clear_data() { - std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> 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<std::mutex> 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<BodyItem> 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<BodyItem> body_item) { - std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<Tab> &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<std::string> &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<std::recursive_mutex> 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 { "</mx-reply>" + 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<Message> 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<std::string> &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<UserInfo> 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<std::function<void()>> task; + while((task = ui_thread_tasks.pop_if_available()) != std::nullopt) { + task.value()(); + } + } + std::unique_ptr<MatrixEvent> Matrix::pop_event() { std::lock_guard<std::mutex> lock(event_queue_mutex); if(!current_event_queue_room || event_queue.empty()) |