From 3609429b3d8fccd99994dde015b6516376e6835b Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 20 May 2021 05:20:49 +0200 Subject: Move chat page room list logic to matrix delegate --- src/plugins/Matrix.cpp | 231 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 186 insertions(+), 45 deletions(-) (limited to 'src/plugins/Matrix.cpp') diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 8a0f486..afa8738 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -437,6 +437,50 @@ namespace QuickMedia { show_notification("QuickMedia matrix - " + sender + " (" + room->get_name() + ")", body); } + static UsersByRoom::iterator find_user_data_by_id(UsersByRoom &users_by_room, const MatrixEventUserInfo &user_info) { + RoomData *room = user_info.room; + auto range = users_by_room.equal_range(room); + for(auto &it = range.first; it != range.second; ++it) { + if(it->second.user_id == user_info.user_id) + return it; + } + return users_by_room.end(); + } + + void MatrixQuickMedia::add_user(MatrixEventUserInfo user_info) { + auto it = find_user_data_by_id(users_by_room, user_info); + if(it == users_by_room.end()) { + users_by_room.insert(std::make_pair(user_info.room, user_info)); + if(chat_page) + chat_page->add_user(std::move(user_info)); + } + } + + void MatrixQuickMedia::remove_user(MatrixEventUserInfo user_info) { + auto it = find_user_data_by_id(users_by_room, user_info); + if(it != users_by_room.end()) { + users_by_room.erase(it); + if(chat_page) + chat_page->remove_user(std::move(user_info)); + } + } + + void MatrixQuickMedia::set_user_info(MatrixEventUserInfo user_info) { + auto it = find_user_data_by_id(users_by_room, user_info); + if(it != users_by_room.end()) { + it->second = user_info; + if(chat_page) + chat_page->set_user_info(std::move(user_info)); + } + } + + void MatrixQuickMedia::for_each_user_in_room(RoomData *room, std::function callback) { + auto range = users_by_room.equal_range(room); + for(auto &it = range.first; it != range.second; ++it) { + callback(it->second); + } + } + static void sort_room_body_items(std::vector> &room_body_items) { 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); @@ -597,6 +641,10 @@ namespace QuickMedia { return PluginResult::OK; } + void MatrixRoomsPage::on_navigate_to_page(Body *body) { + body->items_set_dirty(true); + } + void MatrixRoomsPage::add_body_item(std::shared_ptr body_item) { insert_room_body_item_by_timestamp(body->items, body_item); } @@ -667,6 +715,10 @@ namespace QuickMedia { return PluginResult::OK; } + void MatrixRoomTagsPage::on_navigate_to_page(Body *body) { + body->items_set_dirty(true); + } + 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); @@ -679,8 +731,8 @@ namespace QuickMedia { 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->apply_search_filter_for_item(tag_body_item.get()); 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; } @@ -783,8 +835,8 @@ namespace QuickMedia { void MatrixInvitesPage::add_body_item(std::shared_ptr body_item) { // TODO: Insert in reverse order (to show the latest invite at the top?) + body->apply_search_filter_for_item(body_item.get()); 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()) + ")"; @@ -812,6 +864,108 @@ namespace QuickMedia { rooms_page->matrix_delegate->chat_page = nullptr; } + // Returns |default_value| if the input items is empty + static size_t get_body_item_sorted_insert_position_by_author(BodyItems &body_items, const std::string &display_name, size_t default_value) { + for(size_t i = 0; i < body_items.size(); ++i) { + auto &body_item = body_items[i]; + if(strcasecmp(display_name.c_str(), body_item->get_author().c_str()) <= 0) + return i; + } + return default_value; + } + + static void add_user_to_body_by_user_info(Body *users_body, const MatrixEventUserInfo &user_info) { + std::string display_name = user_info.display_name.value_or(user_info.user_id); + size_t insert_index = get_body_item_sorted_insert_position_by_author(users_body->items, display_name, 0); + + auto body_item = BodyItem::create(""); + body_item->url = user_info.user_id; + body_item->set_author(std::move(display_name)); + body_item->set_author_color(user_id_to_color(user_info.user_id)); + body_item->set_description(user_info.user_id); + body_item->set_description_color(sf::Color(179, 179, 179)); + if(user_info.avatar_url) + body_item->thumbnail_url = user_info.avatar_url.value(); + body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; + body_item->thumbnail_size = sf::Vector2i(32, 32); + + users_body->apply_search_filter_for_item(body_item.get()); + users_body->items.insert(users_body->items.begin() + insert_index, std::move(body_item)); + } + + void MatrixChatPage::add_user(MatrixEventUserInfo user_info) { + if(!current_room || !users_body || user_info.room != current_room) + return; + + // Ignore if the user already exists in the room + for(auto &body_item : users_body->items) { + if(body_item->url == user_info.user_id) + return; + } + + add_user_to_body_by_user_info(users_body, user_info); + } + + void MatrixChatPage::remove_user(MatrixEventUserInfo user_info) { + if(!current_room || !users_body || user_info.room != current_room) + return; + + for(auto it = users_body->items.begin(), end = users_body->items.end(); it != end; ++it) { + if((*it)->url == user_info.user_id) { + users_body->items.erase(it); + return; + } + } + } + + void MatrixChatPage::set_user_info(MatrixEventUserInfo user_info) { + if(!current_room || !users_body || user_info.room != current_room) + return; + + for(auto it = users_body->items.begin(), end = users_body->items.end(); it != end; ++it) { + if((*it)->url == user_info.user_id) { + if(user_info.avatar_url) + (*it)->thumbnail_url = user_info.avatar_url.value(); + + if(user_info.display_name) { + std::string display_name; + if(user_info.display_name.value().empty()) + display_name = user_info.user_id; + else + display_name = user_info.display_name.value(); + + (*it)->set_author(std::move(display_name)); + + auto user_body_item = *it; + users_body->items.erase(it); + + // TODO: extract_first_line_remove_newline_elipses(room->get_user_display_name(message->user), AUTHOR_MAX_LENGTH), + // But that should be done in Text because we need author to be 100% the same as in the input to reorder users + users_body->apply_search_filter_for_item(user_body_item.get()); + size_t insert_index = get_body_item_sorted_insert_position_by_author(users_body->items, user_body_item->get_author(), 0); + users_body->items.insert(users_body->items.begin() + insert_index, std::move(user_body_item)); + } + + return; + } + } + } + + void MatrixChatPage::set_current_room(RoomData *room, Body *users_body) { + this->current_room = room; + this->users_body = users_body; + if(!room || !users_body) + return; + + rooms_page->matrix_delegate->for_each_user_in_room(room, [users_body](const MatrixEventUserInfo &user_info) { + add_user_to_body_by_user_info(users_body, user_info); + }); + } + + size_t MatrixChatPage::get_num_users_in_current_room() const { + return users_body ? users_body->items.size() : 0; + } + PluginResult MatrixRoomDirectoryPage::submit(const std::string &title, const std::string&, std::vector &result_tabs) { std::string server_name = title; @@ -1516,11 +1670,9 @@ namespace QuickMedia { event_user_info.avatar_url = avatar_url; if(is_new_user) { - auto event = std::make_unique(std::move(event_user_info)); - trigger_event(room_data, std::move(event)); + trigger_event(room_data, MatrixEventType::ADD_USER, std::move(event_user_info)); } else { - auto event = std::make_unique(std::move(event_user_info)); - trigger_event(room_data, std::move(event)); + trigger_event(room_data, MatrixEventType::USER_INFO, std::move(event_user_info)); } return user_info; @@ -1779,8 +1931,7 @@ namespace QuickMedia { if(is_new_user) { MatrixEventUserInfo user_info; user_info.user_id = user->user_id; - auto event = std::make_unique(std::move(user_info)); - trigger_event(room_data, std::move(event)); + trigger_event(room_data, MatrixEventType::ADD_USER, std::move(user_info)); } auto user_sender = user; @@ -1791,8 +1942,7 @@ namespace QuickMedia { if(is_new_user) { MatrixEventUserInfo user_info; user_info.user_id = user_sender->user_id; - auto event = std::make_unique(std::move(user_info)); - trigger_event(room_data, std::move(event)); + trigger_event(room_data, MatrixEventType::ADD_USER, std::move(user_info)); } } @@ -1934,8 +2084,7 @@ namespace QuickMedia { user_info.display_name = std::move(new_display_name); user_info.avatar_url = std::move(new_avatar_url); - auto event = std::make_unique(std::move(user_info)); - trigger_event(room_data, std::move(event)); + trigger_event(room_data, MatrixEventType::USER_INFO, std::move(user_info)); } } else { body = user_display_name + " joined the room"; @@ -3781,7 +3930,7 @@ namespace QuickMedia { if(room_it == room_data_by_id.end()) return; - // We want to clear data instead of removing the object iself becasue we want to instance to still be valid, + // We want to clear data instead of removing the object iself because we want to instance to still be valid, // also in the future we can have a "history" tag for rooms we have just left rooms[room_it->second]->clear_data(); room_data_by_id.erase(room_it); @@ -3898,11 +4047,9 @@ namespace QuickMedia { user_info.avatar_url = avatar_url; if(is_new_user) { - auto event = std::make_unique(std::move(user_info)); - trigger_event(room, std::move(event)); + trigger_event(room, MatrixEventType::ADD_USER, std::move(user_info)); } else { - auto event = std::make_unique(std::move(user_info)); - trigger_event(room, std::move(event)); + trigger_event(room, MatrixEventType::USER_INFO, std::move(user_info)); } } #else @@ -3974,19 +4121,6 @@ namespace QuickMedia { #endif } - void Matrix::enable_event_queue(RoomData *room) { - std::lock_guard lock(event_queue_mutex); - assert(!current_event_queue_room); - current_event_queue_room = room; - } - - void Matrix::disable_event_queue() { - std::lock_guard lock(event_queue_mutex); - assert(current_event_queue_room); - current_event_queue_room = nullptr; - event_queue.clear(); - } - void Matrix::update() { std::optional> task; while((task = ui_thread_tasks.pop_if_available()) != std::nullopt) { @@ -3994,20 +4128,27 @@ namespace QuickMedia { } } - std::unique_ptr Matrix::pop_event() { - std::lock_guard lock(event_queue_mutex); - if(!current_event_queue_room || event_queue.empty()) - return nullptr; - - auto event_data = std::move(event_queue.front()); - event_queue.pop_front(); - return event_data; - } - - void Matrix::trigger_event(RoomData *room, std::unique_ptr event) { - std::lock_guard lock(event_queue_mutex); - if(sync_is_cache || !current_event_queue_room || current_event_queue_room != room) - return; - event_queue.push_back(std::move(event)); + void Matrix::trigger_event(RoomData *room, MatrixEventType type, MatrixEventUserInfo user_info) { + user_info.room = room; + switch(type) { + case MatrixEventType::ADD_USER: { + ui_thread_tasks.push([this, user_info{std::move(user_info)}]{ + delegate->add_user(std::move(user_info)); + }); + break; + } + case MatrixEventType::REMOVE_USER: { + ui_thread_tasks.push([this, user_info{std::move(user_info)}]{ + delegate->remove_user(std::move(user_info)); + }); + break; + } + case MatrixEventType::USER_INFO: { + ui_thread_tasks.push([this, user_info{std::move(user_info)}]{ + delegate->set_user_info(std::move(user_info)); + }); + break; + } + } } } \ No newline at end of file -- cgit v1.2.3