diff options
Diffstat (limited to 'src/QuickMedia.cpp')
-rw-r--r-- | src/QuickMedia.cpp | 201 |
1 files changed, 176 insertions, 25 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index f3e83f6..590eb86 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -3116,7 +3116,7 @@ namespace QuickMedia { pinned_tab.body = std::make_unique<Body>(this, loading_icon); pinned_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; pinned_tab.body->thumbnail_mask_shader = &circle_mask_shader; - pinned_tab.body->attach_side = AttachSide::BOTTOM; + pinned_tab.body->attach_side = AttachSide::TOP; //pinned_tab.body->line_separator_color = sf::Color::Transparent; pinned_tab.text = sf::Text("Pinned messages", *FontLoader::get_font(FontLoader::FontType::LATIN), tab_text_size); tabs.push_back(std::move(pinned_tab)); @@ -3130,8 +3130,18 @@ namespace QuickMedia { messages_tab.text = sf::Text("Messages", *FontLoader::get_font(FontLoader::FontType::LATIN), tab_text_size); tabs.push_back(std::move(messages_tab)); + // ChatTab users_tab; + // users_tab.body = std::make_unique<Body>(this, loading_icon); + // users_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; + // users_tab.body->thumbnail_mask_shader = &circle_mask_shader; + // users_tab.body->attach_side = AttachSide::TOP; + // //users_tab.body->line_separator_color = sf::Color::Transparent; + // users_tab.text = sf::Text("Users", *FontLoader::get_font(FontLoader::FontType::LATIN), tab_text_size); + // tabs.push_back(std::move(users_tab)); + const int PINNED_TAB_INDEX = 0; const int MESSAGES_TAB_INDEX = 1; + //const int USERS_TAB_INDEX = 2; int selected_tab = MESSAGES_TAB_INDEX; bool is_window_focused = window.hasFocus(); @@ -3258,6 +3268,7 @@ namespace QuickMedia { bool empty_before = tabs[PINNED_TAB_INDEX].body->items.empty(); int selected_before = tabs[PINNED_TAB_INDEX].body->get_selected_item(); auto prev_pinned_body_items = tabs[PINNED_TAB_INDEX].body->items; + tabs[PINNED_TAB_INDEX].body->clear_items(); // TODO: Add message to rooms messages when there are new pinned events for(const std::string &event : pinned_events.value()) { @@ -3409,23 +3420,53 @@ namespace QuickMedia { AsyncTask<Messages> previous_messages_future; + enum class FetchMessageType { + MESSAGE, + USER_UPDATE, + ROOM_USERS + }; + + struct FetchMessageResult { + FetchMessageType type; + std::shared_ptr<Message> message; + }; + //const int num_fetch_message_threads = 4; - AsyncTask<std::shared_ptr<Message>> fetch_message_future; - RoomData *fetch_future_room = nullptr; + AsyncTask<FetchMessageResult> fetch_message_future; + Message *fetch_message = nullptr; BodyItem *fetch_body_item = nullptr; int fetch_message_tab = -1; // TODO: How about instead fetching all messages we have, not only the visible ones? also fetch with multiple threads. // TODO: Cancel when going to another room? - tabs[PINNED_TAB_INDEX].body->body_item_render_callback = [this, ¤t_room, &fetch_message_future, &tabs, &find_body_item_by_event_id, &fetch_future_room, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) { + tabs[PINNED_TAB_INDEX].body->body_item_render_callback = [this, ¤t_room, &fetch_message_future, &tabs, &fetch_message, &find_body_item_by_event_id, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) { if(fetch_message_future.valid() || !current_room) return; PinnedEventData *event_data = static_cast<PinnedEventData*>(body_item->userdata); - if(!event_data || event_data->status != FetchStatus::NONE) + if(!event_data) + return; + +#if 0 + if(event_data->message->user->resolve_state == UserResolveState::NOT_RESOLVED) { + fetch_message = event_data->message; + event_data->message->user->resolve_state = UserResolveState::RESOLVING; + std::string user_id = event_data->message->user->user_id; + fetch_message_future = [this, ¤t_room, user_id]() { + matrix->update_user_with_latest_state(current_room, user_id); + return FetchMessageResult{FetchMessageType::USER_UPDATE, nullptr}; + }; + return; + } else if(event_data->message->user->resolve_state == UserResolveState::RESOLVING) { + return; + } +#endif + + if(event_data->status != FetchStatus::NONE) return; - // Check if we already have the referenced message as a body item in the messages list, so we dont create a new one + // 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); if(related_body_item) { *body_item = *related_body_item; @@ -3436,28 +3477,44 @@ namespace QuickMedia { } std::string message_event_id = event_data->event_id; - fetch_future_room = current_room; fetch_body_item = body_item; event_data->status = FetchStatus::LOADING; fetch_message_tab = PINNED_TAB_INDEX; // TODO: Check if the message is already cached before calling async? is this needed? is async creation expensive? - fetch_message_future = [this, &fetch_future_room, message_event_id]() { - return matrix->get_message_by_id(fetch_future_room, message_event_id); + fetch_message_future = [this, ¤t_room, message_event_id]() { + return FetchMessageResult{FetchMessageType::MESSAGE, matrix->get_message_by_id(current_room, message_event_id)}; }; }; // TODO: How about instead fetching all messages we have, not only the visible ones? also fetch with multiple threads. // TODO: Cancel when going to another room? - tabs[MESSAGES_TAB_INDEX].body->body_item_render_callback = [this, ¤t_room, &fetch_message_future, &tabs, &find_body_item_by_event_id, &fetch_future_room, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) { + tabs[MESSAGES_TAB_INDEX].body->body_item_render_callback = [this, ¤t_room, &fetch_message_future, &tabs, &fetch_message, &find_body_item_by_event_id, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) { if(fetch_message_future.valid() || !current_room) return; Message *message = static_cast<Message*>(body_item->userdata); assert(message); + +#if 0 + if(message->user->resolve_state == UserResolveState::NOT_RESOLVED) { + fetch_message = message; + message->user->resolve_state = UserResolveState::RESOLVING; + std::string user_id = message->user->user_id; + fetch_message_future = [this, ¤t_room, user_id]() { + matrix->update_user_with_latest_state(current_room, user_id); + return FetchMessageResult{FetchMessageType::USER_UPDATE, nullptr}; + }; + return; + } else if(message->user->resolve_state == UserResolveState::RESOLVING) { + return; + } +#endif + if(message->related_event_id.empty() || body_item->embedded_item_status != FetchStatus::NONE) return; - // Check if we already have the referenced message as a body item, so we dont create a new one + // 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 = related_body_item; @@ -3466,13 +3523,12 @@ namespace QuickMedia { } std::string message_event_id = message->related_event_id; - fetch_future_room = current_room; fetch_body_item = body_item; body_item->embedded_item_status = FetchStatus::LOADING; fetch_message_tab = MESSAGES_TAB_INDEX; // TODO: Check if the message is already cached before calling async? is this needed? is async creation expensive? - fetch_message_future = [this, &fetch_future_room, message_event_id]() { - return matrix->get_message_by_id(fetch_future_room, message_event_id); + fetch_message_future = [this, ¤t_room, message_event_id]() { + return FetchMessageResult{FetchMessageType::MESSAGE, matrix->get_message_by_id(current_room, message_event_id)}; }; }; @@ -3491,7 +3547,7 @@ namespace QuickMedia { sf::Vertex gradient_points[4]; double gradient_inc = 0; - tabs[MESSAGES_TAB_INDEX].body->set_page_scroll(window_size.y); + //tabs[MESSAGES_TAB_INDEX].body->set_page_scroll(window_size.y); bool fetched_enough_messages = false; bool initial_prev_messages_fetch = true; @@ -3648,6 +3704,81 @@ namespace QuickMedia { return false; }; + auto update_pinned_messages_author = [&tabs, ¤t_room](const std::shared_ptr<UserInfo> &user) { + fprintf(stderr, "updated pinned messages author for user: %s\n", user->user_id.c_str()); + std::string user_display_name = current_room->get_user_display_name(user); + std::string user_avatar_url = current_room->get_user_avatar_url(user); + + for(auto &pinned_body_item : tabs[PINNED_TAB_INDEX].body->items) { + Message *message = static_cast<PinnedEventData*>(pinned_body_item->userdata)->message; + // Its fine if we dont set it now. When the message is fetches, it will have updated user info since its fetched later + if(!message || message->user != user) + continue; + + pinned_body_item->set_author(user_display_name); + if(!is_visual_media_message_type(message->type)) { + pinned_body_item->thumbnail_url = user_avatar_url; + pinned_body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; + // if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that + pinned_body_item->thumbnail_size = sf::Vector2i(32, 32); + } + } + }; + + auto update_messages_author = [&tabs, ¤t_room](const std::shared_ptr<UserInfo> &user) { + fprintf(stderr, "updated messages author for user: %s\n", user->user_id.c_str()); + std::string user_display_name = current_room->get_user_display_name(user); + std::string user_avatar_url = current_room->get_user_avatar_url(user); + + for(auto &message_body_items : tabs[MESSAGES_TAB_INDEX].body->items) { + Message *message = static_cast<Message*>(message_body_items->userdata); + if(message->user != user) + continue; + + message_body_items->set_author(user_display_name); + if(!is_visual_media_message_type(message->type)) { + message_body_items->thumbnail_url = user_avatar_url; + message_body_items->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; + // if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that + message_body_items->thumbnail_size = sf::Vector2i(32, 32); + } + } + }; + + // TODO: Optimize + auto update_pinned_messages_authors = [&tabs, ¤t_room]() { + fprintf(stderr, "updated pinned messages author for all users\n"); + for(auto &pinned_body_item : tabs[PINNED_TAB_INDEX].body->items) { + Message *message = static_cast<PinnedEventData*>(pinned_body_item->userdata)->message; + // Its fine if we dont set it now. When the message is fetches, it will have updated user info since its fetched later + if(!message) + continue; + + pinned_body_item->set_author(current_room->get_user_display_name(message->user)); + if(!is_visual_media_message_type(message->type)) { + pinned_body_item->thumbnail_url = current_room->get_user_avatar_url(message->user); + pinned_body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; + // if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that + pinned_body_item->thumbnail_size = sf::Vector2i(32, 32); + } + } + }; + + // TODO: Optimize + auto update_messages_authors = [&tabs, ¤t_room]() { + fprintf(stderr, "updated messages author for all users\n"); + for(auto &message_body_items : tabs[MESSAGES_TAB_INDEX].body->items) { + Message *message = static_cast<Message*>(message_body_items->userdata); + message_body_items->set_author(current_room->get_user_display_name(message->user)); + if(!is_visual_media_message_type(message->type)) { + message_body_items->thumbnail_url = current_room->get_user_avatar_url(message->user); + message_body_items->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; + // if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that + message_body_items->thumbnail_size = sf::Vector2i(32, 32); + } + } + }; + auto cleanup_tasks = [&set_read_marker_future, &fetch_message_future, &typing_state_queue, &typing_state_thread, &post_task_queue, &post_thread, &tabs]() { set_read_marker_future.cancel(); fetch_message_future.cancel(); @@ -3674,6 +3805,19 @@ namespace QuickMedia { //tabs.clear(); }; + // TODO: Remove this once synapse bug has been resolved where /sync does not include user info for new messages when using message filter that limits number of messages for initial sync, + // and then only call this when viewing the users tab for the first time. + if(current_room->users_fetched) { + //TODO BLABLA + //update_ + } else { + // TODO: Race condition? maybe use matrix /members instead which has a since parameter to make the members list match current sync + fetch_message_future = [this, ¤t_room]() { + matrix->update_room_users(current_room); + return FetchMessageResult{FetchMessageType::ROOM_USERS, nullptr}; + }; + } + float tab_shade_height = 0.0f; bool frame_skip_text_entry = false; @@ -4108,31 +4252,38 @@ namespace QuickMedia { // XXX: Hack to scroll up while keeping the selected item (usually the last one) visible if(move_to_bottom) { tabs[MESSAGES_TAB_INDEX].body->select_last_item(); - tabs[MESSAGES_TAB_INDEX].body->set_page_scroll(window_size.y); + //tabs[MESSAGES_TAB_INDEX].body->set_page_scroll(window_size.y); } } fetch_more_previous_messages_if_needed(); } if(fetch_message_future.ready()) { - std::shared_ptr<Message> message = fetch_message_future.get(); - fprintf(stderr, "Finished fetching message: %s\n", message ? message->event_id.c_str() : "(null)"); - // Ignore finished fetch of messages if it happened in another room. When we navigate back to the room we will get the messages again - if(fetch_future_room == current_room) { + FetchMessageResult fetch_message_result = fetch_message_future.get(); + if(fetch_message_result.type == FetchMessageType::ROOM_USERS) { + current_room->users_fetched = true; + update_pinned_messages_authors(); + update_messages_authors(); + } else if(fetch_message_result.type == FetchMessageType::USER_UPDATE) { + update_pinned_messages_author(fetch_message->user); + update_messages_author(fetch_message->user); + fetch_message = nullptr; + } else if(fetch_message_result.type == FetchMessageType::MESSAGE) { + fprintf(stderr, "Finished fetching message: %s\n", fetch_message_result.message ? fetch_message_result.message->event_id.c_str() : "(null)"); if(fetch_message_tab == PINNED_TAB_INDEX) { PinnedEventData *event_data = static_cast<PinnedEventData*>(fetch_body_item->userdata); - if(message) { - *fetch_body_item = *message_to_body_item(current_room, message.get(), current_room->get_user_display_name(me), me->user_id); + if(fetch_message_result.message) { + *fetch_body_item = *message_to_body_item(current_room, fetch_message_result.message.get(), current_room->get_user_display_name(me), me->user_id); event_data->status = FetchStatus::FINISHED_LOADING; - event_data->message = message.get(); + event_data->message = fetch_message_result.message.get(); fetch_body_item->userdata = event_data; } else { fetch_body_item->set_description("Failed to load message!"); event_data->status = FetchStatus::FAILED_TO_LOAD; } } else if(fetch_message_tab == MESSAGES_TAB_INDEX) { - if(message) { - fetch_body_item->embedded_item = message_to_body_item(current_room, message.get(), current_room->get_user_display_name(me), me->user_id); + if(fetch_message_result.message) { + fetch_body_item->embedded_item = message_to_body_item(current_room, fetch_message_result.message.get(), current_room->get_user_display_name(me), me->user_id); fetch_body_item->embedded_item_status = FetchStatus::FINISHED_LOADING; } else { fetch_body_item->embedded_item_status = FetchStatus::FAILED_TO_LOAD; |