From 6c85194c3b1baef0eaa011c4f1b8e48e11860f45 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 3 Aug 2021 15:06:57 +0200 Subject: Make body items private, add accessor functions This allows body to automatically update dirty state (and other states). Correctly format newlines in codeblocks in matrix. --- src/QuickMedia.cpp | 291 ++++++++++++++++++++++++++++------------------------- 1 file changed, 155 insertions(+), 136 deletions(-) (limited to 'src/QuickMedia.cpp') diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index a4dd182..2db5537 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -310,7 +310,7 @@ namespace QuickMedia { bool submit_is_async() override { return false; } - void add_option(BodyItems &items, std::string title, std::string description, OptionsPageHandler handler) { + void add_option(Body *body, std::string title, std::string description, OptionsPageHandler handler) { assert(handler); auto body_item = BodyItem::create(std::move(title)); if(!description.empty()) { @@ -319,7 +319,7 @@ namespace QuickMedia { } body_item->url = std::to_string(handlers.size()); handlers.push_back(std::move(handler)); - items.push_back(std::move(body_item)); + body->append_item(std::move(body_item)); } private: std::string title; @@ -1084,22 +1084,24 @@ namespace QuickMedia { if(strcmp(plugin_name, "launcher") == 0) { auto pipe_body = create_body(true); - pipe_body->items.push_back(create_launcher_body_item("4chan", "4chan", resources_root + "icons/4chan_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("Hot Examples", "hotexamples", "")); - pipe_body->items.push_back(create_launcher_body_item("Manga (all)", "manga", "")); - pipe_body->items.push_back(create_launcher_body_item("Mangadex", "mangadex", resources_root + "icons/mangadex_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("Mangakatana", "mangakatana", resources_root + "icons/mangakatana_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("Manganelo", "manganelo", resources_root + "icons/manganelo_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("Manganelos", "manganelos", resources_root + "icons/manganelos_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("Mangatown", "mangatown", resources_root + "icons/mangatown_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("Onimanga", "onimanga", "")); - pipe_body->items.push_back(create_launcher_body_item("Readm", "readm", resources_root + "icons/readm_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("Matrix", "matrix", resources_root + "icons/matrix_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("Nyaa.si", "nyaa.si", resources_root + "icons/nyaa_si_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("SauceNAO", "saucenao", "")); - pipe_body->items.push_back(create_launcher_body_item("Soundcloud", "soundcloud", resources_root + "icons/soundcloud_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("YouTube", "youtube", resources_root + "icons/yt_launcher.png")); - pipe_body->items.push_back(create_launcher_body_item("YouTube (audio only)", "youtube-audio", resources_root + "icons/yt_launcher.png")); + pipe_body->set_items({ + create_launcher_body_item("4chan", "4chan", resources_root + "icons/4chan_launcher.png"), + create_launcher_body_item("Hot Examples", "hotexamples", ""), + create_launcher_body_item("Manga (all)", "manga", ""), + create_launcher_body_item("Mangadex", "mangadex", resources_root + "icons/mangadex_launcher.png"), + create_launcher_body_item("Mangakatana", "mangakatana", resources_root + "icons/mangakatana_launcher.png"), + create_launcher_body_item("Manganelo", "manganelo", resources_root + "icons/manganelo_launcher.png"), + create_launcher_body_item("Manganelos", "manganelos", resources_root + "icons/manganelos_launcher.png"), + create_launcher_body_item("Mangatown", "mangatown", resources_root + "icons/mangatown_launcher.png"), + create_launcher_body_item("Onimanga", "onimanga", ""), + create_launcher_body_item("Readm", "readm", resources_root + "icons/readm_launcher.png"), + create_launcher_body_item("Matrix", "matrix", resources_root + "icons/matrix_launcher.png"), + create_launcher_body_item("Nyaa.si", "nyaa.si", resources_root + "icons/nyaa_si_launcher.png"), + create_launcher_body_item("SauceNAO", "saucenao", ""), + create_launcher_body_item("Soundcloud", "soundcloud", resources_root + "icons/soundcloud_launcher.png"), + create_launcher_body_item("YouTube", "youtube", resources_root + "icons/yt_launcher.png"), + create_launcher_body_item("YouTube (audio only)", "youtube-audio", resources_root + "icons/yt_launcher.png"), + }); tabs.push_back(Tab{std::move(pipe_body), std::make_unique(this, "Select plugin to launch"), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "manganelo") == 0) { tabs.push_back(Tab{create_body(false, true), std::make_unique(this), create_search_bar("Search...", 400)}); @@ -1176,31 +1178,42 @@ namespace QuickMedia { tabs.push_back(Tab{create_body(), std::make_unique(this, std::move(pages)), create_search_bar("Search...", 400)}); } else if(strcmp(plugin_name, "nyaa.si") == 0) { auto categories_nyaa_si_body = create_body(); - get_nyaa_si_categories(categories_nyaa_si_body->items); + BodyItems body_items; + get_nyaa_si_categories(body_items); + categories_nyaa_si_body->set_items(std::move(body_items)); tabs.push_back(Tab{std::move(categories_nyaa_si_body), std::make_unique(this, false), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); auto categories_sukebei_body = create_body(); - get_sukebei_categories(categories_sukebei_body->items); + get_sukebei_categories(body_items); + categories_sukebei_body->set_items(body_items); tabs.push_back(Tab{std::move(categories_sukebei_body), std::make_unique(this, true), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "4chan") == 0) { auto boards_page = std::make_unique(this, resources_root); auto boards_body = create_body(); - boards_page->get_boards(boards_body->items); + BodyItems body_items; + boards_page->get_boards(body_items); + boards_body->set_items(std::move(body_items)); tabs.push_back(Tab{std::move(boards_body), std::move(boards_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "hotexamples") == 0) { auto body = create_body(); - hot_examples_front_page_fill(body->items); + BodyItems body_items; + hot_examples_front_page_fill(body_items); + body->set_items(std::move(body_items)); tabs.push_back(Tab{std::move(body), std::make_unique(this), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "file-manager") == 0) { auto file_manager_page = std::make_unique(this, fm_mime_type, file_selection_handler); if(!file_manager_page->set_current_directory(file_manager_start_dir)) fprintf(stderr, "Warning: Invalid directory provided with --dir\n"); auto file_manager_body = create_body(); - file_manager_page->get_files_in_directory(file_manager_body->items); + BodyItems body_items; + file_manager_page->get_files_in_directory(body_items); + file_manager_body->set_items(std::move(body_items)); tabs.push_back(Tab{std::move(file_manager_body), std::move(file_manager_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "stdin") == 0) { auto pipe_body = create_body(); - PipePage::load_body_items_from_stdin(pipe_body->items); + BodyItems body_items; + PipePage::load_body_items_from_stdin(body_items); + pipe_body->set_items(std::move(body_items)); tabs.push_back(Tab{std::move(pipe_body), std::make_unique(this), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "youtube") == 0) { if(youtube_url.empty()) { @@ -1217,8 +1230,7 @@ namespace QuickMedia { } else { current_page = PageType::VIDEO_CONTENT; auto youtube_video_page = std::make_unique(this, youtube_url); - BodyItems body_items; - video_content_page(nullptr, youtube_video_page.get(), "", false, nullptr, body_items, 0); + video_content_page(nullptr, youtube_video_page.get(), "", false, nullptr, 0); } } else if(strcmp(plugin_name, "pornhub") == 0) { check_youtube_dl_installed(plugin_name); @@ -1580,15 +1592,15 @@ namespace QuickMedia { std::string image_url = body_item->url; if(is_url_video(body_item->url)) image_url = body_item->thumbnail_url; - body->items.push_back(InfoPage::add_reverse_image_search(image_url)); + body->append_item(InfoPage::add_reverse_image_search(image_url)); } std::vector urls = ranges_get_strings(text, extract_urls(text)); for(const std::string &url : urls) { - body->items.push_back(InfoPage::add_url(url)); + body->append_item(InfoPage::add_url(url)); } - if(body->items.empty()) + if(body->get_num_items() == 0) return false; std::vector info_tabs; @@ -1841,7 +1853,7 @@ namespace QuickMedia { page_stack.push(current_page); current_page = PageType::VIDEO_CONTENT; int selected_index = tabs[selected_tab].body->get_selected_item(); - video_content_page(tabs[selected_tab].page.get(), static_cast(new_tabs[0].page.get()), "", false, tabs[selected_tab].body.get(), tabs[selected_tab].body->items, selected_index, &tab_associated_data[selected_tab].fetched_page, tab_associated_data[selected_tab].update_search_text); + video_content_page(tabs[selected_tab].page.get(), static_cast(new_tabs[0].page.get()), "", false, tabs[selected_tab].body.get(), selected_index, &tab_associated_data[selected_tab].fetched_page, tab_associated_data[selected_tab].update_search_text); } else if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::CHAT) { MatrixChatPage *tmp_matrix_chat_page = static_cast(new_tabs[0].page.get()); MatrixRoomsPage *rooms_page = tmp_matrix_chat_page->rooms_page; @@ -2111,7 +2123,7 @@ namespace QuickMedia { continue; if(associated_data.fetching_next_page_running && associated_data.next_page_future.ready()) { - const bool body_was_empty = tabs[i].body->items.empty(); + const bool body_was_empty = tabs[i].body->get_num_items() == 0; 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()); int prev_selected_item = tabs[i].body->get_selected_item(); @@ -2163,18 +2175,18 @@ namespace QuickMedia { if(associated_data.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::SEARCH && associated_data.fetch_future.ready()) { if(!associated_data.search_text_updated) { FetchResult fetch_result = associated_data.fetch_future.get(); - tabs[i].body->items = std::move(fetch_result.body_items); + tabs[i].body->set_items(std::move(fetch_result.body_items)); if(tabs[i].body->attach_side == AttachSide::TOP) { tabs[i].body->select_first_item(); } else if(tabs[i].body->attach_side == AttachSide::BOTTOM) { - std::reverse(tabs[i].body->items.begin(), tabs[i].body->items.end()); + tabs[i].body->reverse_items(); tabs[i].body->select_last_item(); } associated_data.fetched_page = 0; associated_data.fetching_next_page_failed = false; if(fetch_result.result != PluginResult::OK) associated_data.search_result_text.setString("Search failed!"); - else if(tabs[i].body->items.empty()) + else if(tabs[i].body->get_num_items() == 0) associated_data.search_result_text.setString("No results found"); else associated_data.search_result_text.setString(""); @@ -2188,19 +2200,19 @@ namespace QuickMedia { if(associated_data.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::LAZY && associated_data.fetch_future.ready()) { associated_data.lazy_fetch_finished = true; FetchResult fetch_result = associated_data.fetch_future.get(); - tabs[i].body->items = std::move(fetch_result.body_items); + tabs[i].body->set_items(std::move(fetch_result.body_items)); if(tabs[i].search_bar && tabs[i].page->search_is_filter()) tabs[i].body->filter_search_fuzzy(tabs[i].search_bar->get_text()); if(tabs[i].body->attach_side == AttachSide::TOP) { tabs[i].body->select_first_item(); } if(tabs[i].body->attach_side == AttachSide::BOTTOM) { - std::reverse(tabs[i].body->items.begin(), tabs[i].body->items.end()); + tabs[i].body->reverse_items(); tabs[i].body->select_last_item(); } LazyFetchPage *lazy_fetch_page = static_cast(tabs[i].page.get()); if(fetch_result.result != PluginResult::OK) associated_data.search_result_text.setString("Failed to fetch page!"); - else if(tabs[i].body->items.empty() && !lazy_fetch_page->lazy_fetch_is_loader()) + else if(tabs[i].body->get_num_items() == 0 && !lazy_fetch_page->lazy_fetch_is_loader()) associated_data.search_result_text.setString("No results found"); else associated_data.search_result_text.setString(""); @@ -2233,7 +2245,7 @@ namespace QuickMedia { AsyncImageLoader::get_instance().update(); window.display(); - if(!tabs[selected_tab].body->items.empty()) { + if(tabs[selected_tab].body->get_num_items() > 0) { if(tabs[selected_tab].body->attach_side == AttachSide::TOP && !tabs[selected_tab].body->is_bottom_cut_off()) on_reached_end(); else if(tabs[selected_tab].body->attach_side == AttachSide::BOTTOM && !tabs[selected_tab].body->is_top_cut_off()) @@ -2435,10 +2447,10 @@ namespace QuickMedia { auto body = create_body(); auto options_page = std::make_unique(this, "Select download option"); - options_page->add_option(body->items, "Download video and audio", "", [&audio_only](){ + options_page->add_option(body.get(), "Download video and audio", "", [&audio_only](){ audio_only = false; }); - options_page->add_option(body->items, "Download only audio", "", [&audio_only](){ + options_page->add_option(body.get(), "Download only audio", "", [&audio_only](){ audio_only = true; }); @@ -2534,7 +2546,7 @@ namespace QuickMedia { #define CLEANMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask|Mod4Mask|Mod5Mask)) - void Program::video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, Body *parent_body, BodyItems &next_play_items, int play_index, int *parent_body_page, const std::string &parent_page_search) { + void Program::video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, Body *parent_body, int play_index, int *parent_body_page, const std::string &parent_page_search) { PageType previous_page = pop_page_stack(); bool video_loaded = false; @@ -2551,8 +2563,8 @@ namespace QuickMedia { BodyItems related_videos; bool move_in_parent = false; - if(video_page->autoplay_next_item() && play_index + 1 >= 0 && play_index + 1 < (int)next_play_items.size()) { - related_videos.insert(related_videos.end(), next_play_items.begin() + play_index + 1, next_play_items.end()); + if(parent_body && video_page->autoplay_next_item() && play_index + 1 >= 0 && play_index + 1 < (int)parent_body->get_num_items()) { + parent_body->copy_range(play_index + 1, (size_t)-1, related_videos); move_in_parent = true; } @@ -2951,7 +2963,7 @@ namespace QuickMedia { } if(related_videos_page) { auto related_videos_body = create_body(false, true); - related_videos_body->items = related_videos; + related_videos_body->set_items(related_videos); tabs.push_back(Tab{std::move(related_videos_body), std::move(related_videos_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } if(channels_page) { @@ -3068,8 +3080,8 @@ namespace QuickMedia { fprintf(stderr, "Finished fetching page %d, num new items: %zu\n", fetch_page, new_body_items.size()); size_t num_new_messages = new_body_items.size(); if(num_new_messages > 0) { - next_play_items.insert(next_play_items.end(), new_body_items.begin(), new_body_items.end()); - if(parent_body) parent_body->items_set_dirty(); + if(parent_body) + parent_body->append_items(new_body_items); (*parent_body_page)++; related_videos = std::move(new_body_items); find_next_video(); @@ -3487,7 +3499,7 @@ namespace QuickMedia { if(image_index > 0) { --image_index; goto end_of_images_page; - } else if(image_index == 0 && chapters_body->get_selected_item() < (int)chapters_body->items.size() - 1) { + } else if(image_index == 0 && chapters_body->get_selected_item() < (int)chapters_body->get_num_items() - 1) { page_navigation = -1; goto end_of_images_page; } @@ -3891,7 +3903,7 @@ namespace QuickMedia { BodyItems next_items; int prev_selected = thread_body->get_selected_item(); // TODO: Use real title - video_content_page(thread_page, thread_page, "", true, thread_body, thread_body->items, thread_body->get_selected_item()); + video_content_page(thread_page, thread_page, "", true, thread_body, thread_body->get_selected_item()); if(thread_body->get_selected_item() != prev_selected) { comment_navigation_stack.clear(); comment_page_scroll_stack.clear(); @@ -3936,7 +3948,9 @@ namespace QuickMedia { auto file_manager_page = std::make_unique(this, (FileManagerMimeType)(FILE_MANAGER_MIME_TYPE_IMAGE|FILE_MANAGER_MIME_TYPE_VIDEO)); file_manager_page->set_current_directory(fm_dir.string()); auto file_manager_body = create_body(); - file_manager_page->get_files_in_directory(file_manager_body->items); + BodyItems body_items; + file_manager_page->get_files_in_directory(body_items); + file_manager_body->set_items(std::move(body_items)); std::vector 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)}); @@ -3983,15 +3997,15 @@ namespace QuickMedia { BodyItem *selected_item = thread_body->get_selected(); if(event.key.code == sf::Keyboard::Enter && selected_item && (comment_navigation_stack.empty() || thread_body->get_selected_item() != comment_navigation_stack.back()) && (!selected_item->replies_to.empty() || !selected_item->replies.empty())) { - for(auto &body_item : thread_body->items) { + thread_body->for_each_item([](std::shared_ptr &body_item) { body_item->visible = false; - } + }); selected_item->visible = true; for(size_t reply_to_index : selected_item->replies_to) { - thread_body->items[reply_to_index]->visible = true; + thread_body->get_item_by_index(reply_to_index)->visible = true; } for(size_t reply_index : selected_item->replies) { - thread_body->items[reply_index]->visible = true; + thread_body->get_item_by_index(reply_index)->visible = true; } comment_navigation_stack.push_back(thread_body->get_selected_item()); comment_page_scroll_stack.push_back(thread_body->get_page_scroll()); @@ -4003,23 +4017,23 @@ namespace QuickMedia { comment_navigation_stack.pop_back(); comment_page_scroll_stack.pop_back(); if(comment_navigation_stack.empty()) { - for(auto &body_item : thread_body->items) { - body_item->visible = true; - } + thread_body->for_each_item([](std::shared_ptr &body_item) { + body_item->visible = false; + }); thread_body->set_selected_item(previous_selected); thread_body->clamp_selection(); } else { - for(auto &body_item : thread_body->items) { + thread_body->for_each_item([](std::shared_ptr &body_item) { body_item->visible = false; - } + }); thread_body->set_selected_item(previous_selected); - selected_item = thread_body->items[comment_navigation_stack.back()].get(); + selected_item = thread_body->get_item_by_index(comment_navigation_stack.back()).get(); selected_item->visible = true; for(size_t reply_to_index : selected_item->replies_to) { - thread_body->items[reply_to_index]->visible = true; + thread_body->get_item_by_index(reply_to_index)->visible = true; } for(size_t reply_index : selected_item->replies) { - thread_body->items[reply_index]->visible = true; + thread_body->get_item_by_index(reply_index)->visible = true; } thread_body->clamp_selection(); } @@ -4463,6 +4477,7 @@ namespace QuickMedia { static const sf::Vector2i CHAT_MESSAGE_THUMBNAIL_MAX_SIZE(600, 337); + // TODO: Optimize 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; @@ -4480,7 +4495,7 @@ namespace QuickMedia { } // 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) { + 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 BodyItemList &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); @@ -4499,7 +4514,7 @@ namespace QuickMedia { 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) { + static bool load_cached_related_embedded_item(BodyItem *body_item, Message *message, const std::shared_ptr &me, RoomData *current_room, const BodyItemList &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); } @@ -4545,7 +4560,7 @@ 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) { + static void messages_load_cached_related_embedded_item(BodyItems &new_body_items, const BodyItemList &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); @@ -4806,7 +4821,7 @@ namespace QuickMedia { auto me = matrix->get_me(current_room); auto my_display_name = current_room->get_user_display_name(me); - auto &body_items = tabs[MESSAGES_TAB_INDEX].body->items; + auto body_items = tabs[MESSAGES_TAB_INDEX].body->get_items(); for(auto &message : messages) { // TODO: Make redacted/edited events as (redacted)/(edited) in the body if(message->related_event_type == RelatedEventType::REDACTION || message->related_event_type == RelatedEventType::EDIT) { @@ -4840,7 +4855,7 @@ namespace QuickMedia { if(messages.empty()) return; - auto &body_items = tabs[MESSAGES_TAB_INDEX].body->items; + auto body_items = tabs[MESSAGES_TAB_INDEX].body->get_items(); // TODO: Check in |messages| instead for(auto it = unresolved_reactions.begin(); it != unresolved_reactions.end();) { @@ -4882,20 +4897,19 @@ namespace QuickMedia { }; auto pinned_body_items_contains_event = [&tabs, PINNED_TAB_INDEX](const std::string &event_id) { - for(auto &body_item : tabs[PINNED_TAB_INDEX].body->items) { - if(static_cast(body_item->userdata)->event_id == event_id) - return true; - } - return false; + const int found_item_index = tabs[PINNED_TAB_INDEX].body->find_item_index([&event_id](std::shared_ptr &body_item) { + return static_cast(body_item->userdata)->event_id == event_id; + }); + return found_item_index != -1; }; auto process_pinned_events = [&tabs, &ui_tabs, &pinned_body_items_contains_event, PINNED_TAB_INDEX](const std::optional> &pinned_events) { if(!pinned_events) return; - bool empty_before = tabs[PINNED_TAB_INDEX].body->items.empty(); + bool empty_before = tabs[PINNED_TAB_INDEX].body->get_num_items() == 0; int selected_before = tabs[PINNED_TAB_INDEX].body->get_selected_item(); - auto prev_pinned_body_items = tabs[PINNED_TAB_INDEX].body->items; + auto prev_pinned_body_items = tabs[PINNED_TAB_INDEX].body->get_items_copy(); tabs[PINNED_TAB_INDEX].body->clear_items(); // TODO: Add message to rooms messages when there are new pinned events @@ -4910,7 +4924,7 @@ namespace QuickMedia { event_data->status = FetchStatus::NONE; event_data->message = nullptr; body->userdata = event_data; - tabs[PINNED_TAB_INDEX].body->items.push_back(std::move(body)); + tabs[PINNED_TAB_INDEX].body->append_item(std::move(body)); } for(auto &prev_body_item : prev_pinned_body_items) { @@ -4923,7 +4937,7 @@ namespace QuickMedia { else tabs[PINNED_TAB_INDEX].body->set_selected_item(selected_before); - ui_tabs.set_text(PINNED_TAB_INDEX, "Pinned messages (" + std::to_string(tabs[PINNED_TAB_INDEX].body->items.size()) + ")"); + ui_tabs.set_text(PINNED_TAB_INDEX, "Pinned messages (" + std::to_string(tabs[PINNED_TAB_INDEX].body->get_num_items()) + ")"); }; Body url_selection_body(BODY_THEME_MINIMAL, loading_icon, &rounded_rectangle_shader, &rounded_rectangle_mask_shader); @@ -4946,7 +4960,7 @@ namespace QuickMedia { } auto me = matrix->get_me(current_room); 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); + messages_load_cached_related_embedded_item(new_body_items, tabs[MESSAGES_TAB_INDEX].body->get_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); @@ -4999,7 +5013,7 @@ namespace QuickMedia { auto message_set_replaced_by = [&tabs, &pending_sent_replies, MESSAGES_TAB_INDEX](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); + auto body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->get_items().data(), tabs[MESSAGES_TAB_INDEX].body->get_items().size(), message->related_event_id); if(body_item) { Message *reply_to_message = static_cast(body_item->userdata); if(!reply_to_message) { @@ -5203,7 +5217,7 @@ namespace QuickMedia { message->type = MessageType::TEXT; message->timestamp = time(NULL) * 1000; - int num_items = tabs[MESSAGES_TAB_INDEX].body->items.size(); + int num_items = tabs[MESSAGES_TAB_INDEX].body->get_num_items(); bool scroll_to_end = num_items == 0; if(tabs[MESSAGES_TAB_INDEX].body->is_selected_item_last_visible_item() && selected_tab == MESSAGES_TAB_INDEX) scroll_to_end = true; @@ -5220,7 +5234,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); + load_cached_related_embedded_item(body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->get_items()); tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps({body_item}); Messages messages; messages.push_back(message); @@ -5236,7 +5250,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(get_current_theme().provisional_message_color); - load_cached_related_embedded_item(body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->items); + load_cached_related_embedded_item(body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->get_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; @@ -5261,7 +5275,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(get_current_theme().provisional_message_color); - load_cached_related_embedded_item(body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->items); + load_cached_related_embedded_item(body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->get_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; @@ -5282,15 +5296,15 @@ namespace QuickMedia { message->related_event_type = RelatedEventType::EDIT; message->related_event_id = static_cast(related_to_message)->event_id; size_t body_item_index = 0; - 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, &body_item_index); + auto body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->get_items().data(), tabs[MESSAGES_TAB_INDEX].body->get_items().size(), message->related_event_id, &body_item_index); if(body_item) { - auto body_item_shared_ptr = tabs[MESSAGES_TAB_INDEX].body->items[body_item_index]; + auto body_item_shared_ptr = tabs[MESSAGES_TAB_INDEX].body->get_item_by_index(body_item_index); body_item_shared_ptr->set_description(text); body_item_shared_ptr->set_description_color(get_current_theme().provisional_message_color); 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(edit_body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->items); + load_cached_related_embedded_item(edit_body_item.get(), message.get(), me, current_room, tabs[MESSAGES_TAB_INDEX].body->get_items()); tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps({edit_body_item}); //unreferenced_events.push_back(message); @@ -5349,7 +5363,7 @@ namespace QuickMedia { 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.get(), event_data->message, me, current_room, tabs[MESSAGES_TAB_INDEX].body->items)) + if(load_cached_related_embedded_item(body_item.get(), event_data->message, me, current_room, tabs[MESSAGES_TAB_INDEX].body->get_items())) return; std::string message_event_id = event_data->message->related_event_id; @@ -5369,7 +5383,7 @@ namespace QuickMedia { // 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); + auto related_body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->get_items().data(), tabs[MESSAGES_TAB_INDEX].body->get_items().size(), event_data->event_id); if(related_body_item) { *body_item = *related_body_item; body_item->reactions.clear(); @@ -5407,7 +5421,7 @@ namespace QuickMedia { return; } - if(load_cached_related_embedded_item(body_item.get(), message, me, current_room, tabs[MESSAGES_TAB_INDEX].body->items)) + if(load_cached_related_embedded_item(body_item.get(), message, me, current_room, tabs[MESSAGES_TAB_INDEX].body->get_items())) return; std::string message_event_id = message->related_event_id; @@ -5431,7 +5445,7 @@ namespace QuickMedia { Message *prev_message = static_cast(prev_item->userdata); if(is_system_message_type(prev_message->type) && is_system_message_type(message->type)) return true; - else if(is_system_message_type(message->type)) + else if(is_system_message_type(prev_message->type) || is_system_message_type(message->type)) return false; if(is_visual_media_message_type(prev_message->type) && !prev_item->thumbnail_url.empty()) @@ -5455,7 +5469,7 @@ namespace QuickMedia { auto fetch_more_previous_messages_if_needed = [this, &tabs, ¤t_room, &fetched_enough_messages, &previous_messages_future, MESSAGES_TAB_INDEX]() { if(!fetched_enough_messages && !previous_messages_future.valid()) { - if(tabs[MESSAGES_TAB_INDEX].body->items.size() < 30) { + if(tabs[MESSAGES_TAB_INDEX].body->get_num_items() < 30) { previous_messages_future = AsyncTask([this, ¤t_room]() { Messages messages; if(matrix->get_previous_room_messages(current_room, messages) != PluginResult::OK) @@ -5495,7 +5509,7 @@ namespace QuickMedia { current_page = PageType::VIDEO_CONTENT; auto youtube_video_page = std::make_unique(this, url); // TODO: Use real title - video_content_page(matrix_chat_page, youtube_video_page.get(), "", false, nullptr, tabs[MESSAGES_TAB_INDEX].body->items, tabs[MESSAGES_TAB_INDEX].body->get_selected_item()); + video_content_page(matrix_chat_page, youtube_video_page.get(), "", false, tabs[MESSAGES_TAB_INDEX].body.get(), tabs[MESSAGES_TAB_INDEX].body->get_selected_item()); redraw = true; avatar_applied = false; } else { @@ -5531,7 +5545,7 @@ namespace QuickMedia { return; const int selected_tab = ui_tabs.get_selected(); - int num_items = tabs[MESSAGES_TAB_INDEX].body->items.size(); + int num_items = tabs[MESSAGES_TAB_INDEX].body->get_num_items(); bool scroll_to_end = num_items == 0; if(selected_tab == MESSAGES_TAB_INDEX && (tabs[MESSAGES_TAB_INDEX].body->is_selected_item_last_visible_item() || !tabs[MESSAGES_TAB_INDEX].body->get_selected())) scroll_to_end = true; @@ -5543,7 +5557,7 @@ namespace QuickMedia { } 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); + messages_load_cached_related_embedded_item(new_body_items, tabs[MESSAGES_TAB_INDEX].body->get_items(), me, current_room); tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(std::move(new_body_items)); if(scroll_to_end) tabs[MESSAGES_TAB_INDEX].body->select_last_item(); @@ -5572,8 +5586,7 @@ namespace QuickMedia { bool prev_no_video = no_video; no_video = is_audio; video_page->set_url(selected->url); - BodyItems next_items; - video_content_page(matrix_chat_page, video_page.get(), selected_item_message->body, message_type == MessageType::VIDEO || message_type == MessageType::AUDIO, nullptr, next_items, 0); + video_content_page(matrix_chat_page, video_page.get(), selected_item_message->body, message_type == MessageType::VIDEO || message_type == MessageType::AUDIO, nullptr, 0); no_video = prev_no_video; redraw = true; avatar_applied = false; @@ -5598,7 +5611,7 @@ namespace QuickMedia { url_selection_body.clear_items(); for(const std::string &url : urls) { auto body_item = BodyItem::create(url); - url_selection_body.items.push_back(std::move(body_item)); + url_selection_body.append_item(std::move(body_item)); } return true; } @@ -5630,50 +5643,46 @@ namespace QuickMedia { auto update_pinned_messages_author = [&tabs, ¤t_room, PINNED_TAB_INDEX](const std::shared_ptr &user) { fprintf(stderr, "updated pinned messages author for user: %s\n", user->user_id.c_str()); - for(auto &pinned_body_item : tabs[PINNED_TAB_INDEX].body->items) { + tabs[PINNED_TAB_INDEX].body->for_each_item([¤t_room, &user](std::shared_ptr &pinned_body_item) { Message *message = static_cast(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; - + return; user_update_display_info(pinned_body_item.get(), current_room, message); - } + }); }; auto update_messages_author = [&tabs, ¤t_room, MESSAGES_TAB_INDEX](const std::shared_ptr &user) { fprintf(stderr, "updated messages author for user: %s\n", user->user_id.c_str()); - for(auto &message_body_items : tabs[MESSAGES_TAB_INDEX].body->items) { + tabs[MESSAGES_TAB_INDEX].body->for_each_item([¤t_room, &user](std::shared_ptr &message_body_items) { Message *message = static_cast(message_body_items->userdata); if(!message || message->user != user) - continue; - + return; user_update_display_info(message_body_items.get(), current_room, message); - } + }); }; // TODO: Optimize auto update_pinned_messages_authors = [&tabs, ¤t_room, PINNED_TAB_INDEX]() { fprintf(stderr, "updated pinned messages author for all users in room: %s\n", current_room->id.c_str()); - for(auto &pinned_body_item : tabs[PINNED_TAB_INDEX].body->items) { + tabs[PINNED_TAB_INDEX].body->for_each_item([¤t_room](std::shared_ptr &pinned_body_item) { Message *message = static_cast(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; - + return; user_update_display_info(pinned_body_item.get(), current_room, message); - } + }); }; // TODO: Optimize auto update_messages_authors = [&tabs, ¤t_room, MESSAGES_TAB_INDEX]() { fprintf(stderr, "updated messages author for all users in room: %s\n", current_room->id.c_str()); - for(auto &message_body_items : tabs[MESSAGES_TAB_INDEX].body->items) { + tabs[MESSAGES_TAB_INDEX].body->for_each_item([¤t_room](std::shared_ptr &message_body_items) { Message *message = static_cast(message_body_items->userdata); if(!message) - continue; - + return; user_update_display_info(message_body_items.get(), current_room, message); - } + }); }; auto cleanup_tasks = [&set_read_marker_future, &fetch_message_future, &fetch_users_future, &typing_state_queue, &typing_state_thread, &post_task_queue, &provisional_message_queue, &fetched_messages_set, &sent_messages, &pending_sent_replies, &post_thread, &tabs, MESSAGES_TAB_INDEX, PINNED_TAB_INDEX, USERS_TAB_INDEX]() { @@ -5699,9 +5708,10 @@ namespace QuickMedia { if(!tabs.empty()) { tabs[MESSAGES_TAB_INDEX].body->clear_items(); - for(auto &body_item : tabs[PINNED_TAB_INDEX].body->items) { - delete (PinnedEventData*)body_item->userdata; - } + tabs[PINNED_TAB_INDEX].body->for_each_item([](std::shared_ptr &pinned_body_item) { + delete (PinnedEventData*)pinned_body_item->userdata; + pinned_body_item->userdata = nullptr; + }); tabs[PINNED_TAB_INDEX].body->clear_items(); tabs[USERS_TAB_INDEX].body->clear_items(); } @@ -5824,6 +5834,8 @@ namespace QuickMedia { goto chat_page_end; } else if(event.key.code == sf::Keyboard::I && event.key.control) { BodyItem *selected_item = tabs[selected_tab].body->get_selected(); + if(selected_item && selected_item->url.empty()) + selected_item = selected_item->embedded_item.get(); if(selected_item && !selected_item->url.empty() && !selected_item->thumbnail_url.empty()) { Message *selected_item_message = nullptr; if(selected_tab == MESSAGES_TAB_INDEX) { @@ -6051,7 +6063,9 @@ namespace QuickMedia { auto file_manager_page = std::make_unique(this); file_manager_page->set_current_directory(fm_dir.string()); auto file_manager_body = create_body(); - file_manager_page->get_files_in_directory(file_manager_body->items); + BodyItems body_items; + file_manager_page->get_files_in_directory(body_items); + file_manager_body->set_items(std::move(body_items)); std::vector 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)}); @@ -6226,7 +6240,7 @@ namespace QuickMedia { modify_related_messages_in_current_room(new_messages); process_reactions(new_messages); // TODO: Do not loop all items, only loop the new items - resolve_unreferenced_events_with_body_items(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size()); + resolve_unreferenced_events_with_body_items(tabs[MESSAGES_TAB_INDEX].body->get_items().data(), tabs[MESSAGES_TAB_INDEX].body->get_items().size()); } if(num_new_messages > 0 && current_room->initial_prev_messages_fetch) { current_room->initial_prev_messages_fetch = false; @@ -6398,7 +6412,7 @@ namespace QuickMedia { if(selected_tab == MESSAGES_TAB_INDEX && current_room && current_room->body_item && !current_room->last_message_read && matrix->is_initial_sync_finished()) { if(!tabs[selected_tab].body->is_bottom_cut_off() && is_window_focused && chat_state != ChatState::URL_SELECTION && !setting_read_marker && read_marker_timer.getElapsedTime().asMilliseconds() >= read_marker_timeout_ms) { - auto &body_items = tabs[selected_tab].body->items; + auto body_items = tabs[selected_tab].body->get_items(); int last_timeline_message = (int)body_items.size() - 1; for(int i = last_timeline_message - 1; i >= 0; --i) { BodyItem *item = body_items[i].get(); @@ -6574,22 +6588,24 @@ namespace QuickMedia { auto invites_body = create_body(); auto matrix_invites_page = std::make_unique(this, matrix, invites_body.get()); + BodyItems room_dir_body_items; + add_body_item_unique_title(room_dir_body_items, matrix->get_homeserver_domain()); + add_body_item_unique_title(room_dir_body_items, "midov.pl"); + add_body_item_unique_title(room_dir_body_items, "matrix.org"); + add_body_item_unique_title(room_dir_body_items, "kde.org"); + add_body_item_unique_title(room_dir_body_items, "librem.one"); + add_body_item_unique_title(room_dir_body_items, "maunium.net"); + add_body_item_unique_title(room_dir_body_items, "halogen.city"); + add_body_item_unique_title(room_dir_body_items, "gnome.org"); + add_body_item_unique_title(room_dir_body_items, "shivering-isles.com"); + add_body_item_unique_title(room_dir_body_items, "nerdsin.space"); + add_body_item_unique_title(room_dir_body_items, "glowers.club"); + add_body_item_unique_title(room_dir_body_items, "privacytools.io"); + add_body_item_unique_title(room_dir_body_items, "linuxdelta.com"); + add_body_item_unique_title(room_dir_body_items, "tchncs.de"); + add_body_item_unique_title(room_dir_body_items, "jupiterbroadcasting.com"); auto room_directory_body = create_body(); - add_body_item_unique_title(room_directory_body->items, matrix->get_homeserver_domain()); - add_body_item_unique_title(room_directory_body->items, "midov.pl"); - add_body_item_unique_title(room_directory_body->items, "matrix.org"); - add_body_item_unique_title(room_directory_body->items, "kde.org"); - add_body_item_unique_title(room_directory_body->items, "librem.one"); - add_body_item_unique_title(room_directory_body->items, "maunium.net"); - add_body_item_unique_title(room_directory_body->items, "halogen.city"); - add_body_item_unique_title(room_directory_body->items, "gnome.org"); - add_body_item_unique_title(room_directory_body->items, "shivering-isles.com"); - add_body_item_unique_title(room_directory_body->items, "nerdsin.space"); - add_body_item_unique_title(room_directory_body->items, "glowers.club"); - add_body_item_unique_title(room_directory_body->items, "privacytools.io"); - add_body_item_unique_title(room_directory_body->items, "linuxdelta.com"); - add_body_item_unique_title(room_directory_body->items, "tchncs.de"); - add_body_item_unique_title(room_directory_body->items, "jupiterbroadcasting.com"); + room_directory_body->set_items(std::move(room_dir_body_items)); auto matrix_room_directory_page = std::make_unique(this, matrix); MatrixQuickMedia matrix_handler(this, matrix, matrix_rooms_page.get(), matrix_rooms_tag_page.get(), matrix_invites_page.get(), matrix_notifications_page.get()); @@ -6767,6 +6783,7 @@ namespace QuickMedia { return; } + string_replace_all(filename, '/', '_'); std::string output_filepath = file_save_page(filename); if(!window.isOpen() || output_filepath.empty()) { exit_code = 1; @@ -6959,7 +6976,9 @@ namespace QuickMedia { auto file_manager_page = std::make_unique(this); file_manager_page->set_current_directory(file_manager_start_dir); auto file_manager_body = create_body(); - file_manager_page->get_files_in_directory(file_manager_body->items); + BodyItems body_items; + file_manager_page->get_files_in_directory(body_items); + file_manager_body->set_items(std::move(body_items)); auto search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); Tabs ui_tabs(&rounded_rectangle_shader); @@ -6985,7 +7004,7 @@ namespace QuickMedia { if(task_result == TaskResult::TRUE) { if(!new_tabs.empty()) { - file_manager_body->items = std::move(new_tabs[0].body->items); + new_tabs[0].body->move_items_to(file_manager_body.get()); file_manager_body->select_first_item(); search_bar->clear(); } @@ -7038,10 +7057,10 @@ namespace QuickMedia { auto body = create_body(); auto options_page = std::make_unique(this, "Are you sure you want to overwrite " + filename_full_path.data + "?"); - options_page->add_option(body->items, "No", "", [&overwrite](){ + options_page->add_option(body.get(), "No", "", [&overwrite](){ overwrite = false; }); - options_page->add_option(body->items, "Yes", "", [&overwrite](){ + options_page->add_option(body.get(), "Yes", "", [&overwrite](){ overwrite = true; }); -- cgit v1.2.3