From ce00471fd84745dcbbcb9f2d9ef434acb3d0fd2b Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 14 Mar 2022 18:41:31 +0100 Subject: Image scroll view: add first/last image to allow scrolling to previous/next chapter, load next chapters page when reaching bottom --- src/ImageViewer.cpp | 123 ++++++++++++++++++++++++++++++++---------------- src/QuickMedia.cpp | 64 +++++++++++++++++-------- src/plugins/Youtube.cpp | 1 + 3 files changed, 128 insertions(+), 60 deletions(-) (limited to 'src') 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 #include #include @@ -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 &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 &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 &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 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 watch_progress = get_watch_progress_for_plugin("youtube"); auto it = watch_progress.find(video_id); if(it == watch_progress.end()) -- cgit v1.2.3