aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-08-03 15:06:57 +0200
committerdec05eba <dec05eba@protonmail.com>2021-08-05 05:50:23 +0200
commit6c85194c3b1baef0eaa011c4f1b8e48e11860f45 (patch)
tree61f3eb4304091fd2203519702a4f4daf184c5a59 /src
parentcbc6997c0a5659239d2cd971f2fa77eeda53550b (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/Body.cpp192
-rw-r--r--src/BodyItem.cpp83
-rw-r--r--src/QuickMedia.cpp291
-rw-r--r--src/Storage.cpp3
-rw-r--r--src/plugins/FileManager.cpp2
-rw-r--r--src/plugins/Fourchan.cpp2
-rw-r--r--src/plugins/HotExamples.cpp2
-rw-r--r--src/plugins/MangaGeneric.cpp2
-rw-r--r--src/plugins/Mangadex.cpp4
-rw-r--r--src/plugins/Manganelo.cpp2
-rw-r--r--src/plugins/Matrix.cpp166
-rw-r--r--src/plugins/NyaaSi.cpp14
-rw-r--r--src/plugins/Soundcloud.cpp6
13 files changed, 440 insertions, 329 deletions
diff --git a/src/Body.cpp b/src/Body.cpp
index 0804399..6e01266 100644
--- a/src/Body.cpp
+++ b/src/Body.cpp
@@ -92,79 +92,6 @@ namespace QuickMedia {
return sf::Vector2f(vec.x, vec.y);
}
- BodyItem::BodyItem(std::string _title) :
- visible(true),
- dirty(false),
- dirty_description(false),
- dirty_author(false),
- dirty_timestamp(false),
- thumbnail_is_local(false),
- userdata(nullptr),
- timestamp(0),
- title_color(get_current_theme().text_color),
- author_color(get_current_theme().text_color),
- description_color(get_current_theme().text_color)
- {
- if(!_title.empty())
- set_title(std::move(_title));
- }
-
- BodyItem& BodyItem::operator=(const BodyItem &other) {
- url = other.url;
- thumbnail_url = other.thumbnail_url;
- visible = other.visible;
- dirty = !other.title.empty();
- dirty_description = !other.description.empty();
- dirty_author = !other.author.empty();
- dirty_timestamp = other.timestamp != 0;
- thumbnail_is_local = other.thumbnail_is_local;
- title_text.reset();
- description_text.reset();
- author_text.reset();
- timestamp_text.reset();
- replies_to = other.replies_to;
- replies = other.replies;
- post_number = other.post_number;
- userdata = other.userdata;
- loaded_height = 0.0f;
- loaded_image_size = sf::Vector2f(0.0f, 0.0f);
- loaded_content_height = 0.0f;
- embedded_item_status = other.embedded_item_status;
- if(other.embedded_item) {
- embedded_item.reset(new BodyItem(""));
- *embedded_item = *other.embedded_item;
- } else {
- embedded_item.reset();
- }
- thumbnail_mask_type = other.thumbnail_mask_type;
- thumbnail_size = other.thumbnail_size;
- reactions.clear();
- for(auto &reaction : other.reactions) {
- Reaction reaction_copy;
- reaction_copy.text = std::make_unique<Text>(*reaction.text);
- reaction_copy.userdata = reaction.userdata;
- reactions.push_back(std::move(reaction_copy));
- }
- title = other.title;
- description = other.description;
- author = other.author;
- timestamp = other.timestamp;
- title_color = other.title_color;
- author_color = other.author_color;
- description_color = other.description_color;
- extra = other.extra;
- keep_alive_frames = other.keep_alive_frames;
- return *this;
- }
-
- void BodyItem::add_reaction(std::string text, void *userdata) {
- sf::String str = sf::String::fromUtf8(text.begin(), text.end());
- Reaction reaction;
- reaction.text = std::make_unique<Text>(std::move(str), false, std::floor(14 * get_ui_scale()), 0.0f);
- reaction.userdata = userdata;
- reactions.push_back(std::move(reaction));
- }
-
Body::Body(BodyTheme body_theme, sf::Texture &loading_icon_texture, sf::Shader *rounded_rectangle_shader, sf::Shader *rounded_rectangle_mask_shader) :
draw_thumbnails(true),
body_item_render_callback(nullptr),
@@ -329,6 +256,13 @@ namespace QuickMedia {
clamp_selection();
}
+ void Body::set_items(BodyItems items) {
+ for(auto &item : items) {
+ filter_search_fuzzy_item(current_filter, item.get());
+ }
+ this->items = std::move(items);
+ }
+
void Body::clear_items() {
items.clear();
selected_item = 0;
@@ -336,18 +270,53 @@ namespace QuickMedia {
page_scroll = 0.0f;
}
+ void Body::prepend_item(std::shared_ptr<BodyItem> body_item) {
+ apply_search_filter_for_item(body_item.get());
+ items.insert(items.begin(), std::move(body_item));
+ }
+
void Body::prepend_items_reverse(BodyItems new_items) {
+ for(auto &item : new_items) {
+ filter_search_fuzzy_item(current_filter, item.get());
+ }
items.insert(items.begin(), std::make_move_iterator(new_items.rbegin()), std::make_move_iterator(new_items.rend()));
- items_set_dirty();
+ }
+
+ void Body::append_item(std::shared_ptr<BodyItem> body_item) {
+ apply_search_filter_for_item(body_item.get());
+ items.push_back(std::move(body_item));
}
void Body::append_items(BodyItems new_items) {
+ for(auto &item : new_items) {
+ filter_search_fuzzy_item(current_filter, item.get());
+ }
items.insert(items.end(), std::make_move_iterator(new_items.begin()), std::make_move_iterator(new_items.end()));
- items_set_dirty();
+ }
+
+ void Body::insert_item(std::shared_ptr<BodyItem> body_item, int index) {
+ apply_search_filter_for_item(body_item.get());
+ items.insert(items.begin() + index, std::move(body_item));
+ }
+
+ void Body::move_items_to(Body *other_body) {
+ other_body->set_items(std::move(items));
+ }
+
+ void Body::move_item(size_t src_index, size_t dst_index) {
+ assert(src_index < items.size());
+ assert(dst_index < items.size());
+ auto item_to_move = std::move(items[src_index]);
+ items.erase(items.begin() + src_index);
+ if(dst_index <= src_index)
+ items.insert(items.begin() + dst_index, std::move(item_to_move));
+ else
+ items.insert(items.begin() + dst_index - 1, std::move(item_to_move));
}
// TODO: Binary search and use hint to start search from start or end (for example when adding "previous" items or "next" items)
size_t Body::insert_item_by_timestamp(std::shared_ptr<BodyItem> body_item) {
+ apply_search_filter_for_item(body_item.get());
for(size_t i = 0; i < items.size(); ++i) {
if(body_item->get_timestamp() < items[i]->get_timestamp()) {
items.insert(items.begin() + i, std::move(body_item));
@@ -369,7 +338,6 @@ namespace QuickMedia {
}
clamp_selection();
- items_set_dirty(); // TODO: Apply this now, otherwise the below code wont work
if(!selected_body_item)
return;
@@ -382,6 +350,66 @@ namespace QuickMedia {
}
}
+ void Body::for_each_item(std::function<void(std::shared_ptr<BodyItem>&)> callback) {
+ for(std::shared_ptr<BodyItem> &body_item : items) {
+ callback(body_item);
+ }
+ }
+
+ std::shared_ptr<BodyItem> Body::find_item(std::function<bool(std::shared_ptr<BodyItem>&)> callback) {
+ for(std::shared_ptr<BodyItem> &body_item : items) {
+ if(callback(body_item))
+ return body_item;
+ }
+ return nullptr;
+ }
+
+ int Body::find_item_index(std::function<bool(std::shared_ptr<BodyItem>&)> callback) {
+ for(int i = 0; i != (int)items.size(); ++i) {
+ std::shared_ptr<BodyItem> &body_item = items[i];
+ if(callback(body_item))
+ return i;
+ }
+ return -1;
+ }
+
+ bool Body::erase_item(std::function<bool(std::shared_ptr<BodyItem>&)> callback) {
+ for(auto it = items.begin(), end = items.end(); it != end; ++it) {
+ if(callback(*it)) {
+ items.erase(it);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ std::shared_ptr<BodyItem> Body::get_item_by_index(size_t index) {
+ assert(index < items.size());
+ return items[index];
+ }
+
+ BodyItemList Body::get_items() {
+ return BodyItemList(&items);
+ }
+
+ BodyItems Body::get_items_copy() {
+ return items;
+ }
+
+ void Body::copy_range(size_t start_index, size_t end_index, BodyItems &target) {
+ assert(end_index == (size_t)-1 || end_index >= start_index);
+ assert(start_index < items.size() && (end_index == (size_t)-1 || end_index < items.size()));
+ target.insert(target.end(), items.begin() + start_index, end_index == (size_t)-1 ? items.end() : (items.begin() + end_index));
+ }
+
+ size_t Body::get_num_items() const {
+ return items.size();
+ }
+
+ void Body::reverse_items() {
+ std::reverse(items.begin(), items.end());
+ }
+
void Body::clear_cache() {
clear_text_cache();
malloc_trim(0);
@@ -554,12 +582,6 @@ namespace QuickMedia {
// TODO: Use a render target for the whole body so all images can be put into one.
// TODO: Load thumbnails with more than one thread.
void Body::draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size, const Json::Value &content_progress) {
- if(items_dirty != DirtyState::FALSE) {
- if(using_filter || items_dirty == DirtyState::FORCE_TRUE)
- filter_search_fuzzy(current_filter);
- items_dirty = DirtyState::FALSE;
- }
-
const bool rendering_card_view = card_view && card_view_enabled;
body_size_changed = std::abs(size.x - body_size.x) > 0.1f || std::abs(size.y - body_size.y) > 0.1f;
@@ -1599,7 +1621,6 @@ namespace QuickMedia {
// TODO: Support utf-8 case insensitive find
static bool string_find_fuzzy_case_insensitive(const std::string &str, const std::string &substr) {
- if(str.empty()) return false;
if(substr.empty()) return true;
size_t str_index = 0;
@@ -1623,7 +1644,6 @@ namespace QuickMedia {
void Body::filter_search_fuzzy(const std::string &text) {
current_filter = text;
- items_dirty = DirtyState::FALSE;
if(text.empty()) {
for(auto &item : items) {
@@ -1670,10 +1690,6 @@ namespace QuickMedia {
page_scroll = scroll;
}
- void Body::items_set_dirty(bool force) {
- items_dirty = force ? DirtyState::FORCE_TRUE : DirtyState::TRUE;
- }
-
void Body::apply_search_filter_for_item(BodyItem *body_item) {
filter_search_fuzzy_item(current_filter, body_item);
}
diff --git a/src/BodyItem.cpp b/src/BodyItem.cpp
new file mode 100644
index 0000000..bf6e45d
--- /dev/null
+++ b/src/BodyItem.cpp
@@ -0,0 +1,83 @@
+#include "../include/BodyItem.hpp"
+#include "../include/Theme.hpp"
+#include "../include/Utils.hpp"
+#include <cmath>
+
+namespace QuickMedia {
+ BodyItem::BodyItem(std::string _title) :
+ visible(true),
+ dirty(false),
+ dirty_description(false),
+ dirty_author(false),
+ dirty_timestamp(false),
+ thumbnail_is_local(false),
+ userdata(nullptr),
+ timestamp(0),
+ title_color(get_current_theme().text_color),
+ author_color(get_current_theme().text_color),
+ description_color(get_current_theme().text_color)
+ {
+ if(!_title.empty())
+ set_title(std::move(_title));
+ }
+
+ BodyItem& BodyItem::operator=(const BodyItem &other) {
+ url = other.url;
+ thumbnail_url = other.thumbnail_url;
+ visible = other.visible;
+ dirty = !other.title.empty();
+ dirty_description = !other.description.empty();
+ dirty_author = !other.author.empty();
+ dirty_timestamp = other.timestamp != 0;
+ thumbnail_is_local = other.thumbnail_is_local;
+ title_text.reset();
+ description_text.reset();
+ author_text.reset();
+ timestamp_text.reset();
+ replies_to = other.replies_to;
+ replies = other.replies;
+ post_number = other.post_number;
+ userdata = other.userdata;
+ loaded_height = 0.0f;
+ loaded_image_size = sf::Vector2f(0.0f, 0.0f);
+ loaded_content_height = 0.0f;
+ embedded_item_status = other.embedded_item_status;
+ if(other.embedded_item) {
+ embedded_item.reset(new BodyItem(""));
+ *embedded_item = *other.embedded_item;
+ } else {
+ embedded_item.reset();
+ }
+ thumbnail_mask_type = other.thumbnail_mask_type;
+ thumbnail_size = other.thumbnail_size;
+ reactions.clear();
+ for(auto &reaction : other.reactions) {
+ Reaction reaction_copy;
+ reaction_copy.text = std::make_unique<Text>(*reaction.text);
+ reaction_copy.userdata = reaction.userdata;
+ reactions.push_back(std::move(reaction_copy));
+ }
+ title = other.title;
+ description = other.description;
+ author = other.author;
+ timestamp = other.timestamp;
+ title_color = other.title_color;
+ author_color = other.author_color;
+ description_color = other.description_color;
+ extra = other.extra;
+ keep_alive_frames = other.keep_alive_frames;
+ return *this;
+ }
+
+ void BodyItem::add_reaction(std::string text, void *userdata) {
+ sf::String str = sf::String::fromUtf8(text.begin(), text.end());
+ Reaction reaction;
+ reaction.text = std::make_unique<Text>(std::move(str), false, std::floor(14 * get_ui_scale()), 0.0f);
+ reaction.userdata = userdata;
+ reactions.push_back(std::move(reaction));
+ }
+
+ void BodyItem::draw_list(Body *body, sf::RenderTarget &render_target) {
+
+ }
+} \ No newline at end of file
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<PipePage>(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<ManganeloSearchPage>(this), create_search_bar("Search...", 400)});
@@ -1176,31 +1178,42 @@ namespace QuickMedia {
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) {
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<NyaaSiCategoryPage>(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<NyaaSiCategoryPage>(this, true), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
} else if(strcmp(plugin_name, "4chan") == 0) {
auto boards_page = std::make_unique<FourchanBoardsPage>(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<HotExamplesLanguageSelectPage>(this), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
} else if(strcmp(plugin_name, "file-manager") == 0) {
auto file_manager_page = std::make_unique<FileManagerPage>(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<PipePage>(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<YoutubeVideoPage>(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<std::string> 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<Tab> 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<VideoPage*>(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<VideoPage*>(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<MatrixChatPage*>(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<LazyFetchPage*>(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<OptionsPage>(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<FileManagerPage>(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<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)});
@@ -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<BodyItem> &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<BodyItem> &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<BodyItem> &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<BodyItem> find_body_item_by_event_id(const std::shared_ptr<BodyItem> *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<UserInfo> &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<UserInfo> &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<UserInfo> &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<UserInfo> &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<Message*>(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<PinnedEventData*>(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<BodyItem> &body_item) {
+ return static_cast<PinnedEventData*>(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<std::vector<std::string>> &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> 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<Message*>(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<Message*>(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, &current_room, text, msgtype, body_item, message]() {
ProvisionalMessage provisional_message;
@@ -5261,7 +5275,7 @@ namespace QuickMedia {
message->related_event_id = static_cast<Message*>(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, &current_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<Message*>(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<Message*>(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, &current_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<Messages>([this, &current_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<YoutubeVideoPage>(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, &current_room, PINNED_TAB_INDEX](const std::shared_ptr<UserInfo> &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([&current_room, &user](std::shared_ptr<BodyItem> &pinned_body_item) {
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;
-
+ return;
user_update_display_info(pinned_body_item.get(), current_room, message);
- }
+ });
};
auto update_messages_author = [&tabs, &current_room, MESSAGES_TAB_INDEX](const std::shared_ptr<UserInfo> &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([&current_room, &user](std::shared_ptr<BodyItem> &message_body_items) {
Message *message = static_cast<Message*>(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, &current_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([&current_room](std::shared_ptr<BodyItem> &pinned_body_item) {
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;
-
+ return;
user_update_display_info(pinned_body_item.get(), current_room, message);
- }
+ });
};
// TODO: Optimize
auto update_messages_authors = [&tabs, &current_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([&current_room](std::shared_ptr<BodyItem> &message_body_items) {
Message *message = static_cast<Message*>(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<BodyItem> &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<FileManagerPage>(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<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)});
@@ -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<MatrixInvitesPage>(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<MatrixRoomDirectoryPage>(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<FileManagerPage>(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<OptionsPage>(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;
});
diff --git a/src/Storage.cpp b/src/Storage.cpp
index 50d1ffd..9a1c492 100644
--- a/src/Storage.cpp
+++ b/src/Storage.cpp
@@ -309,7 +309,8 @@ namespace QuickMedia {
char *env = getenv("PATH");
std::unordered_set<std::string> paths;
string_split(env, ':', [&paths](const char *str, size_t size) {
- paths.insert(std::string(str, size));
+ if(size > 0)
+ paths.insert(std::string(str, size));
return true;
});
diff --git a/src/plugins/FileManager.cpp b/src/plugins/FileManager.cpp
index f78265b..295b962 100644
--- a/src/plugins/FileManager.cpp
+++ b/src/plugins/FileManager.cpp
@@ -52,7 +52,7 @@ namespace QuickMedia {
set_last_accessed_dir(current_dir);
auto body = create_body();
- body->items = std::move(result_items);
+ body->set_items(std::move(result_items));
result_tabs.push_back(Tab{std::move(body), nullptr, nullptr});
return PluginResult::OK;
}
diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp
index c1d7d6a..f7c9910 100644
--- a/src/plugins/Fourchan.cpp
+++ b/src/plugins/Fourchan.cpp
@@ -365,7 +365,7 @@ namespace QuickMedia {
}
auto body = create_body(false);
- body->items = std::move(result_items);
+ body->set_items(std::move(result_items));
result_tabs.push_back(Tab{std::move(body), std::make_unique<FourchanThreadPage>(program, board_id, url), nullptr});
return PluginResult::OK;
}
diff --git a/src/plugins/HotExamples.cpp b/src/plugins/HotExamples.cpp
index 02f1217..29e0110 100644
--- a/src/plugins/HotExamples.cpp
+++ b/src/plugins/HotExamples.cpp
@@ -132,7 +132,7 @@ namespace QuickMedia {
quickmedia_html_search_deinit(&html_search);
auto body = create_body();
- body->items = std::move(result_items);
+ body->set_items(std::move(result_items));
result_tabs.push_back({ std::move(body), std::make_unique<HotExamplesCodeExamplesPage>(program, title + " code examples"), create_search_bar("Search...", SEARCH_DELAY_FILTER) });
return PluginResult::OK;
}
diff --git a/src/plugins/MangaGeneric.cpp b/src/plugins/MangaGeneric.cpp
index 4668970..90da0c2 100644
--- a/src/plugins/MangaGeneric.cpp
+++ b/src/plugins/MangaGeneric.cpp
@@ -368,7 +368,7 @@ namespace QuickMedia {
return PluginResult::ERR;
auto body = create_body();
- body->items = std::move(chapters_items);
+ body->set_items(std::move(chapters_items));
result_tabs.push_back(Tab{std::move(body), std::make_unique<MangaGenericChaptersPage>(program, title, url, manga_id_extractor, service_name, website_url, &list_page_query, fail_on_http_error), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
for(auto &it : creators) {
diff --git a/src/plugins/Mangadex.cpp b/src/plugins/Mangadex.cpp
index 477608e..98683c1 100644
--- a/src/plugins/Mangadex.cpp
+++ b/src/plugins/Mangadex.cpp
@@ -307,7 +307,9 @@ namespace QuickMedia {
PluginResult MangadexSearchPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
chapter_image_urls.clear();
auto body = create_body();
- get_chapters_for_manga(this, url, 0, body->items, chapter_image_urls);
+ BodyItems body_items;
+ get_chapters_for_manga(this, url, 0, body_items, chapter_image_urls);
+ body->set_items(std::move(body_items));
result_tabs.push_back(Tab{std::move(body), std::make_unique<MangadexChaptersPage>(program, this, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
return PluginResult::OK;
}
diff --git a/src/plugins/Manganelo.cpp b/src/plugins/Manganelo.cpp
index e0517dd..d3d7bfa 100644
--- a/src/plugins/Manganelo.cpp
+++ b/src/plugins/Manganelo.cpp
@@ -93,7 +93,7 @@ namespace QuickMedia {
return PluginResult::ERR;
auto chapters_body = page->create_body();
- chapters_body->items = std::move(chapters_items);
+ chapters_body->set_items(std::move(chapters_items));
result_tabs.push_back(Tab{std::move(chapters_body), std::make_unique<ManganeloChaptersPage>(page->program, title, url), page->create_search_bar("Search...", SEARCH_DELAY_FILTER)});
// TODO: Fix. Doesn't work because manganelo changes creator url format
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 18a76eb..f072a27 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -506,26 +506,26 @@ namespace QuickMedia {
});
}
- static void insert_room_body_item_by_timestamp(BodyItems &body_items, std::shared_ptr<BodyItem> new_body_item) {
+ static void insert_room_body_item_by_timestamp(Body *body, 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));
+ const int insert_index = body->find_item_index([new_room](std::shared_ptr<BodyItem> &body_item) {
+ RoomData *room = static_cast<RoomData*>(body_item->userdata);
+ return new_room->last_message_timestamp >= room->last_message_timestamp;
+ });
+
+ if(insert_index == -1)
+ body->append_item(std::move(new_body_item));
+ else
+ body->insert_item(std::move(new_body_item), insert_index);
}
+ // TODO: Optimize
void body_set_selected_item_by_url(Body *body, const std::string &url) {
- for(size_t i = 0; i < body->items.size(); ++i) {
- if(body->items[i]->url == url) {
- body->select_first_item();
- body->set_selected_item(i, false);
- return;
- }
- }
+ const int found_item_index = body->find_item_index([&url](std::shared_ptr<BodyItem> &body_item) {
+ return body_item->url == url;
+ });
+ if(found_item_index != -1)
+ body->set_selected_item(found_item_index, false);
}
void MatrixQuickMedia::clear_data() {
@@ -658,12 +658,8 @@ 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<BodyItem> body_item) {
- insert_room_body_item_by_timestamp(body->items, body_item);
+ insert_room_body_item_by_timestamp(body, body_item);
}
void MatrixRoomsPage::move_room_to_top(RoomData *room) {
@@ -678,28 +674,25 @@ namespace QuickMedia {
if(room_body_index == selected_item)
return;
- for(size_t i = 0; i < body->items.size(); ++i) {
- RoomData *room_i = static_cast<RoomData*>(body->items[i]->userdata);
+ for(size_t i = 0; i < body->get_num_items(); ++i) {
+ RoomData *room_i = static_cast<RoomData*>(body->get_item_by_index(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);
- if(room_body_index >= (int)i)
- body->items.insert(body->items.begin() + i, std::move(body_item_to_insert));
- else
- body->items.insert(body->items.begin() + (i - 1), std::move(body_item_to_insert));
- if((int)i < selected_item && room_body_index > selected_item && body->items.size() > 1 && i != body->items.size() - 1) {
+ body->move_item(room_body_index, i);
+ if((int)i < selected_item && room_body_index > selected_item && body->get_num_items() > 1 && i != body->get_num_items() - 1)
body->select_next_item();
- }
+
return;
}
}
}
void MatrixRoomsPage::remove_body_item_by_room_id(const std::string &room_id) {
- remove_body_item_by_url(body->items, room_id);
+ body->erase_item([&room_id](std::shared_ptr<BodyItem> &body_item) {
+ return body_item->url == room_id;
+ });
if(current_chat_page && current_chat_page->room_id == room_id) {
program->set_go_to_previous_page();
body->select_first_item();
@@ -731,9 +724,10 @@ namespace QuickMedia {
auto body = create_body(true);
Body *body_ptr = body.get();
TagData &tag_data = tag_body_items_by_name[url];
- body->items = tag_data.room_body_items;
+ BodyItems room_body_items = tag_data.room_body_items;
+ sort_room_body_items(room_body_items);
+ body->set_items(std::move(room_body_items));
//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());
@@ -742,10 +736,6 @@ 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<BodyItem> body_item, const std::string &tag) {
TagData *tag_data;
auto tag_body_it = tag_body_items_by_name.find(tag);
@@ -759,7 +749,7 @@ namespace QuickMedia {
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->append_item(tag_body_item);
tag_data = &tag_body_items_by_name[tag];
tag_data->tag_item = tag_body_item;
}
@@ -789,9 +779,10 @@ namespace QuickMedia {
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);
+ const auto &tag_item = tag_body_it->second.tag_item;
+ body->erase_item([&tag_item](std::shared_ptr<BodyItem> &body_item) {
+ return body_item == tag_item;
+ });
tag_body_items_by_name.erase(tag_body_it);
}
}
@@ -831,8 +822,8 @@ namespace QuickMedia {
PluginResult MatrixInvitesPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
auto body = create_body();
- body->items.push_back(BodyItem::create("Accept"));
- body->items.push_back(BodyItem::create("Decline"));
+ body->append_item(BodyItem::create("Accept"));
+ body->append_item(BodyItem::create("Decline"));
result_tabs.push_back(Tab{std::move(body), std::make_unique<MatrixInviteDetailsPage>(program, matrix, this, url, "Invite to " + title), nullptr});
return PluginResult::OK;
}
@@ -864,16 +855,19 @@ namespace QuickMedia {
// 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));
- if(body->items.size() != prev_invite_count) {
- prev_invite_count = body->items.size();
- title = "Invites (" + std::to_string(body->items.size()) + ")";
+ if(body->get_num_items() != prev_invite_count) {
+ prev_invite_count = body->get_num_items();
+ title = "Invites (" + std::to_string(body->get_num_items()) + ")";
}
}
void MatrixInvitesPage::remove_body_item_by_room_id(const std::string &room_id) {
- if(remove_body_item_by_url(body->items, room_id)) {
- prev_invite_count = body->items.size();
- title = "Invites (" + std::to_string(body->items.size()) + ")";
+ const bool item_removed = body->erase_item([&room_id](std::shared_ptr<BodyItem> &body_item) {
+ return body_item->url == room_id;
+ });
+ if(item_removed) {
+ prev_invite_count = body->get_num_items();
+ title = "Invites (" + std::to_string(body->get_num_items()) + ")";
}
}
@@ -908,8 +902,7 @@ namespace QuickMedia {
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.push_back(std::move(body_item));
+ users_body->append_item(std::move(body_item));
}
void MatrixChatPage::add_user(MatrixEventUserInfo user_info) {
@@ -924,12 +917,9 @@ namespace QuickMedia {
return;
// TODO: Optimize
- 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;
- }
- }
+ users_body->erase_item([&user_info](std::shared_ptr<BodyItem> &it) {
+ return it->url == user_info.user_id;
+ });
}
void MatrixChatPage::set_user_info(MatrixEventUserInfo user_info) {
@@ -937,32 +927,25 @@ namespace QuickMedia {
return;
// TODO: Optimize
- 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(extract_first_line_remove_newline_elipses(display_name, AUTHOR_MAX_LENGTH));
-
- //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(it->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));
- }
+ auto user_body_item = users_body->find_item([&user_info](std::shared_ptr<BodyItem> &it) {
+ return it->url == user_info.user_id;
+ });
- return;
- }
+ if(!user_body_item)
+ return;
+
+ if(user_info.avatar_url)
+ user_body_item->thumbnail_url = user_info.avatar_url.value();
+
+ if(user_info.display_name) {
+ const 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();
+
+ user_body_item->set_author(extract_first_line_remove_newline_elipses(*display_name, AUTHOR_MAX_LENGTH));
+ users_body->apply_search_filter_for_item(user_body_item.get());
}
}
@@ -978,7 +961,7 @@ namespace QuickMedia {
}
size_t MatrixChatPage::get_num_users_in_current_room() const {
- return users_body ? users_body->items.size() : 0;
+ return users_body ? users_body->get_num_items() : 0;
}
void MatrixChatPage::set_room_as_read(RoomData *room) {
@@ -1095,19 +1078,20 @@ namespace QuickMedia {
//int prev_selected_item = notifications_body->get_selected_item();
//notifications_body->items.push_back(notification_to_body_item(notifications_body, notification));
//notifications_body->set_selected_item(prev_selected_item - 1);
- notifications_body->items.insert(notifications_body->items.begin(), notification_to_body_item(notifications_body, notification));
+ notifications_body->prepend_item(notification_to_body_item(notifications_body, notification));
notifications_body->select_next_item();
}
+ // TODO: Only loop unread items
void MatrixNotificationsPage::set_room_as_read(RoomData *room) {
- for(auto &body_item : notifications_body->items) {
+ notifications_body->for_each_item([room](std::shared_ptr<BodyItem> &body_item) {
NotificationsExtraData *extra_data = static_cast<NotificationsExtraData*>(body_item->extra.get());
if(!extra_data->read && extra_data->room == room) {
extra_data->read = true;
body_item->set_author_color(get_current_theme().text_color);
body_item->set_description_color(get_current_theme().text_color);
}
- }
+ });
}
SearchResult MatrixInviteUserPage::search(const std::string &str, BodyItems &result_items) {
@@ -3036,8 +3020,12 @@ namespace QuickMedia {
bool is_inside_code_block = false;
bool is_first_line = true;
string_split(body, '\n', [this, room, &formatted_body, &is_inside_code_block, &is_first_line](const char *str, size_t size){
- if(!is_first_line)
- formatted_body += "<br/>";
+ if(!is_first_line) {
+ if(is_inside_code_block)
+ formatted_body += '\n';
+ else
+ formatted_body += "<br/>";
+ }
std::string line_str(str, size);
html_escape_sequences(line_str);
diff --git a/src/plugins/NyaaSi.cpp b/src/plugins/NyaaSi.cpp
index ccf027d..8e55e62 100644
--- a/src/plugins/NyaaSi.cpp
+++ b/src/plugins/NyaaSi.cpp
@@ -134,12 +134,12 @@ namespace QuickMedia {
return body_item;
}
- static void sort_page_create_body_items(BodyItems &body_items, NyaaSiSortType sort_type) {
+ static void sort_page_create_body_items(Body *body, NyaaSiSortType sort_type) {
for(size_t i = 0; i < sort_type_names.size(); ++i) {
std::string prefix = " ";
if((NyaaSiSortType)i == sort_type)
prefix = "* ";
- body_items.push_back(create_sort_body_item(prefix + sort_type_names[i], (NyaaSiSortType)i));
+ body->append_item(create_sort_body_item(prefix + sort_type_names[i], (NyaaSiSortType)i));
}
}
@@ -294,12 +294,12 @@ namespace QuickMedia {
auto search_page = std::make_unique<NyaaSiSearchPage>(program, strip(title), url, std::move(domain));
NyaaSiSearchPage *search_page_p = search_page.get();
auto body = create_body();
- body->items = std::move(result_items);
+ body->set_items(std::move(result_items));
result_tabs.push_back(Tab{std::move(body), std::move(search_page), create_search_bar("Search...", 500)});
auto sort_order_page_body = create_body();
Body *sort_order_page_body_p = sort_order_page_body.get();
- sort_page_create_body_items(sort_order_page_body->items, NyaaSiSortType::UPLOAD_DATE_DESC);
+ sort_page_create_body_items(sort_order_page_body_p, NyaaSiSortType::UPLOAD_DATE_DESC);
result_tabs.push_back(Tab{std::move(sort_order_page_body), std::make_unique<NyaaSiSortOrderPage>(program, sort_order_page_body_p, search_page_p), nullptr});
return PluginResult::OK;
}
@@ -486,7 +486,7 @@ namespace QuickMedia {
return PluginResult::ERR;
auto body = create_body();
- body->items = std::move(result_items);
+ body->set_items(std::move(result_items));
result_tabs.push_back(Tab{std::move(body), std::make_unique<NyaaSiTorrentPage>(program), nullptr});
return PluginResult::OK;
}
@@ -499,8 +499,8 @@ namespace QuickMedia {
PluginResult NyaaSiSortOrderPage::submit(const std::string&, const std::string&, std::vector<Tab>&) {
const NyaaSiSortType sort_type = (NyaaSiSortType)(size_t)submit_body_item->userdata;
- body->items.clear();
- sort_page_create_body_items(body->items, sort_type);
+ body->clear_items();
+ sort_page_create_body_items(body, sort_type);
search_page->set_sort_type(sort_type);
search_page->needs_refresh = true;
return PluginResult::OK;
diff --git a/src/plugins/Soundcloud.cpp b/src/plugins/Soundcloud.cpp
index 7079e46..f20cf7d 100644
--- a/src/plugins/Soundcloud.cpp
+++ b/src/plugins/Soundcloud.cpp
@@ -247,7 +247,7 @@ namespace QuickMedia {
if(url == "track") {
SoundcloudPlaylist *playlist = static_cast<SoundcloudPlaylist*>(submit_body_item->extra.get());
auto body = create_body(false, true);
- body->items = playlist->tracks;
+ body->set_items(playlist->tracks);
result_tabs.push_back(Tab{std::move(body), std::make_unique<SoundcloudPlaylistPage>(program, playlist, title), nullptr});
} else if(url.find("/stream/users/") != std::string::npos) {
std::string query_url = url + "?client_id=" + client_id + "&limit=20&offset=0&linked_partitioning=1&app_version=1616689516&app_locale=en";
@@ -258,7 +258,9 @@ namespace QuickMedia {
auto body = create_body(false, true);
std::string next_href;
- PluginResult pr = parse_user_page(json_root, body->items, next_href);
+ BodyItems body_items;
+ PluginResult pr = parse_user_page(json_root, body_items, next_href);
+ body->set_items(std::move(body_items));
if(pr != PluginResult::OK) return pr;
result_tabs.push_back(Tab{std::move(body), std::make_unique<SoundcloudUserPage>(program, title, url, std::move(next_href)), nullptr});