#pragma once #include "Body.hpp" #include "SearchBar.hpp" #include "Page.hpp" #include "Storage.hpp" #include "Tab.hpp" #include "MessageQueue.hpp" #include #include #include #include #include #include #include #include #include #include #include "../plugins/Plugin.hpp" #include #include namespace QuickMedia { class Matrix; class FileManager; class MangaImagesPage; class ImageBoardThreadPage; class RoomData; class MatrixChatPage; class VideoPage; enum class ImageViewMode { SINGLE, SCROLL }; struct CopyOp { Path source; Path destination; }; enum class TaskResult { TRUE, FALSE, CANCEL }; enum class FetchType { SEARCH, LAZY }; struct FetchResult { BodyItems body_items; PluginResult result; }; struct TabAssociatedData { std::string update_search_text; bool search_text_updated = false; FetchStatus fetch_status = FetchStatus::NONE; bool lazy_fetch_finished = false; FetchType fetch_type; bool typing = false; bool fetching_next_page_running = false; int fetched_page = 0; sf::Text search_result_text; std::future fetch_future; std::future next_page_future; }; class Program { public: Program(); ~Program(); int run(int argc, char **argv); bool is_tor_enabled(); std::unique_ptr create_body(); std::unique_ptr create_search_bar(const std::string &placeholder, int search_delay); bool load_manga_content_storage(const char *service_name, const std::string &manga_title, const std::string &manga_id); void select_file(const std::string &filepath); bool is_window_focused(); RoomData* get_current_chat_room(); void set_go_to_previous_page(); TaskResult run_task_with_loading_screen(std::function callback); const char* get_plugin_name() const; void manga_get_watch_history(const char *plugin_name, BodyItems &history_items); void youtube_get_watch_history(BodyItems &history_items); private: void base_event_handler(sf::Event &event, PageType previous_page, Body *body, SearchBar *search_bar, bool handle_key_press = true, bool handle_searchbar = true); void event_idle_handler(const sf::Event &event); void idle_active_handler(); void update_idle_state(); void page_loop_render(sf::RenderWindow &window, std::vector &tabs, int selected_tab, TabAssociatedData &tab_associated_data, const Json::Value *json_chapters); using PageLoopSubmitHandler = std::function &new_tabs)>; void page_loop(std::vector &tabs, int start_tab_index = 0, PageLoopSubmitHandler after_submit_handler = nullptr); void video_content_page(VideoPage *video_page, std::string video_title, bool download_if_streaming_fails); // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter int image_page(MangaImagesPage *images_page, Body *chapters_body); void image_continuous_page(MangaImagesPage *images_page); void image_board_thread_page(ImageBoardThreadPage *thread_page, Body *thread_body); void chat_login_page(); bool chat_page(MatrixChatPage *matrix_chat_page, RoomData *current_room, std::vector &room_tabs, int room_selected_tab, TabAssociatedData &room_tab_associated_data); void after_matrix_login_page(); enum class LoadImageResult { OK, FAILED, DOWNLOAD_IN_PROGRESS }; LoadImageResult load_image_by_index(int image_index, sf::Texture &image_texture, sf::String &error_message); void download_chapter_images_if_needed(MangaImagesPage *images_page); void select_episode(BodyItem *item, bool start_from_beginning); // Returns PageType::EXIT if empty PageType pop_page_stack(); Json::Value load_video_history_json(); Json::Value load_recommended_json(); void save_recommendations_from_related_videos(const std::string &video_url, const std::string &video_title, const BodyItems &related_media_body_items); private: enum class UpscaleImageAction { NO, LOW_RESOLUTION, FORCE }; Display *disp; sf::RenderWindow window; Matrix *matrix = nullptr; bool is_login_sync = false; int monitor_hz; sf::Vector2f window_size; const char *plugin_name = nullptr; sf::Texture plugin_logo; sf::Texture loading_icon; sf::Sprite load_sprite; sf::Clock load_sprite_timer; PageType current_page; std::stack page_stack; int image_index; Path content_storage_file; Path content_cache_dir; std::string manga_id_base64; Json::Value content_storage_json; std::unordered_set watched_videos; std::future search_suggestion_future; std::future autocomplete_future; std::future image_download_future; std::thread image_upscale_thead; MessageQueue images_to_upscale_queue; std::vector image_upscale_status; std::string downloading_chapter_url; bool image_download_cancel = false; int exit_code = 0; std::string resources_root; sf::Shader circle_mask_shader; bool use_tor = false; bool no_video = false; bool use_system_mpv_config = false; UpscaleImageAction upscale_image_action = UpscaleImageAction::NO; // TODO: Save this to config file when switching modes ImageViewMode image_view_mode = ImageViewMode::SINGLE; std::vector selected_files; bool fit_image_to_window = false; RoomData *current_chat_room = nullptr; bool go_to_previous_page = false; sf::RoundedRectangleShape tab_background; sf::RectangleShape tab_shade; sf::Text tab_text; sf::Vertex gradient_points[4]; sf::Vector2f body_pos; sf::Vector2f body_size; bool show_room_side_panel = true; std::thread::id main_thread_id; sf::Clock idle_timer; bool idle = true; bool low_cpu_mode = false; }; }