# HG changeset patch # User Paper # Date 1718129800 14400 # Node ID 34347fd2a2defc03fda5c88403a75f89d04c37d3 # Parent 76d7315504c4c85cec6113d28d19a029bfe63632 session: allow printing status messages ...! diff -r 76d7315504c4 -r 34347fd2a2de Makefile.am --- a/Makefile.am Tue Jun 11 13:29:45 2024 -0400 +++ b/Makefile.am Tue Jun 11 14:16:40 2024 -0400 @@ -126,6 +126,7 @@ minori_qtheaders = \ include/core/http.h \ + include/core/session.h \ include/gui/dialog/about.h \ include/gui/dialog/information.h \ include/gui/dialog/settings.h \ @@ -162,7 +163,6 @@ include/core/filesystem.h \ include/core/ini.h \ include/core/json.h \ - include/core/session.h \ include/core/strings.h \ include/core/time.h \ include/core/torrent.h \ @@ -196,6 +196,7 @@ src/core/http.cc \ src/core/ini.cc \ src/core/json.cc \ + src/core/session.cc \ src/core/strings.cc \ src/core/time.cc \ src/gui/dialog/settings/application.cc \ diff -r 76d7315504c4 -r 34347fd2a2de include/core/session.h --- a/include/core/session.h Tue Jun 11 13:29:45 2024 -0400 +++ b/include/core/session.h Tue Jun 11 14:16:40 2024 -0400 @@ -4,27 +4,42 @@ #include "core/config.h" #include "gui/locale.h" +#include #include #include "semver/semver.hpp" #include +#include -struct Session { +class MainWindow; + +struct Session : public QObject { + Q_OBJECT + public: - Session() { timer.start(); } + Session(); + + void SetMainWindow(MainWindow* window); + + void SetStatusBar(const std::string& message); + /* we literally *cannot* be lying to the user by doing this */ - void IncrementRequests() { requests++; }; - unsigned int GetRequests() { return requests; }; - int uptime() { return timer.elapsed(); } + void IncrementRequests(); + unsigned int GetRequests(); + int uptime(); Config config; static constexpr semver::version version{PACKAGE_VERSION}; +signals: + void StatusBarChange(const std::string& message); + private: /* IncrementRequests() gets called by different threads */ - std::atomic requests = 0; - QElapsedTimer timer; + std::atomic requests_ = 0; + QElapsedTimer timer_; + MainWindow* window_; }; extern Session session; diff -r 76d7315504c4 -r 34347fd2a2de include/gui/window.h --- a/include/gui/window.h Tue Jun 11 13:29:45 2024 -0400 +++ b/include/gui/window.h Tue Jun 11 14:16:40 2024 -0400 @@ -27,6 +27,7 @@ /* ... :) */ Q_DECLARE_METATYPE(std::vector); +Q_DECLARE_METATYPE(std::string); class MainWindowPlayingThread final : public QThread { Q_OBJECT @@ -84,6 +85,9 @@ void showEvent(QShowEvent* event) override; void closeEvent(QCloseEvent* event) override; +public slots: + void SetStatusMessage(const std::string& message); + private: QWidget main_widget_; QStackedWidget stack_; diff -r 76d7315504c4 -r 34347fd2a2de src/core/session.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/core/session.cc Tue Jun 11 14:16:40 2024 -0400 @@ -0,0 +1,40 @@ +#include "core/session.h" +#include "core/strings.h" +#include "core/config.h" +#include "gui/window.h" +#include "gui/locale.h" + +#include +#include + +#include "semver/semver.hpp" + +#include + +Session session; + +Session::Session() { + timer_.start(); +} + +void Session::SetMainWindow(MainWindow* window) { + disconnect(); + window_ = window; + connect(this, &Session::StatusBarChange, window_, &MainWindow::SetStatusMessage); +} + +void Session::SetStatusBar(const std::string& message) { + emit StatusBarChange(message); +} + +void Session::IncrementRequests() { + requests_++; +}; + +unsigned int Session::GetRequests() { + return requests_; +}; + +int Session::uptime() { + return timer_.elapsed(); +} diff -r 76d7315504c4 -r 34347fd2a2de src/gui/pages/anime_list.cc --- a/src/gui/pages/anime_list.cc Tue Jun 11 13:29:45 2024 -0400 +++ b/src/gui/pages/anime_list.cc Tue Jun 11 14:16:40 2024 -0400 @@ -305,8 +305,9 @@ if (!index.isValid()) continue; Anime::Anime* anime = source_model->GetAnimeFromIndex(index); - if (anime) - animes.insert(anime); + if (!anime) + continue; + animes.insert(&Anime::db.items[anime->GetId()]); } menu->addAction(tr("Information"), [this, animes] { @@ -352,10 +353,10 @@ reinterpret_cast(sort_models[tab_bar->currentIndex()]->sourceModel()); const QModelIndex index = source_model->index(selection.indexes().first().row()); - Anime::Anime* anime = source_model->GetAnimeFromIndex(index); + Anime::Anime& anime = Anime::db.items[source_model->GetAnimeFromIndex(index)->GetId()]; InformationDialog* dialog = new InformationDialog( - anime, [this](Anime::Anime* anime) { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, this); + &anime, [this](Anime::Anime* anime) { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, this); dialog->show(); dialog->raise(); diff -r 76d7315504c4 -r 34347fd2a2de src/gui/window.cc --- a/src/gui/window.cc Tue Jun 11 13:29:45 2024 -0400 +++ b/src/gui/window.cc Tue Jun 11 14:16:40 2024 -0400 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,8 @@ sidebar_.setFixedWidth(128); sidebar_.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + statusBar(); + new QHBoxLayout(&main_widget_); CreateBars(); @@ -132,6 +135,10 @@ playing_thread_timer_.start(5000); } +void MainWindow::SetStatusMessage(const std::string& message) { + statusBar()->showMessage(Strings::ToQString(message), 2000); +} + /* Does the main part of what Qt's generic "RetranslateUI" function would do */ void MainWindow::AddMainWidgets() { int page = sidebar_.GetCurrentItem(); diff -r 76d7315504c4 -r 34347fd2a2de src/main.cc --- a/src/main.cc Tue Jun 11 13:29:45 2024 -0400 +++ b/src/main.cc Tue Jun 11 14:16:40 2024 -0400 @@ -11,8 +11,6 @@ #include -Session session; - int main(int argc, char** argv) { QApplication app(argc, argv); app.setApplicationName("minori"); @@ -21,6 +19,7 @@ qRegisterMetaType>(); /* window.cc */ qRegisterMetaType>(); /* search.cc */ + qRegisterMetaType(); session.config.Load(); Anime::db.LoadDatabaseFromDisk(); @@ -31,5 +30,8 @@ window.setWindowTitle("Minori"); window.show(); + /* do this before starting the app... */ + session.SetMainWindow(&window); + return app.exec(); } diff -r 76d7315504c4 -r 34347fd2a2de src/services/anilist.cc --- a/src/services/anilist.cc Tue Jun 11 13:29:45 2024 -0400 +++ b/src/services/anilist.cc Tue Jun 11 14:16:40 2024 -0400 @@ -74,28 +74,29 @@ return Strings::ToUtf8String(HTTP::Request("https://graphql.anilist.co", headers, data, HTTP::Type::Post)); } -static nlohmann::json SendJSONRequest(const nlohmann::json& data) { +static bool SendJSONRequest(const nlohmann::json& data, nlohmann::json& out) { std::string request = SendRequest(data.dump()); if (request.empty()) { - std::cerr << "[AniList] JSON Request returned an empty result!" << std::endl; - return {}; + session.SetStatusBar("AniList: JSON request returned an empty result!"); + return false; } - auto ret = nlohmann::json::parse(request, nullptr, false); - if (ret.is_discarded()) { - std::cerr << "[AniList] Failed to parse request JSON!" << std::endl; - return {}; + out = nlohmann::json::parse(request, nullptr, false); + if (out.is_discarded()) { + session.SetStatusBar("AniList: Failed to parse request JSON!"); + return false; } - if (ret.contains("/errors"_json_pointer) && ret.at("/errors"_json_pointer).is_array()) { - for (const auto& error : ret.at("/errors"_json_pointer)) + if (out.contains("/errors"_json_pointer) && out.at("/errors"_json_pointer).is_array()) { + for (const auto& error : out.at("/errors"_json_pointer)) std::cerr << "[AniList] Received an error in response: " << JSON::GetString(error, "/message"_json_pointer, "") << std::endl; - return {}; + session.SetStatusBar("AniList: Received an error in response!"); + return false; } - return ret; + return true; } static void ParseListStatus(std::string status, Anime::Anime& anime) { @@ -212,10 +213,12 @@ int GetAnimeList() { if (!account.IsValid()) { - std::cerr << "AniList: Account isn't valid!" << std::endl; + session.SetStatusBar("AniList: Account isn't valid!"); return 0; } + session.SetStatusBar("AniList: Retrieving anime list..."); + /* NOTE: these really ought to be in the qrc file */ constexpr std::string_view query = "query ($id: Int) {\n" " MediaListCollection (userId: $id, type: ANIME) {\n" @@ -253,11 +256,18 @@ }; // clang-format on - auto res = SendJSONRequest(json); + session.SetStatusBar("AniList: Parsing anime list..."); - for (const auto& list : res["data"]["MediaListCollection"]["lists"].items()) + nlohmann::json result; + const bool res = SendJSONRequest(json, result); + if (!res) + return 0; + + for (const auto& list : result["data"]["MediaListCollection"]["lists"].items()) ParseList(list.value()); + session.SetStatusBar("AniList: Retrieved anime list successfully!"); + return 1; } @@ -280,13 +290,16 @@ }; // clang-format on - auto res = SendJSONRequest(json); + nlohmann::json result; + const bool res = SendJSONRequest(json, result); + if (!res) + return {}; /* FIXME: error handling here */ std::vector ret; - ret.reserve(res["data"]["Page"]["media"].size()); + ret.reserve(result["/data/Page/media"_json_pointer].size()); - for (const auto& media : res["data"]["Page"]["media"].items()) + for (const auto& media : result["/data/Page/media"_json_pointer].items()) ret.push_back(ParseMediaJson(media.value())); return ret; @@ -321,13 +334,17 @@ }} }; - auto res = SendJSONRequest(json); - ret.reserve(ret.capacity() + res["data"]["Page"]["media"].size()); + nlohmann::json result; + const bool res = SendJSONRequest(json, result); + if (!res) + return {}; - for (const auto& media : res["data"]["Page"]["media"].items()) + ret.reserve(ret.capacity() + result["data"]["Page"]["media"].size()); + + for (const auto& media : result["data"]["Page"]["media"].items()) ret.push_back(ParseMediaJson(media.value())); - has_next_page = JSON::GetBoolean(res, "/data/Page/pageInfo/hasNextPage"_json_pointer, false); + has_next_page = JSON::GetBoolean(result, "/data/Page/pageInfo/hasNextPage"_json_pointer, false); if (has_next_page) page++; } @@ -363,6 +380,8 @@ if (!service_id) return 0; + session.SetStatusBar("AniList: Updating anime entry..."); + constexpr std::string_view query = "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String, $start: " "FuzzyDateInput, $comp: FuzzyDateInput, $repeat: Int) {\n" @@ -387,9 +406,14 @@ }; // clang-format on - auto ret = SendJSONRequest(json); + nlohmann::json result; + const bool ret = SendJSONRequest(json, result); + if (!ret) + return 0; - return JSON::GetNumber(ret, "/data/SaveMediaListEntry/id"_json_pointer, 0); + session.SetStatusBar("AniList: Anime entry updated successfully!"); + + return JSON::GetNumber(result, "/data/SaveMediaListEntry/id"_json_pointer, 0); } static int ParseUser(const nlohmann::json& json) { @@ -412,6 +436,8 @@ account.SetAuthToken(Strings::ToUtf8String(token)); + session.SetStatusBar("AniList: Requesting user ID..."); + constexpr std::string_view query = "query {\n" " Viewer {\n" " id\n" @@ -425,7 +451,13 @@ {"query", query} }; - auto ret = SendJSONRequest(json); + /* SendJSONRequest handles status errors */ + nlohmann::json result; + const bool ret = SendJSONRequest(json, result); + if (!ret) + return 0; + + session.SetStatusBar("AniList: Successfully retrieved user data!"); ParseUser(ret["data"]["Viewer"]); return true;