From a8e0846a7c111a8d5b5cf8592ecb9b9bbd15ce26 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 22 Sep 2020 22:46:29 +0200 Subject: Initial file manager implementation, with thumbnail caching --- src/QuickMedia.cpp | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 4 deletions(-) (limited to 'src/QuickMedia.cpp') diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index f57b674..e7a310d 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -8,6 +8,7 @@ #include "../plugins/Dmenu.hpp" #include "../plugins/NyaaSi.hpp" #include "../plugins/Matrix.hpp" +#include "../plugins/FileManager.hpp" #include "../include/Scale.hpp" #include "../include/Program.h" #include "../include/VideoPlayer.hpp" @@ -198,6 +199,10 @@ namespace QuickMedia { window.setFramerateLimit(monitor_hz); } fprintf(stderr, "Monitor hz: %d\n", monitor_hz); + + if(create_directory_recursive(get_cache_dir().join("thumbnails")) != 0) { + fprintf(stderr, "Failed to create thumbnails directory\n"); + } } Program::~Program() { @@ -236,12 +241,13 @@ namespace QuickMedia { } static void usage() { - fprintf(stderr, "usage: QuickMedia [--tor] [--use-system-mpv-config] [-p placeholder-text]\n"); + fprintf(stderr, "usage: QuickMedia [--tor] [--use-system-mpv-config] [--dir ] [-p ]\n"); fprintf(stderr, "OPTIONS:\n"); - fprintf(stderr, " plugin The plugin to use. Should be either 4chan, manganelo, mangatown, mangadex, pornhub, youtube, nyaa.si or dmenu\n"); + fprintf(stderr, " plugin The plugin to use. Should be either 4chan, manganelo, mangatown, mangadex, pornhub, youtube, nyaa.si, matrix, file-manager or dmenu\n"); fprintf(stderr, " --tor Use tor. Disabled by default\n"); fprintf(stderr, " --use-system-mpv-config Use system mpv config instead of no config. Disabled by default\n"); fprintf(stderr, " --upscale-images Upscale low-resolution manga pages using waifu2x-ncnn-vulkan. Disabled by default\n"); + fprintf(stderr, " --dir Set the start directory when using file-manager\n"); fprintf(stderr, " -p Change the placeholder text for dmenu\n"); fprintf(stderr, "EXAMPLES:\n"); fprintf(stderr, "QuickMedia manganelo\n"); @@ -277,6 +283,7 @@ namespace QuickMedia { current_plugin = nullptr; std::string plugin_logo_path; std::string search_placeholder; + const char *start_dir = nullptr; for(int i = 1; i < argc; ++i) { if(!current_plugin) { @@ -301,11 +308,13 @@ namespace QuickMedia { } else if(strcmp(argv[i], "nyaa.si") == 0) { current_plugin = new NyaaSi(); plugin_logo_path = resources_root + "images/nyaa_si_logo.png"; - } else if(strcmp(argv[i], "dmenu") == 0) { - current_plugin = new Dmenu(); } else if(strcmp(argv[i], "matrix") == 0) { current_plugin = new Matrix(); plugin_logo_path = resources_root + "images/matrix_logo.png"; + } else if(strcmp(argv[i], "file-manager") == 0) { + current_plugin = new FileManager(); + } else if(strcmp(argv[i], "dmenu") == 0) { + current_plugin = new Dmenu(); } else { fprintf(stderr, "Invalid plugin %s\n", argv[i]); usage(); @@ -319,6 +328,11 @@ namespace QuickMedia { use_system_mpv_config = true; } else if(strcmp(argv[i], "--upscale-images") == 0) { upscale_images = true; + } else if(strcmp(argv[i], "--dir") == 0) { + if(i < argc - 1) { + start_dir = argv[i + 1]; + ++i; + } } else if(strcmp(argv[i], "-p") == 0) { if(i < argc - 1) { search_placeholder = argv[i + 1]; @@ -331,12 +345,35 @@ namespace QuickMedia { } } + if(!current_plugin) { + fprintf(stderr, "Missing plugin argument\n"); + usage(); + return -1; + } + if(!search_placeholder.empty() && current_plugin->name == "dmenu") { fprintf(stderr, "Option -p is only valid with dmenu\n"); usage(); return -1; } + if(current_plugin->name == "file-manager") { + current_page = Page::FILE_MANAGER; + } else { + if(start_dir) { + fprintf(stderr, "Option --dir is only valid with file-manager\n"); + usage(); + return -1; + } + } + + if(start_dir) { + if(!static_cast(current_plugin)->set_current_directory(start_dir)) { + fprintf(stderr, "Invalid directory provided with --dir: %s\n", start_dir); + return -3; + } + } + if(use_tor && !is_program_executable_by_name("torsocks")) { fprintf(stderr, "torsocks needs to be installed (and accessible from PATH environment variable) when using the --tor option\n"); return -2; @@ -492,6 +529,11 @@ namespace QuickMedia { chat_page(); break; } + case Page::FILE_MANAGER: { + body->draw_thumbnails = true; + file_manager_page(); + break; + } } } @@ -2444,6 +2486,91 @@ namespace QuickMedia { } } + void Program::file_manager_page() { + selected_files.clear(); + int prev_autosearch_delay = search_bar->text_autosearch_delay; + search_bar->text_autosearch_delay = current_plugin->get_search_delay(); + Page previous_page = pop_page_stack(); + + assert(current_plugin->name == "file-manager"); + FileManager *file_manager = static_cast(current_plugin); + + sf::Text current_dir_text(file_manager->get_current_dir().string(), bold_font, 18); + + // TODO: Make asynchronous. + // TODO: Automatically go to the parent if this fails (recursively). + if(file_manager->get_files_in_directory(body->items) != PluginResult::OK) { + show_notification("QuickMedia", "File manager failed to get files in directory: " + file_manager->get_current_dir().string(), Urgency::CRITICAL); + } + + // TODO: Have an option for the search bar to be multi-line. + search_bar->onTextUpdateCallback = [this](const sf::String &text) { + body->filter_search_fuzzy(text); + body->reset_selected(); + }; + + search_bar->onTextSubmitCallback = [this, previous_page, ¤t_dir_text](const std::string&) -> bool { + BodyItem *selected_item = body->get_selected(); + if(!selected_item) + return false; + + FileManager *file_manager = static_cast(current_plugin); + if(file_manager->set_child_directory(selected_item->get_title())) { + std::string current_dir_str = file_manager->get_current_dir().string(); + current_dir_text.setString(current_dir_str); + // TODO: Make asynchronous. + // TODO: Automatically go to the parent if this fails (recursively). + body->items.clear(); + if(file_manager->get_files_in_directory(body->items) != PluginResult::OK) { + show_notification("QuickMedia", "File manager failed to get files in directory: " + current_dir_str, Urgency::CRITICAL); + } + body->reset_selected(); + return true; + } else { + std::filesystem::path full_path = file_manager->get_current_dir() / selected_item->get_title(); + selected_files.push_back(full_path.string()); + printf("%s\n", selected_files.back().c_str()); + current_page = previous_page; + return false; + } + }; + + sf::Vector2f body_pos; + sf::Vector2f body_size; + bool redraw = true; + sf::Event event; + + while (current_page == Page::FILE_MANAGER) { + while (window.pollEvent(event)) { + base_event_handler(event, previous_page); + if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus) + redraw = true; + } + + if(redraw) { + redraw = false; + search_bar->onWindowResize(window_size); + get_body_dimensions(window_size, search_bar.get(), body_pos, body_size); + const float dir_text_height = std::floor(current_dir_text.getLocalBounds().height + 12.0f); + body_pos.y += dir_text_height; + body_size.y -= dir_text_height; + current_dir_text.setPosition(body_pos.x, body_pos.y - dir_text_height); + } + + search_bar->update(); + window.clear(back_color); + body->draw(window, body_pos, body_size); + window.draw(current_dir_text); + search_bar->draw(window); + window.display(); + } + + search_bar->text_autosearch_delay = prev_autosearch_delay; + // We want exit code 1 if the file manager was launched and no files were selected, to know when the user didn't select any file(s) + if(selected_files.empty() && current_page == Page::EXIT) + exit(1); + } + void Program::image_board_thread_list_page() { assert(current_plugin->is_image_board()); ImageBoard *image_board = static_cast(current_plugin); -- cgit v1.2.3