From c428eb6118a2c7e7dcf9ebdee05e80eb5cd3dc1b Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 27 Mar 2021 23:53:14 +0100 Subject: Fix some body flickering when loading embedded items that are in cache --- src/QuickMedia.cpp | 124 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 54 deletions(-) diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index a26f52f..e94ba34 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -3217,6 +3217,46 @@ namespace QuickMedia { static const sf::Vector2i CHAT_MESSAGE_THUMBNAIL_MAX_SIZE(600, 337); + static std::shared_ptr find_body_item_by_event_id(const std::shared_ptr *body_items, size_t num_body_items, const std::string &event_id, size_t *index_result = nullptr) { + if(event_id.empty()) + return nullptr; + + for(size_t i = 0; i < num_body_items; ++i) { + auto &body_item = body_items[i]; + if(body_item->userdata && static_cast(body_item->userdata)->event_id == event_id) { + if(index_result) + *index_result = i; + return body_item; + } + } + + return nullptr; + } + + // Returns true if cached and loaded + static bool load_cached_related_embedded_item(BodyItem *body_item, Message *message, UserInfo *me, const std::string &my_display_name, const std::string &my_user_id, const BodyItems &message_body_items) { + // Check if we already have the referenced message as a body item, so we dont create a new one. + // TODO: Optimize from linear search to hash map + auto related_body_item = find_body_item_by_event_id(message_body_items.data(), message_body_items.size(), message->related_event_id); + if(!related_body_item) + return false; + + body_item->embedded_item = std::make_shared(""); + *body_item->embedded_item = *related_body_item; + body_item->embedded_item->embedded_item = nullptr; + body_item->embedded_item->reactions.clear(); + if((related_body_item->userdata && static_cast(related_body_item->userdata)->user.get() == me) || message_contains_user_mention(message->body, my_display_name) || message_contains_user_mention(message->body, my_user_id)) + body_item->set_description_color(sf::Color(255, 100, 100)); + else + body_item->set_description_color(sf::Color::White); + body_item->embedded_item_status = FetchStatus::FINISHED_LOADING; + return true; + } + + static bool load_cached_related_embedded_item(BodyItem *body_item, Message *message, const std::shared_ptr &me, RoomData *current_room, const BodyItems &message_body_items) { + return load_cached_related_embedded_item(body_item, message, me.get(), current_room->get_user_display_name(me), me->user_id, message_body_items); + } + static std::shared_ptr message_to_body_item(RoomData *room, Message *message, const std::string &my_display_name, const std::string &my_user_id) { auto body_item = BodyItem::create(""); body_item->set_author(room->get_user_display_name(message->user)); @@ -3253,6 +3293,15 @@ namespace QuickMedia { return result_items; } + static void messages_load_cached_related_embedded_item(BodyItems &new_body_items, const BodyItems &all_body_items, const std::shared_ptr &me, RoomData *current_room) { + std::string my_display_name = current_room->get_user_display_name(me); + for(auto &body_item : new_body_items) { + Message *message = static_cast(body_item->userdata); + if(message) + load_cached_related_embedded_item(body_item.get(), message, me.get(), my_display_name, me->user_id, all_body_items); + } + } + static bool is_state_message_type(const Message *message) { if(!message) return true; @@ -3383,23 +3432,6 @@ namespace QuickMedia { bool redraw = true; bool draw_room_list = show_room_side_panel; - // TODO: Optimize with hash map? - auto find_body_item_by_event_id = [](std::shared_ptr *body_items, size_t num_body_items, const std::string &event_id, size_t *index_result = nullptr) -> std::shared_ptr { - if(event_id.empty()) - return nullptr; - - for(size_t i = 0; i < num_body_items; ++i) { - auto &body_item = body_items[i]; - if(body_item->userdata && static_cast(body_item->userdata)->event_id == event_id) { - if(index_result) - *index_result = i; - return body_item; - } - } - - return nullptr; - }; - // TODO: What if these never end up referencing events? clean up automatically after a while? Messages unreferenced_events; @@ -3421,7 +3453,7 @@ namespace QuickMedia { }; // TODO: Optimize with hash map? - auto resolve_unreferenced_events_with_body_items = [this, ¤t_room, &set_body_as_deleted, &unreferenced_events, &find_body_item_by_event_id](std::shared_ptr *body_items, size_t num_body_items) { + auto resolve_unreferenced_events_with_body_items = [this, ¤t_room, &set_body_as_deleted, &unreferenced_events](std::shared_ptr *body_items, size_t num_body_items) { if(num_body_items == 0) return; @@ -3457,7 +3489,7 @@ namespace QuickMedia { }; // TODO: Optimize find_body_item_by_event_id hash map? - auto modify_related_messages_in_current_room = [this, ¤t_room, &set_body_as_deleted, &unreferenced_events, &find_body_item_by_event_id, &tabs](Messages &messages) { + auto modify_related_messages_in_current_room = [this, ¤t_room, &set_body_as_deleted, &unreferenced_events, &tabs](Messages &messages) { if(messages.empty()) return; @@ -3491,7 +3523,7 @@ namespace QuickMedia { std::vector> unresolved_reactions; // TODO: Optimize find_body_item_by_event_id hash map? - auto process_reactions = [&tabs, &find_body_item_by_event_id, &unresolved_reactions, ¤t_room](Messages &messages) { + auto process_reactions = [&tabs, &unresolved_reactions, ¤t_room](Messages &messages) { if(messages.empty()) return; @@ -3600,7 +3632,9 @@ namespace QuickMedia { fetched_messages_set.insert(message->event_id); } auto me = matrix->get_me(current_room); - tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(messages_to_body_items(current_room, all_messages, current_room->get_user_display_name(me), me->user_id)); + auto new_body_items = messages_to_body_items(current_room, all_messages, current_room->get_user_display_name(me), me->user_id); + messages_load_cached_related_embedded_item(new_body_items, tabs[MESSAGES_TAB_INDEX].body->items, me, current_room); + tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(std::move(new_body_items)); modify_related_messages_in_current_room(all_messages); process_reactions(all_messages); tabs[MESSAGES_TAB_INDEX].body->select_last_item(); @@ -3646,7 +3680,7 @@ namespace QuickMedia { }; std::thread post_thread(post_thread_handler); - auto message_set_replaced_by = [&find_body_item_by_event_id, &tabs, &pending_sent_replies](std::shared_ptr message) { + auto message_set_replaced_by = [&tabs, &pending_sent_replies](std::shared_ptr message) { if(message->related_event_type == RelatedEventType::EDIT) { auto body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), message->related_event_id); if(body_item) { @@ -3697,7 +3731,7 @@ namespace QuickMedia { bool frame_skip_text_entry = false; - chat_input.on_submit_callback = [this, &frame_skip_text_entry, &tabs, &me, &chat_input, &selected_tab, ¤t_room, &new_page, &chat_state, &pending_sent_replies, ¤tly_operating_on_item, &post_task_queue, &process_reactions, &find_body_item_by_event_id](std::string text) mutable { + chat_input.on_submit_callback = [this, &frame_skip_text_entry, &tabs, &me, &chat_input, &selected_tab, ¤t_room, &new_page, &chat_state, &pending_sent_replies, ¤tly_operating_on_item, &post_task_queue, &process_reactions](std::string text) mutable { if(!current_room) return false; @@ -3765,6 +3799,7 @@ namespace QuickMedia { message->related_event_type = RelatedEventType::REACTION; message->related_event_id = static_cast(related_to_message)->event_id; auto body_item = message_to_body_item(current_room, message.get(), current_room->get_user_avatar_url(me), me->user_id); + load_cached_related_embedded_item(body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->items); tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps({body_item}); Messages messages; messages.push_back(message); @@ -3780,6 +3815,7 @@ namespace QuickMedia { } else { auto body_item = message_to_body_item(current_room, message.get(), current_room->get_user_avatar_url(me), me->user_id); body_item->set_description_color(provisional_message_color); + load_cached_related_embedded_item(body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->items); tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps({body_item}); post_task_queue.push([this, ¤t_room, text, msgtype, body_item, message]() { ProvisionalMessage provisional_message; @@ -3804,6 +3840,7 @@ namespace QuickMedia { message->related_event_id = static_cast(related_to_message)->event_id; auto body_item = message_to_body_item(current_room, message.get(), current_room->get_user_avatar_url(me), me->user_id); body_item->set_description_color(provisional_message_color); + load_cached_related_embedded_item(body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->items); tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps({body_item}); post_task_queue.push([this, ¤t_room, text, related_to_message, body_item, message, transaction_id]() { ProvisionalMessage provisional_message; @@ -3832,6 +3869,7 @@ namespace QuickMedia { auto edit_body_item = message_to_body_item(current_room, message.get(), current_room->get_user_avatar_url(me), me->user_id); edit_body_item->visible = false; + load_cached_related_embedded_item(body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->items); tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps({edit_body_item}); //unreferenced_events.push_back(message); @@ -3877,7 +3915,7 @@ namespace QuickMedia { int fetch_message_tab = -1; // TODO: How about instead fetching all messages we have, not only the visible ones? also fetch with multiple threads. - tabs[PINNED_TAB_INDEX].body->body_item_render_callback = [this, ¤t_room, &me, &fetch_message_future, &tabs, &fetch_message, &find_body_item_by_event_id, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) { + tabs[PINNED_TAB_INDEX].body->body_item_render_callback = [this, ¤t_room, &me, &fetch_message_future, &tabs, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) { if(fetch_message_future.valid()) return; @@ -3900,25 +3938,13 @@ namespace QuickMedia { } #endif + // 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)) return; - // Check if we already have the referenced message as a body item, so we dont create a new one. - // TODO: Optimize from linear search to hash map - auto related_body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), event_data->message->related_event_id); - if(related_body_item) { - body_item->embedded_item = std::make_shared(""); - *body_item->embedded_item = *related_body_item; - body_item->embedded_item->embedded_item = nullptr; - body_item->embedded_item->reactions.clear(); - if(related_body_item->userdata && static_cast(related_body_item->userdata)->user == me) - body_item->set_description_color(sf::Color(255, 100, 100)); - else - body_item->set_description_color(sf::Color::White); - body_item->embedded_item_status = FetchStatus::FINISHED_LOADING; + if(load_cached_related_embedded_item(body_item, event_data->message, me, current_room, tabs[MESSAGES_TAB_INDEX].body->items)) return; - } std::string message_event_id = event_data->message->related_event_id; fetch_body_item = body_item; @@ -3934,6 +3960,7 @@ namespace QuickMedia { if(event_data->status != FetchStatus::NONE) return; + // Fetch embed message // Check if we already have the referenced message as a body item in the messages list, so we dont create a new one. // TODO: Optimize from linear search to hash map auto related_body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), event_data->event_id); @@ -3961,7 +3988,7 @@ namespace QuickMedia { }; // TODO: How about instead fetching all messages we have, not only the visible ones? also fetch with multiple threads. - tabs[MESSAGES_TAB_INDEX].body->body_item_render_callback = [this, ¤t_room, &me, &fetch_message_future, &tabs, &is_window_focused, &chat_state, &setting_read_marker, &read_marker_timer, &read_marker_timeout_ms, &set_read_marker_future, &find_body_item_by_event_id, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) { + tabs[MESSAGES_TAB_INDEX].body->body_item_render_callback = [this, ¤t_room, &me, &fetch_message_future, &tabs, &is_window_focused, &chat_state, &setting_read_marker, &read_marker_timer, &read_marker_timeout_ms, &set_read_marker_future, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) { Message *message = static_cast(body_item->userdata); if(!message) return; @@ -4010,21 +4037,8 @@ namespace QuickMedia { return; } - // Check if we already have the referenced message as a body item, so we dont create a new one. - // TODO: Optimize from linear search to hash map - auto related_body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), message->related_event_id); - if(related_body_item) { - body_item->embedded_item = std::make_shared(""); - *body_item->embedded_item = *related_body_item; - body_item->embedded_item->embedded_item = nullptr; - body_item->embedded_item->reactions.clear(); - if((related_body_item->userdata && static_cast(related_body_item->userdata)->user == me) || message_contains_user_mention(message->body, current_room->get_user_display_name(me)) || message_contains_user_mention(message->body, me->user_id)) - body_item->set_description_color(sf::Color(255, 100, 100)); - else - body_item->set_description_color(sf::Color::White); - body_item->embedded_item_status = FetchStatus::FINISHED_LOADING; + if(load_cached_related_embedded_item(body_item, message, me, current_room, tabs[MESSAGES_TAB_INDEX].body->items)) return; - } std::string message_event_id = message->related_event_id; fetch_body_item = body_item; @@ -4189,7 +4203,9 @@ namespace QuickMedia { } BodyItem *selected_item = tabs[MESSAGES_TAB_INDEX].body->get_selected(); - tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(messages_to_body_items(current_room, messages, current_room->get_user_display_name(me), me->user_id)); + auto new_body_items = messages_to_body_items(current_room, messages, current_room->get_user_display_name(me), me->user_id); + messages_load_cached_related_embedded_item(new_body_items, tabs[MESSAGES_TAB_INDEX].body->items, me, current_room); + tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(std::move(new_body_items)); if(selected_item && !scroll_to_end) { int selected_item_index = tabs[MESSAGES_TAB_INDEX].body->get_index_by_body_item(selected_item); if(selected_item_index != -1) -- cgit v1.2.3