aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2022-03-14 18:41:31 +0100
committerdec05eba <dec05eba@protonmail.com>2022-03-14 18:41:31 +0100
commitce00471fd84745dcbbcb9f2d9ef434acb3d0fd2b (patch)
treed79a9c3d04d8ae182ccf6697da9f4d9f9e18f54d /src
parent0b1f7936b0d52ad39016c9a7ad5320474034d500 (diff)
Image scroll view: add first/last image to allow scrolling to previous/next chapter, load next chapters page when reaching bottom
Diffstat (limited to 'src')
-rw-r--r--src/ImageViewer.cpp123
-rw-r--r--src/QuickMedia.cpp64
-rw-r--r--src/plugins/Youtube.cpp1
3 files changed, 128 insertions, 60 deletions
diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp
index 1176046..064afa4 100644
--- a/src/ImageViewer.cpp
+++ b/src/ImageViewer.cpp
@@ -4,6 +4,7 @@
#include "../include/ResourceLoader.hpp"
#include "../include/Scale.hpp"
#include "../include/Config.hpp"
+#include "../include/Theme.hpp"
#include <mglpp/system/FloatRect.hpp>
#include <malloc.h>
#include <mglpp/window/Event.hpp>
@@ -83,28 +84,49 @@ namespace QuickMedia {
}
bool ImageViewer::render_page(mgl::Window &window, int page, double offset_y) {
- if(page < 0 || page >= (int)image_data.size())
- return false;
-
- std::shared_ptr<ImageData> &page_image_data = image_data[page];
const mgl::vec2d image_size = get_page_size(page);
mgl::vec2d render_pos(floor(window_size.x * 0.5 - image_size.x * 0.5), scroll + offset_y);
- if(render_pos.y + image_size.y <= 0.0 || render_pos.y >= window_size.y) {
- if(page_image_data)
- page_image_data->visible_on_screen = false;
- return true;
- }
bool scrolling = (std::abs(scroll_speed) > 0.01f);
if(!scrolling)
render_pos.y = floor(render_pos.y);
double top_dist = std::abs(0.0 - render_pos.y);
- if(top_dist < min_page_top_dist) {
+ if(top_dist < min_page_top_dist && page != -1 && page != num_pages) {
min_page_top_dist = top_dist;
page_closest_to_top = page;
}
+ if(render_pos.y + image_size.y <= 0.0 || render_pos.y >= window_size.y) {
+ if(page >= 0 && page < num_pages) {
+ std::shared_ptr<ImageData> &page_image_data = image_data[page];
+ if(page_image_data)
+ page_image_data->visible_on_screen = false;
+ }
+ return true;
+ }
+
+ if(page == -1 || page == num_pages) {
+ // TODO: Dont show if first/last chapter
+ mgl::Text text(page == -1 ? "Scroll up to go to the previous chapter" : "Scroll down to go to the next chapter", *FontLoader::get_font(FontLoader::FontType::LATIN, 30 * get_config().scale * get_config().font_scale));
+ auto text_bounds = text.get_bounds();
+ text.set_color(get_theme().text_color);
+ mgl::vec2d render_pos_text(floor(window_size.x * 0.5 - text_bounds.size.x * 0.5), image_size.y * 0.5 - text_bounds.size.y * 0.5 + scroll + offset_y);
+
+ if(!scrolling)
+ render_pos_text.y = floor(render_pos_text.y);
+
+ mgl::Rectangle background(mgl::vec2f(image_size.x, image_size.y));
+ background.set_color(get_theme().selected_color);
+ background.set_position(mgl::vec2f(render_pos.x, render_pos.y));
+ window.draw(background);
+
+ text.set_position(mgl::vec2f(render_pos_text.x, render_pos_text.y));
+ window.draw(text);
+ return true;
+ }
+
+ std::shared_ptr<ImageData> &page_image_data = image_data[page];
if(page_image_data) {
page_image_data->visible_on_screen = true;
@@ -140,14 +162,14 @@ namespace QuickMedia {
mgl::Text error_message(std::move(msg), *FontLoader::get_font(FontLoader::FontType::LATIN, 30 * get_config().scale * get_config().font_scale));
auto text_bounds = error_message.get_bounds();
- error_message.set_color(mgl::Color(0, 0, 0, 255));
+ error_message.set_color(get_theme().text_color);
mgl::vec2d render_pos_text(floor(window_size.x * 0.5 - text_bounds.size.x * 0.5), image_size.y * 0.5 - text_bounds.size.y * 0.5 + scroll + offset_y);
if(!scrolling)
render_pos_text.y = floor(render_pos_text.y);
mgl::Rectangle background(mgl::vec2f(image_size.x, image_size.y));
- background.set_color(mgl::Color(255, 255, 255, 255));
+ background.set_color(get_theme().selected_color);
background.set_position(mgl::vec2f(render_pos.x, render_pos.y));
window.draw(background);
@@ -159,14 +181,14 @@ namespace QuickMedia {
mgl::Text error_message("Downloading page " + page_str, *FontLoader::get_font(FontLoader::FontType::LATIN, 30 * get_config().scale * get_config().font_scale));
auto text_bounds = error_message.get_bounds();
- error_message.set_color(mgl::Color(0, 0, 0, 255));
+ error_message.set_color(get_theme().text_color);
mgl::vec2d render_pos_text(floor(window_size.x * 0.5 - text_bounds.size.x * 0.5), image_size.y * 0.5 - text_bounds.size.y * 0.5 + scroll + offset_y);
if(!scrolling)
render_pos_text.y = floor(render_pos_text.y);
mgl::Rectangle background(mgl::vec2f(image_size.x, image_size.y));
- background.set_color(mgl::Color(255, 255, 255, 255));
+ background.set_color(get_theme().selected_color);
background.set_position(mgl::vec2f(render_pos.x, render_pos.y));
window.draw(background);
@@ -202,12 +224,30 @@ namespace QuickMedia {
return (!key.control && key.code == mgl::Keyboard::Down) || (!key.alt && key.control && key.code == mgl::Keyboard::J);
}
- static bool is_key_previous_chapter(const mgl::Event::KeyEvent &key) {
- return (key.control && key.code == mgl::Keyboard::Up) || (key.alt && key.control && key.code == mgl::Keyboard::K);
- }
+ void ImageViewer::scroll_to_page(int page) {
+ scroll = 0.0;
+ scroll_speed = 0.0;
- static bool is_key_next_chapter(const mgl::Event::KeyEvent &key) {
- return (key.control && key.code == mgl::Keyboard::Down) || (key.alt && key.control && key.code == mgl::Keyboard::J);
+ for(int i = -1; i < num_pages + 1; ++i) {
+ const mgl::vec2d current_page_size = get_page_size(i);
+ double scroll_diff = 0.0;
+ if(i < 0) {
+ scroll_diff = current_page_size.y - prev_size_first_page.y;
+ prev_size_first_page = current_page_size;
+ } else if(i >= num_pages) {
+ scroll_diff = current_page_size.y - prev_size_last_page.y;
+ prev_size_last_page = current_page_size;
+ } else {
+ scroll_diff = current_page_size.y - page_size[i].prev_size.y;
+ page_size[i].prev_size = current_page_size;
+ }
+
+ if(i < page) {
+ scroll -= scroll_diff;
+ if(scroll_diff < 0.001)
+ scroll -= current_page_size.y;
+ }
+ }
}
ImageViewerAction ImageViewer::draw() {
@@ -222,15 +262,7 @@ namespace QuickMedia {
window_size.x = window_size_i.x;
window_size.y = window_size_i.y;
window_size_set = true;
-
- for(int i = 0; i < num_pages; ++i) {
- const mgl::vec2d current_page_size = get_page_size(i);
- const double scroll_diff = current_page_size.y - page_size[i].prev_size.y;
- page_size[i].prev_size = current_page_size;
-
- if(i < current_page)
- scroll -= scroll_diff;
- }
+ scroll_to_page(current_page);
}
// TODO: Only redraw when scrolling and when image has finished downloading
@@ -250,18 +282,18 @@ namespace QuickMedia {
if(is_key_scroll_down(event.key))
down_pressed = true;
- if(is_key_previous_chapter(event.key))
- return ImageViewerAction::PREVIOUS_CHAPTER;
-
- if(is_key_next_chapter(event.key))
- return ImageViewerAction::NEXT_CHAPTER;
-
if(event.key.code == mgl::Keyboard::Escape)
return ImageViewerAction::RETURN;
if(event.key.code == mgl::Keyboard::I)
return ImageViewerAction::SWITCH_TO_SINGLE_IMAGE_MODE;
+ if(event.key.code == mgl::Keyboard::Home)
+ scroll_to_page(0);
+
+ if(event.key.code == mgl::Keyboard::End)
+ scroll_to_page(num_pages - 1);
+
if(event.key.code == mgl::Keyboard::F)
*fit_image_to_window = !*fit_image_to_window;
} else if(event.type == mgl::Event::KeyReleased) {
@@ -347,10 +379,19 @@ namespace QuickMedia {
}
double page_offset = 0.0;
- for(int i = 0; i < num_pages; ++i) {
+ for(int i = -1; i < num_pages + 1; ++i) {
const mgl::vec2d current_page_size = get_page_size(i);
- const double scroll_diff = current_page_size.y - page_size[i].prev_size.y;
- page_size[i].prev_size = current_page_size;
+ double scroll_diff = 0.0;
+ if(i < 0) {
+ scroll_diff = current_page_size.y - prev_size_first_page.y;
+ prev_size_first_page = current_page_size;
+ } else if(i >= num_pages) {
+ scroll_diff = current_page_size.y - prev_size_last_page.y;
+ prev_size_last_page = current_page_size;
+ } else {
+ scroll_diff = current_page_size.y - page_size[i].prev_size.y;
+ page_size[i].prev_size = current_page_size;
+ }
if(page_offset < -scroll)
scroll -= scroll_diff;
@@ -359,8 +400,8 @@ namespace QuickMedia {
page_offset += current_page_size.y;
}
- const double first_image_height = get_page_size(0).y;
- const double last_image_height = get_page_size((int)image_data.size() - 1).y;
+ const double first_image_height = get_page_size(-1).y;
+ const double last_image_height = get_page_size(image_data.size()).y;
// TODO: Do not allow scrolling if all images height (page_offset) is smaller than window height
@@ -368,8 +409,10 @@ namespace QuickMedia {
const double bottom_scroll = std::min(window_size.y, window_size.y + last_image_height - window_size.y);
if(scroll > top_scroll) {
scroll = top_scroll;
+ return ImageViewerAction::PREVIOUS_CHAPTER;
} else if(scroll + page_offset < bottom_scroll && page_offset > window_size.y) {
scroll = -page_offset + bottom_scroll;
+ return ImageViewerAction::NEXT_CHAPTER;
}
if(page_closest_to_top != -1)
@@ -410,7 +453,7 @@ namespace QuickMedia {
}
int ImageViewer::get_focused_page() const {
- return 1 + focused_page;
+ return std::max(0, std::min(1 + focused_page, num_pages));
}
mgl::vec2d ImageViewer::get_page_size(int page) {
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index e6e8e68..4bdf4d6 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -2210,18 +2210,50 @@ namespace QuickMedia {
page_navigation = image_continuous_page(manga_images_page);
}
- if(page_navigation == -1) {
+ if(page_navigation == -1) { // previous chapter
// TODO: Make this work if the list is sorted differently than from newest to oldest.
- chapters_body->select_next_item();
- select_episode(chapters_body->get_selected(), !continue_left_off);
- if(!continue_left_off)
- image_index = 99999; // Start at the page that shows we are at the end of the chapter
- manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url);
- } else if(page_navigation == 1) {
+
+ if(chapters_body->select_next_item()) {
+ select_episode(chapters_body->get_selected(), !continue_left_off);
+ if(!continue_left_off)
+ image_index = 99999; // Start at the page that shows we are at the end of the chapter
+ manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url);
+ } else if(!tab_associated_data[selected_tab].fetching_next_page_failed) {
+ BodyItems new_body_items;
+ const int fetch_page = tab_associated_data[selected_tab].fetched_page + 1;
+ TaskResult load_next_page_result = run_task_with_loading_screen([&] {
+ if(tabs[selected_tab].page->get_page("", fetch_page, new_body_items) != PluginResult::OK) {
+ fprintf(stderr, "Failed to get next page (page %d)\n", fetch_page);
+ return false;
+ }
+ return true;
+ });
+
+ 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) {
+ tabs[selected_tab].body->append_items(new_body_items);
+ tab_associated_data[selected_tab].fetched_page++;
+
+ select_episode(chapters_body->get_selected(), !continue_left_off);
+ if(!continue_left_off)
+ image_index = 99999; // Start at the page that shows we are at the end of the chapter
+ manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url);
+ } else {
+ tab_associated_data[selected_tab].fetching_next_page_failed = true;
+ }
+
+ if(load_next_page_result == TaskResult::CANCEL) {
+ current_page = pop_page_stack();
+ break;
+ }
+ }
+ } else if(page_navigation == 1) { // next chapter
// TODO: Make this work if the list is sorted differently than from newest to oldest.
- chapters_body->select_previous_item();
- select_episode(chapters_body->get_selected(), !continue_left_off);
- manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url);
+ if(chapters_body->select_previous_item()) {
+ select_episode(chapters_body->get_selected(), !continue_left_off);
+ manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url);
+ }
}
}
}
@@ -3118,7 +3150,6 @@ namespace QuickMedia {
std::string audio_url;
bool has_embedded_audio = true;
- std::string prev_start_time;
std::vector<MediaChapter> media_chapters;
auto load_video_error_check = [&](std::string start_time = "", bool reuse_media_source = false) mutable {
@@ -3219,7 +3250,6 @@ namespace QuickMedia {
const bool is_resume_go_back = !start_time.empty();
if(start_time.empty())
start_time = video_page->get_url_timestamp();
- prev_start_time = start_time;
watched_videos.insert(video_page->get_url());
// TODO: Sync sequences
@@ -4081,12 +4111,6 @@ namespace QuickMedia {
image_index = num_manga_pages;
goto end_of_images_page;
}
- } else if((event.key.control && event.key.code == mgl::Keyboard::Up) || (event.key.alt && event.key.control && event.key.code == mgl::Keyboard::K)) {
- page_navigation = -1;
- goto end_of_images_page;
- } else if((event.key.control && event.key.code == mgl::Keyboard::Down) || (event.key.alt && event.key.control && event.key.code == mgl::Keyboard::J)) {
- page_navigation = 1;
- goto end_of_images_page;
} else if(event.key.code == mgl::Keyboard::Escape) {
current_page = pop_page_stack();
} else if(event.key.code == mgl::Keyboard::I) {
@@ -4200,7 +4224,7 @@ namespace QuickMedia {
Json::Value json_chapter;
int current_read_page;
save_manga_progress(images_page, json_chapters, json_chapter, current_read_page);
- ImageViewer image_viewer(&window, num_manga_pages, images_page->manga_name, images_page->get_chapter_name(), image_index, content_cache_dir, &fit_image_to_window);
+ ImageViewer image_viewer(&window, num_manga_pages, images_page->manga_name, images_page->get_chapter_name(), std::min(num_manga_pages - 1, image_index), content_cache_dir, &fit_image_to_window);
idle_active_handler();
@@ -4234,7 +4258,7 @@ namespace QuickMedia {
image_index = focused_page - 1;
if(focused_page != current_read_page) {
current_read_page = focused_page;
- json_chapter["current"] = current_read_page;
+ json_chapter["current"] = std::max(0, std::min(current_read_page, num_manga_pages));
json_chapters[images_page->get_chapter_name()] = json_chapter;
content_storage_json["chapters"] = json_chapters;
if(!save_json_to_file_atomic(content_storage_file, content_storage_json)) {
diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp
index b3150a3..bbf3108 100644
--- a/src/plugins/Youtube.cpp
+++ b/src/plugins/Youtube.cpp
@@ -1869,6 +1869,7 @@ namespace QuickMedia {
return "";
}
+ // TODO: Remove very old videos, to not make this file too large which slows this down on slow harddrives
std::unordered_map<std::string, WatchProgress> watch_progress = get_watch_progress_for_plugin("youtube");
auto it = watch_progress.find(video_id);
if(it == watch_progress.end())