diff options
author | dec05eba <dec05eba@protonmail.com> | 2020-10-30 16:47:40 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-10-30 18:30:46 +0100 |
commit | 928f2525c29929de0c2ab520f48c82b5cb882aa7 (patch) | |
tree | e97130909f65e7835e4740824e9f38f58e4c0fbe | |
parent | e422322650f9cb057937182987071438f9c79e84 (diff) |
Matrix: re-add /logout, cancel task immediately
Cancel video download when pressing escape,
other fixes..
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | TODO | 7 | ||||
-rw-r--r-- | images/matrix_logo.png | bin | 1199 -> 6323 bytes | |||
-rw-r--r-- | include/AsyncTask.hpp | 9 | ||||
-rw-r--r-- | include/Body.hpp | 3 | ||||
-rw-r--r-- | include/Program.hpp (renamed from include/Program.h) | 16 | ||||
-rw-r--r-- | include/QuickMedia.hpp | 1 | ||||
-rw-r--r-- | plugins/Manga.hpp | 2 | ||||
-rw-r--r-- | plugins/Page.hpp | 2 | ||||
-rw-r--r-- | src/Body.cpp | 10 | ||||
-rw-r--r-- | src/DownloadUtils.cpp | 3 | ||||
-rw-r--r-- | src/FileAnalyzer.cpp | 2 | ||||
-rw-r--r-- | src/Notification.cpp | 2 | ||||
-rw-r--r-- | src/Program.cpp (renamed from src/Program.c) | 47 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 222 | ||||
-rw-r--r-- | src/VideoPlayer.cpp | 2 | ||||
-rw-r--r-- | src/plugins/Manga.cpp | 5 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 11 | ||||
-rw-r--r-- | src/plugins/NyaaSi.cpp | 2 |
19 files changed, 222 insertions, 125 deletions
@@ -51,6 +51,7 @@ Press `M` to begin writing a message in a matrix room, press `ESC` to cancel.\ Press `R` to reply to a message on matrix, press `ESC` to cancel.\ Press `E` to edit a message on matrix, press `ESC` to cancel. Currently only works for your own messages.\ Press `D` to delete a message on matrix. Currently deleting a message only deletes the event, so if you delete an edit then the original message wont be deleted.\ +Press `Ctrl + C` to copy the message of the selected item in matrix to the clipboard.\ Press `Ctrl + V` to upload media to room in matrix if the clipboard contains a valid absolute filepath. In matrix you can select a message with enter to open the url in the message (or if there are multiple urls then a menu will appear for selecting which to open). @@ -55,7 +55,7 @@ Scroll to bottom when receiving a new message even if the selected message is no Also add a tab for common directories and recently accessed files/directories (the directories would be the directory of used files). Provide a way to go to the first unread message in matrix and also show a marker in the body (maybe a red line?) where the first unread message is. Allow scrolling body item. A body item can be long and we wont be able to read all of it otherwise (such as a message on matrix). Pressing up/down should scroll such a large body item rather than moving to another one. -Cleanup keybindings. Some require ctrl, some dont (4chan vs matrix for example). +Cleanup keybindings. Some require ctrl, some dont. Add room topic beside room name in matrix (in messages tab). Move rooms in matrix to previous page instead, then messages can be beside users, pinned messages, settings, etc and they would all be connected to that one room, then beside rooms tab there would be a global settings tab. Add /me to matrix, emoji, reactions... @@ -123,4 +123,7 @@ Replying to edited message shows incorrect body in matrix. Show in room tags list when there is a message in any of the rooms in the tag. Apply current search filter when adding new rooms to the room list. Cancel video download when pressing escape or closing window (important in matrix). -Support webp.
\ No newline at end of file +Support webp. +Reload history/recommendations after closing a video. +Show images while they download by showing them as scanlines starting from the top. Needed for slow websites such as 4chan. +Use curl parallel download instead of downloading with multiple threads.
\ No newline at end of file diff --git a/images/matrix_logo.png b/images/matrix_logo.png Binary files differindex 055a9c7..29a2ee3 100644 --- a/images/matrix_logo.png +++ b/images/matrix_logo.png diff --git a/include/AsyncTask.hpp b/include/AsyncTask.hpp new file mode 100644 index 0000000..81be1ee --- /dev/null +++ b/include/AsyncTask.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include <functional> +#include <deque> +#include <mutex> + +namespace QuickMedia { + +}
\ No newline at end of file diff --git a/include/Body.hpp b/include/Body.hpp index 9cdcd7b..1dc1fe8 100644 --- a/include/Body.hpp +++ b/include/Body.hpp @@ -147,14 +147,13 @@ namespace QuickMedia { // Select next item, ignoring invisible items. Returns true if the item was changed. This can be used to check if the bottom was hit when wrap_around is set to false bool select_next_item(); - void set_selected_item(int item); + void set_selected_item(int item, bool reset_prev_selected_item = true); // Returns -1 if item can't be found int get_index_by_body_item(BodyItem *body_item); void select_first_item(); void select_last_item(); - void reset_selected(); void clear_items(); void prepend_items(BodyItems new_items); void append_items(BodyItems new_items); diff --git a/include/Program.h b/include/Program.hpp index cab8d26..8ac2d2d 100644 --- a/include/Program.h +++ b/include/Program.hpp @@ -1,11 +1,8 @@ -#ifndef QUICKMEDIA_PROGRAM_H -#define QUICKMEDIA_PROGRAM_H +#ifndef QUICKMEDIA_PROGRAM_HPP +#define QUICKMEDIA_PROGRAM_HPP #include <sys/types.h> - -#ifdef __cplusplus -extern "C" { -#endif +#include <thread> typedef struct { pid_t pid; @@ -41,8 +38,7 @@ int wait_program_non_blocking(pid_t process_id, int *status); */ int exec_program_async(const char **args, pid_t *result_process_id); -#ifdef __cplusplus -} -#endif +void program_clear_current_thread(); +void program_kill_in_thread(const std::thread::id &thread_id); -#endif +#endif /* QUICKMEDIA_PROGRAM_HPP */ diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp index 99bab7a..6f8e3ff 100644 --- a/include/QuickMedia.hpp +++ b/include/QuickMedia.hpp @@ -63,6 +63,7 @@ namespace QuickMedia { void image_board_thread_page(ImageBoardThreadPage *thread_page, Body *thread_body); void chat_login_page(); void chat_page(MatrixChatPage *chat_page, RoomData *current_room); + void after_matrix_login_page(); enum class LoadImageResult { OK, diff --git a/plugins/Manga.hpp b/plugins/Manga.hpp index d3725da..afd8a3c 100644 --- a/plugins/Manga.hpp +++ b/plugins/Manga.hpp @@ -53,7 +53,7 @@ namespace QuickMedia { public: MangaChaptersPage(Program *program, std::string manga_name, std::string manga_url) : TrackablePage(program, std::move(manga_name), std::move(manga_url)) {} TrackResult track(const std::string &str) override; - void on_navigate_to_page() override; + void on_navigate_to_page(BodyItems &body_items) override; protected: virtual bool extract_id_from_url(const std::string &url, std::string &manga_id) const = 0; virtual const char* get_service_name() const = 0; diff --git a/plugins/Page.hpp b/plugins/Page.hpp index cc7dad6..db844c5 100644 --- a/plugins/Page.hpp +++ b/plugins/Page.hpp @@ -45,7 +45,7 @@ namespace QuickMedia { virtual bool is_lazy_fetch_page() const { return false; } // This is called both when first navigating to page and when going back to page - virtual void on_navigate_to_page() {}; + virtual void on_navigate_to_page(BodyItems &body_items) { (void)body_items; } // Called periodically (every frame right now) if this page is the currently active one virtual void update() {} diff --git a/src/Body.cpp b/src/Body.cpp index 7f96263..3f5c755 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -186,10 +186,11 @@ namespace QuickMedia { return true; } - void Body::set_selected_item(int item) { + void Body::set_selected_item(int item, bool reset_prev_selected_item) { //assert(item >= 0 && item < (int)items.size()); selected_item = item; - prev_selected_item = selected_item; + if(reset_prev_selected_item) + prev_selected_item = selected_item; clamp_selection(); //page_scroll = 0.0f; } @@ -216,10 +217,6 @@ namespace QuickMedia { clamp_selection(); } - void Body::reset_selected() { - select_first_item(); - } - void Body::clear_items() { items.clear(); selected_item = 0; @@ -235,6 +232,7 @@ namespace QuickMedia { items.insert(items.end(), std::make_move_iterator(new_items.begin()), std::make_move_iterator(new_items.end())); } + // TODO: Binary search and use hint to start search from start or end (for example when adding "previous" items or "next" items) void Body::insert_item_by_timestamp(std::shared_ptr<BodyItem> body_item) { for(size_t i = 0; i < items.size(); ++i) { if(body_item->get_timestamp() < items[i]->get_timestamp()) { diff --git a/src/DownloadUtils.cpp b/src/DownloadUtils.cpp index fd7e7d1..cbdded6 100644 --- a/src/DownloadUtils.cpp +++ b/src/DownloadUtils.cpp @@ -1,5 +1,5 @@ #include "../include/DownloadUtils.hpp" -#include "../include/Program.h" +#include "../include/Program.hpp" #include "../include/Storage.hpp" #include "../include/base64_url.hpp" #include <SFML/System/Clock.hpp> @@ -141,6 +141,7 @@ namespace QuickMedia { char read_buffer[8192]; rapidjson::FileReadStream is(file, read_buffer, sizeof(read_buffer)); rapidjson::ParseResult parse_result = result.ParseStream(is); + program_clear_current_thread(); fclose(file); wait_program(read_program.pid); diff --git a/src/FileAnalyzer.cpp b/src/FileAnalyzer.cpp index 82d2c06..8d5eae8 100644 --- a/src/FileAnalyzer.cpp +++ b/src/FileAnalyzer.cpp @@ -1,5 +1,5 @@ #include "../include/FileAnalyzer.hpp" -#include "../include/Program.h" +#include "../include/Program.hpp" #include <sys/stat.h> #include <stdio.h> #include <array> diff --git a/src/Notification.cpp b/src/Notification.cpp index 1201557..9ffbaac 100644 --- a/src/Notification.cpp +++ b/src/Notification.cpp @@ -1,5 +1,5 @@ #include "../include/Notification.hpp" -#include "../include/Program.h" +#include "../include/Program.hpp" #include <assert.h> #include <stdio.h> diff --git a/src/Program.c b/src/Program.cpp index a82bcd2..136a494 100644 --- a/src/Program.c +++ b/src/Program.cpp @@ -1,4 +1,4 @@ -#include "../include/Program.h" +#include "../include/Program.hpp" #include <unistd.h> #include <sys/wait.h> #include <sys/prctl.h> @@ -7,10 +7,40 @@ #include <stdio.h> #include <stdlib.h> #include <assert.h> +#include <unordered_map> +#include <mutex> +#include <signal.h> #define READ_END 0 #define WRITE_END 1 +class CurrentThreadProgram { +public: + void set(ReadProgram read_program) { + std::lock_guard<std::mutex> lock(mutex); + thread_current_program[std::this_thread::get_id()] = read_program; + } + + void clear() { + std::lock_guard<std::mutex> lock(mutex); + thread_current_program.erase(std::this_thread::get_id()); + } + + void kill_in_thread(const std::thread::id &thread_id) { + std::lock_guard<std::mutex> lock(mutex); + auto it = thread_current_program.find(thread_id); + if(it != thread_current_program.end()) { + close(it->second.read_fd); + kill(it->second.pid, SIGTERM); + } + } +private: + std::unordered_map<std::thread::id, ReadProgram> thread_current_program; + std::mutex mutex; +}; + +static CurrentThreadProgram current_thread_program; + int exec_program_pipe(const char **args, ReadProgram *read_program) { /* 1 arguments */ if(args[0] == NULL) @@ -51,6 +81,7 @@ int exec_program_pipe(const char **args, ReadProgram *read_program) { close(fd[WRITE_END]); read_program->pid = pid; read_program->read_fd = fd[READ_END]; + current_thread_program.set(*read_program); return 0; } } @@ -63,6 +94,7 @@ int exec_program(const char **args, ProgramOutputCallback output_callback, void int result = 0; int status; + int exit_status; char buffer[4097]; @@ -77,6 +109,8 @@ int exec_program(const char **args, ProgramOutputCallback output_callback, void break; } + //check if running. Also do the same in download_to_json + buffer[bytes_read] = '\0'; if(output_callback) { result = output_callback(buffer, bytes_read, userdata); @@ -84,6 +118,7 @@ int exec_program(const char **args, ProgramOutputCallback output_callback, void break; } } + program_clear_current_thread(); if(result != 0) kill(read_program.pid, SIGTERM); @@ -99,7 +134,7 @@ int exec_program(const char **args, ProgramOutputCallback output_callback, void goto cleanup; } - int exit_status = WEXITSTATUS(status); + exit_status = WEXITSTATUS(status); if(exit_status != 0) { fprintf(stderr, "Failed to execute program ("); const char **arg = args; @@ -201,3 +236,11 @@ int exec_program_async(const char **args, pid_t *result_process_id) { } return 0; } + +void program_clear_current_thread() { + current_thread_program.clear(); +} + +void program_kill_in_thread(const std::thread::id &thread_id) { + current_thread_program.kill_in_thread(thread_id); +} diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index ba9a680..3b99d55 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -9,7 +9,7 @@ #include "../plugins/Matrix.hpp" #include "../plugins/FileManager.hpp" #include "../include/Scale.hpp" -#include "../include/Program.h" +#include "../include/Program.hpp" #include "../include/VideoPlayer.hpp" #include "../include/StringUtils.hpp" #include "../include/GoogleCaptcha.hpp" @@ -641,51 +641,7 @@ namespace QuickMedia { chat_login_page(); } - if(!window.isOpen()) - return exit_code; - - auto rooms_body = create_body(); - rooms_body->thumbnail_mask_shader = &circle_mask_shader; - auto matrix_rooms_page = std::make_unique<MatrixRoomsPage>(this, rooms_body.get(), "All rooms"); - - auto rooms_tags_body = create_body(); - rooms_tags_body->thumbnail_mask_shader = &circle_mask_shader; - auto matrix_rooms_tag_page = std::make_unique<MatrixRoomTagsPage>(this, rooms_tags_body.get()); - - MatrixQuickMedia matrix_handler(this, matrix, matrix_rooms_page.get(), matrix_rooms_tag_page.get()); - matrix->start_sync(&matrix_handler); - - tabs.push_back(Tab{std::move(rooms_body), std::move(matrix_rooms_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); - tabs.push_back(Tab{std::move(rooms_tags_body), std::move(matrix_rooms_tag_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); - - sf::Sprite load_sprite(loading_icon); - sf::Vector2u loading_icon_size = loading_icon.getSize(); - load_sprite.setOrigin(loading_icon_size.x * 0.5f, loading_icon_size.y * 0.5f); - - sf::Clock timer; - sf::Event event; - while(window.isOpen() && !matrix->is_initial_sync_finished()) { - while(window.pollEvent(event)) { - if(event.type == sf::Event::Closed) - window.close(); - else if(event.type == sf::Event::Resized) { - window_size.x = event.size.width; - window_size.y = event.size.height; - sf::FloatRect visible_area(0, 0, window_size.x, window_size.y); - window.setView(sf::View(visible_area)); - } - } - window.clear(back_color); - load_sprite.setPosition(window_size.x * 0.5f, window_size.y * 0.5f); - load_sprite.setRotation(timer.getElapsedTime().asSeconds() * 400.0); - window.draw(load_sprite); - window.display(); - } - - while(window.isOpen()) { - page_loop(tabs); - } - + after_matrix_login_page(); exit(exit_code); // Exit immediately without waiting for anything to finish //matrix->stop_sync(); } @@ -975,6 +931,16 @@ namespace QuickMedia { return current_chat_room; } + static void select_body_item_by_room(Body *body, RoomData *room) { + for(size_t i = 0; i < body->items.size(); ++i) { + auto &body_item = body->items[i]; + if(body_item->userdata == room) { + body->set_selected_item(i, false); + return; + } + } + } + void Program::page_loop(std::vector<Tab> &tabs) { if(tabs.empty()) { show_notification("QuickMedia", "No tabs provided!", Urgency::CRITICAL); @@ -983,7 +949,7 @@ namespace QuickMedia { for(Tab &tab : tabs) { tab.body->thumbnail_max_size = tab.page->get_thumbnail_max_size(); - tab.page->on_navigate_to_page(); + tab.page->on_navigate_to_page(tab.body->items); } const Json::Value *json_chapters = &Json::Value::nullSingleton(); @@ -1106,11 +1072,12 @@ namespace QuickMedia { current_page = PageType::CHAT; current_chat_room = matrix->get_room_by_id(selected_item->url); chat_page(static_cast<MatrixChatPage*>(new_tabs[0].page.get()), current_chat_room); + select_body_item_by_room(tabs[selected_tab].body.get(), current_chat_room); current_chat_room = nullptr; } else { page_loop(new_tabs); } - tabs[selected_tab].page->on_navigate_to_page(); + tabs[selected_tab].page->on_navigate_to_page(tabs[selected_tab].body->items); if(content_storage_json.isObject()) { const Json::Value &chapters_json = content_storage_json["chapters"]; if(chapters_json.isObject()) @@ -1614,9 +1581,11 @@ namespace QuickMedia { video_url = std::move(video_path.data); video_url_is_local = true; } else { - std::future<DownloadResult> download_future = std::async(std::launch::async, [this, &video_path, video_url]() { - return download_to_file(video_url, video_path.data, {}, use_tor, true); - }); + std::promise<DownloadResult> download_result_promise; + std::future<DownloadResult> download_future = download_result_promise.get_future(); + std::thread download_thread([this, &video_path, video_url](std::promise<DownloadResult> &&promise) { + promise.set_value(download_to_file(video_url, video_path.data, {}, use_tor, true)); + }, std::move(download_result_promise)); window_size.x = window.getSize().x; window_size.y = window.getSize().y; @@ -1625,9 +1594,8 @@ namespace QuickMedia { while(window.isOpen()) { while(window.pollEvent(event)) { if(event.type == sf::Event::Closed) { - // TODO: Remove this - if(download_future.valid()) - download_future.get(); + program_kill_in_thread(download_thread.get_id()); + download_thread.join(); current_page = previous_page; window.close(); return; @@ -1637,16 +1605,17 @@ namespace QuickMedia { sf::FloatRect visible_area(0, 0, window_size.x, window_size.y); window.setView(sf::View(visible_area)); } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) { - // TODO: Remove this - if(download_future.valid()) - download_future.get(); + program_kill_in_thread(download_thread.get_id()); + download_thread.join(); current_page = previous_page; return; } } if(is_future_ready(download_future)) { - if(download_future.get() != DownloadResult::OK) { + DownloadResult download_result = download_future.get(); + download_thread.join(); + if(download_result != DownloadResult::OK) { show_notification("QuickMedia", "Failed to download " + video_url, Urgency::CRITICAL); current_page = previous_page; return; @@ -3307,7 +3276,9 @@ namespace QuickMedia { chat_state = ChatState::NAVIGATING; return true; } else if(text == "/logout") { - show_notification("QuickMedia", "/logout command is temporary disabled. Delete " + get_storage_dir().join("matrix").join("session.json").data + " and restart QuickMedia to logout", Urgency::CRITICAL); + new_page = PageType::CHAT_LOGIN; + chat_input.set_editable(false); + chat_state = ChatState::NAVIGATING; return true; } else if(strncmp(text.c_str(), "/me ", 4) == 0) { msgtype = "m.emote"; @@ -3460,14 +3431,20 @@ namespace QuickMedia { float tab_vertical_offset = 0.0f; - auto typing_async_func = [this](bool new_state, RoomData *room) { - if(new_state) { - matrix->on_start_typing(room); - } else { - matrix->on_stop_typing(room); + MessageQueue<bool> typing_state_queue; + std::thread typing_state_thread([this, ¤t_room, &typing_state_queue]() { + while(true) { + std::optional<bool> state_opt = typing_state_queue.pop_wait(); + if(!state_opt) + break; + + bool state = state_opt.value(); + if(state) + matrix->on_start_typing(current_room); + else + matrix->on_stop_typing(current_room); } - }; - std::vector<std::future<void>> typing_futures; + }); sf::Clock frame_timer; @@ -3638,7 +3615,7 @@ namespace QuickMedia { if(typing && current_room) { fprintf(stderr, "Stopped typing\n"); typing = false; - typing_futures.push_back(std::async(typing_async_func, false, current_room)); + typing_state_queue.push(false); } } else if((event.key.code == sf::Keyboard::Right) && selected_tab < (int)tabs.size() - 1) { tabs[selected_tab].body->clear_cache(); @@ -3648,7 +3625,7 @@ namespace QuickMedia { if(typing && current_room) { fprintf(stderr, "Stopped typing\n"); typing = false; - typing_futures.push_back(std::async(typing_async_func, false, current_room)); + typing_state_queue.push(false); } } else if(event.key.code == sf::Keyboard::Escape) { goto chat_page_end; @@ -3662,6 +3639,14 @@ namespace QuickMedia { } } + if(current_room) { + if(event.key.control && event.key.code == sf::Keyboard::C) { + BodyItem *selected = tabs[selected_tab].body->get_selected(); + if(selected) + sf::Clipboard::setString(selected->get_description()); + } + } + if(selected_tab == MESSAGES_TAB_INDEX && current_room) { if(event.key.code == sf::Keyboard::U) { frame_skip_text_entry = true; @@ -3783,7 +3768,7 @@ namespace QuickMedia { start_typing_timer.restart(); if(!typing && current_room) { fprintf(stderr, "Started typing\n"); - typing_futures.push_back(std::async(typing_async_func, true, current_room)); + typing_state_queue.push(true); } typing = true; } @@ -3795,7 +3780,7 @@ namespace QuickMedia { if(typing && current_room) { fprintf(stderr, "Stopped typing\n"); typing = false; - typing_futures.push_back(std::async(typing_async_func, false, current_room)); + typing_state_queue.push(false); } } //chat_input.on_event(event); @@ -3840,7 +3825,30 @@ namespace QuickMedia { break; } case PageType::CHAT_LOGIN: { - abort(); + // TODO: Cancel these instead + if(set_read_marker_future.valid()) + set_read_marker_future.get(); + if(previous_messages_future.valid()) + previous_messages_future.get(); + if(fetch_message_future.valid()) + fetch_message_future.get(); + typing_state_queue.close(); + if(typing_state_thread.joinable()) + typing_state_thread.join(); + new_page = PageType::CHAT; + matrix->stop_sync(); + matrix->logout(); + tabs[MESSAGES_TAB_INDEX].body->clear_cache(); + // TODO: Instead of doing this, exit this current function and navigate to chat login page instead. + // This doesn't currently work because at the end of this function there are futures that need to wait + // and one of them is /sync, which has a timeout of 30 seconds. That timeout has to be killed somehow. + //delete current_plugin; + //current_plugin = new Matrix(); + current_page = PageType::CHAT_LOGIN; + chat_login_page(); + if(current_page == PageType::CHAT) + after_matrix_login_page(); + exit(0); break; } default: @@ -3850,22 +3858,7 @@ namespace QuickMedia { if(typing && start_typing_timer.getElapsedTime().asSeconds() >= typing_timeout_seconds && current_room) { fprintf(stderr, "Stopped typing\n"); typing = false; - typing_futures.push_back(std::async(typing_async_func, false, current_room)); - } - - for(auto it = typing_futures.begin(); it != typing_futures.end(); ) { - if(!it->valid()) { - it = typing_futures.erase(it); - continue; - } - - if(it->wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - it->get(); - it = typing_futures.erase(it); - continue; - } - - ++it; + typing_state_queue.push(false); } if(current_room && current_room->userdata && room_avatar_thumbnail_data->loading_state == LoadingState::NOT_LOADED) @@ -4146,13 +4139,60 @@ namespace QuickMedia { previous_messages_future.get(); if(fetch_message_future.valid()) fetch_message_future.get(); - for(auto &typing_future : typing_futures) { - if(typing_future.valid()) - typing_future.get(); - } + typing_state_queue.close(); + if(typing_state_thread.joinable()) + typing_state_thread.join(); for(auto &body_item : tabs[PINNED_TAB_INDEX].body->items) { delete (PinnedEventData*)body_item->userdata; } } + + void Program::after_matrix_login_page() { + if(!window.isOpen()) + exit(exit_code); + + auto rooms_body = create_body(); + rooms_body->thumbnail_mask_shader = &circle_mask_shader; + auto matrix_rooms_page = std::make_unique<MatrixRoomsPage>(this, rooms_body.get(), "All rooms"); + + auto rooms_tags_body = create_body(); + rooms_tags_body->thumbnail_mask_shader = &circle_mask_shader; + auto matrix_rooms_tag_page = std::make_unique<MatrixRoomTagsPage>(this, rooms_tags_body.get()); + + MatrixQuickMedia matrix_handler(this, matrix, matrix_rooms_page.get(), matrix_rooms_tag_page.get()); + matrix->start_sync(&matrix_handler); + + std::vector<Tab> tabs; + tabs.push_back(Tab{std::move(rooms_body), std::move(matrix_rooms_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + tabs.push_back(Tab{std::move(rooms_tags_body), std::move(matrix_rooms_tag_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + + sf::Sprite load_sprite(loading_icon); + sf::Vector2u loading_icon_size = loading_icon.getSize(); + load_sprite.setOrigin(loading_icon_size.x * 0.5f, loading_icon_size.y * 0.5f); + + sf::Clock timer; + sf::Event event; + while(window.isOpen() && !matrix->is_initial_sync_finished()) { + while(window.pollEvent(event)) { + if(event.type == sf::Event::Closed) + window.close(); + else if(event.type == sf::Event::Resized) { + window_size.x = event.size.width; + window_size.y = event.size.height; + sf::FloatRect visible_area(0, 0, window_size.x, window_size.y); + window.setView(sf::View(visible_area)); + } + } + window.clear(back_color); + load_sprite.setPosition(window_size.x * 0.5f, window_size.y * 0.5f); + load_sprite.setRotation(timer.getElapsedTime().asSeconds() * 400.0); + window.draw(load_sprite); + window.display(); + } + + while(window.isOpen()) { + page_loop(tabs); + } + } } diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp index cbb9634..c7d2697 100644 --- a/src/VideoPlayer.cpp +++ b/src/VideoPlayer.cpp @@ -1,6 +1,6 @@ #include "../include/VideoPlayer.hpp" #include "../include/Storage.hpp" -#include "../include/Program.h" +#include "../include/Program.hpp" #include <string> #include <json/reader.h> #include <json/writer.h> diff --git a/src/plugins/Manga.cpp b/src/plugins/Manga.cpp index 323794c..4685cec 100644 --- a/src/plugins/Manga.cpp +++ b/src/plugins/Manga.cpp @@ -1,5 +1,5 @@ #include "../../plugins/Manga.hpp" -#include "../../include/Program.h" +#include "../../include/Program.hpp" namespace QuickMedia { TrackResult MangaChaptersPage::track(const std::string &str) { @@ -10,7 +10,8 @@ namespace QuickMedia { return TrackResult::ERR; } - void MangaChaptersPage::on_navigate_to_page() { + void MangaChaptersPage::on_navigate_to_page(BodyItems &body_items) { + (void)body_items; std::string manga_id; if(extract_id_from_url(content_url, manga_id)) load_manga_content_storage(get_service_name(), content_title, manga_id); diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index a702841..93eb1d6 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -3,6 +3,7 @@ #include "../../include/StringUtils.hpp" #include "../../include/NetUtils.hpp" #include "../../include/Notification.hpp" +#include "../../include/Program.hpp" #include <rapidjson/document.h> #include <rapidjson/writer.h> #include <rapidjson/stringbuffer.h> @@ -521,8 +522,8 @@ namespace QuickMedia { } void Matrix::stop_sync() { - // TODO: Kill the running download in |sync_thread| instead of waiting until sync returns (which can be up to 30 seconds) sync_running = false; + program_kill_in_thread(sync_thread.get_id()); if(sync_thread.joinable()) sync_thread.join(); } @@ -534,8 +535,12 @@ namespace QuickMedia { void Matrix::get_room_sync_data(RoomData *room, SyncData &sync_data) { room->acquire_room_lock(); auto &room_messages = room->get_messages_thread_unsafe(); - sync_data.messages.insert(sync_data.messages.end(), room_messages.begin() + room->messages_read_index, room_messages.end()); - room->messages_read_index = room_messages.size(); + if(room->messages_read_index <= room_messages.size()) { + sync_data.messages.insert(sync_data.messages.end(), room_messages.begin() + room->messages_read_index, room_messages.end()); + room->messages_read_index = room_messages.size(); + } else { + fprintf(stderr, "Unexpected behavior!!!! get_room_sync_data said read index is %zu but we only have %zu messages\n", room->messages_read_index, room_messages.size()); + } if(room->pinned_events_updated) { sync_data.pinned_events = room->get_pinned_events_unsafe(); room->pinned_events_updated = false; diff --git a/src/plugins/NyaaSi.cpp b/src/plugins/NyaaSi.cpp index 8b1efc7..082aaa8 100644 --- a/src/plugins/NyaaSi.cpp +++ b/src/plugins/NyaaSi.cpp @@ -1,5 +1,5 @@ #include "../../plugins/NyaaSi.hpp" -#include "../../include/Program.h" +#include "../../include/Program.hpp" #include "../../include/Storage.hpp" #include "../../include/Notification.hpp" #include "../../include/StringUtils.hpp" |