Mercurial > minori
changeset 15:cde8f67a7c7d
*: update, megacommit :)
line wrap: on
line diff
--- a/.clang-format Tue Sep 19 16:33:07 2023 -0400 +++ b/.clang-format Tue Sep 19 22:36:08 2023 -0400 @@ -1,22 +1,28 @@ --- BasedOnStyle: LLVM +UseTab: ForIndentation +PointerAlignment: Left +ColumnLimit: 120 IndentWidth: 4 TabWidth: 4 -UseTab: Always -PointerAlignment: Left +AccessModifierOffset: 4 + IndentCaseLabels: true +IndentAccessModifiers: true +IndentPPDirectives: AfterHash + BreakBeforeBraces: Attach BreakStringLiterals: true -AllowShortIfStatementsOnASingleLine: false -ColumnLimit: 120 + AlignAfterOpenBracket: Align -IndentAccessModifiers: true -AccessModifierOffset: 4 AlignArrayOfStructures: Left +AlignEscapedNewlines: DontAlign AlignConsecutiveMacros: Enabled: true AcrossEmptyLines: true AcrossComments: false + +AllowShortIfStatementsOnASingleLine: false AllowShortBlocksOnASingleLine: Empty AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: InlineOnly
--- a/CMakeLists.txt Tue Sep 19 16:33:07 2023 -0400 +++ b/CMakeLists.txt Tue Sep 19 22:36:08 2023 -0400 @@ -53,6 +53,7 @@ # Translate src/gui/translate/anime.cpp + src/gui/translate/anilist.cpp # Services (only AniList for now) src/services/services.cpp
--- a/include/core/anime.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/core/anime.h Tue Sep 19 22:36:08 2023 -0400 @@ -16,8 +16,8 @@ PAUSED }; -constexpr std::array<ListStatus, 5> ListStatuses{ListStatus::CURRENT, ListStatus::PLANNING, ListStatus::COMPLETED, - ListStatus::DROPPED, ListStatus::PAUSED}; +constexpr std::array<ListStatus, 5> ListStatuses{ListStatus::CURRENT, ListStatus::COMPLETED, ListStatus::PAUSED, + ListStatus::DROPPED, ListStatus::PLANNING}; enum class SeriesStatus { UNKNOWN, @@ -63,37 +63,37 @@ }; struct ListInformation { - int id = 0; - int progress = 0; - int score = 0; - ListStatus status = ListStatus::NOT_IN_LIST; - Date started; - Date completed; - bool is_private = false; - unsigned int rewatched_times = 0; - bool rewatching = false; - uint64_t updated = 0; - std::string notes; + int id = 0; + int progress = 0; + int score = 0; + ListStatus status = ListStatus::NOT_IN_LIST; + Date started; + Date completed; + bool is_private = false; + unsigned int rewatched_times = 0; + bool rewatching = false; + uint64_t updated = 0; + std::string notes; }; struct SeriesInformation { - int id; - struct { - std::string romaji; - std::string english; - std::string native; - } title; - std::vector<std::string> synonyms; - int episodes = 0; - SeriesStatus status = SeriesStatus::UNKNOWN; - Date air_date; - std::vector<std::string> genres; - std::vector<std::string> producers; - SeriesFormat format = SeriesFormat::UNKNOWN; - SeriesSeason season = SeriesSeason::UNKNOWN; - int audience_score = 0; - std::string synopsis; - int duration = 0; + int id; + struct { + std::string romaji; + std::string english; + std::string native; + } title; + std::vector<std::string> synonyms; + int episodes = 0; + SeriesStatus status = SeriesStatus::UNKNOWN; + Date air_date; + std::vector<std::string> genres; + std::vector<std::string> producers; + SeriesFormat format = SeriesFormat::UNKNOWN; + SeriesSeason season = SeriesSeason::UNKNOWN; + int audience_score = 0; + std::string synopsis; + int duration = 0; }; class Anime {
--- a/include/core/strings.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/core/strings.h Tue Sep 19 22:36:08 2023 -0400 @@ -1,8 +1,11 @@ #ifndef __core__strings_h #define __core__strings_h + #include <string> #include <vector> + namespace Strings { + /* Implode function: takes a vector of strings and turns it into a string, separated by delimiters. */ std::string Implode(const std::vector<std::string>& vector, const std::string& delimiter); @@ -14,5 +17,9 @@ /* stupid HTML bullshit */ std::string TextifySynopsis(const std::string& string); -}; // namespace StringUtils + +std::string ToUpper(const std::string& string); +std::string ToLower(const std::string& string); + +}; // namespace StringUtils #endif // __core__strings_h \ No newline at end of file
--- a/include/gui/pages/anime_list.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/gui/pages/anime_list.h Tue Sep 19 22:36:08 2023 -0400 @@ -44,7 +44,6 @@ AL_COMPLETED, AL_UPDATED, AL_NOTES, - AL_ID, /* Note: This is only used in Qt::UserRole to make my life easier */ NB_COLUMNS }; @@ -71,7 +70,7 @@ public: AnimeListWidget(QWidget* parent); - void RefreshList(); + void Refresh(); void Reset(); protected: @@ -81,6 +80,8 @@ void SetupLayout(); void showEvent(QShowEvent*) override; void resizeEvent(QResizeEvent* e) override; + void RefreshList(); + void RefreshTabs(); private slots: void DisplayColumnHeaderMenu();
--- a/include/gui/sidebar.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/gui/sidebar.h Tue Sep 19 22:36:08 2023 -0400 @@ -19,7 +19,7 @@ protected: virtual void mouseMoveEvent(QMouseEvent* event) override; QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex& index, - const QEvent* event) const override; + const QEvent* event) const override; int RemoveSeparatorsFromIndex(int index); }; #endif // __gui__sidebar_h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/gui/translate/anilist.h Tue Sep 19 22:36:08 2023 -0400 @@ -0,0 +1,13 @@ +#ifndef __gui__translate__anilist_h +#define __gui__translate__anilist_h +#include "core/anime.h" + +namespace Translate::AniList { + +Anime::SeriesStatus ToSeriesStatus(std::string status); +Anime::SeriesSeason ToSeriesSeason(std::string season); +Anime::SeriesFormat ToSeriesFormat(std::string format); + +} + +#endif // __gui__translate__anilist_h
--- a/include/gui/translate/anime.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/gui/translate/anime.h Tue Sep 19 22:36:08 2023 -0400 @@ -2,9 +2,9 @@ namespace Translate { -std::string TranslateListStatus(const Anime::ListStatus status); -std::string TranslateSeriesFormat(const Anime::SeriesFormat format); -std::string TranslateSeriesSeason(const Anime::SeriesSeason season); -std::string TranslateSeriesStatus(const Anime::SeriesStatus status); +std::string ToString(const Anime::ListStatus status); +std::string ToString(const Anime::SeriesFormat format); +std::string ToString(const Anime::SeriesSeason season); +std::string ToString(const Anime::SeriesStatus status); } // namespace Translate
--- a/include/gui/ui_utils.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/gui/ui_utils.h Tue Sep 19 22:36:08 2023 -0400 @@ -74,5 +74,5 @@ Header* header; Paragraph* paragraph; }; -}; // namespace UiUtils +}; // namespace UiUtils #endif // __gui__ui_utils_h \ No newline at end of file
--- a/include/services/anilist.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/services/anilist.h Tue Sep 19 22:36:08 2023 -0400 @@ -1,9 +1,12 @@ #ifndef __services__anilist_h #define __services__anilist_h + #include "core/anime.h" #include "core/json.h" #include <curl/curl.h> + namespace Services::AniList { + int AuthorizeUser(); /* Read queries */ @@ -11,5 +14,7 @@ /* Write queries (mutations) */ int UpdateAnimeEntry(int id); -}; // namespace AniList + +}; // namespace Services::AniList + #endif // __services__anilist_h
--- a/include/sys/osx/dark_theme.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/sys/osx/dark_theme.h Tue Sep 19 22:36:08 2023 -0400 @@ -1,10 +1,14 @@ #ifndef __sys__osx__dark_theme_h #define __sys__osx__dark_theme_h + namespace osx { + bool DarkThemeAvailable(); bool IsInDarkTheme(); void SetToDarkTheme(); void SetToLightTheme(); void SetToAutoTheme(); + } // namespace osx + #endif // __sys__osx__dark_theme_h \ No newline at end of file
--- a/include/sys/osx/filesystem.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/sys/osx/filesystem.h Tue Sep 19 22:36:08 2023 -0400 @@ -1,7 +1,12 @@ #ifndef __sys__osx__filesystem_h #define __sys__osx__filesystem_h + #include <string> + namespace osx { + std::string GetApplicationSupportDirectory(); + } + #endif // __sys__osx__filesystem_h \ No newline at end of file
--- a/include/sys/win32/dark_theme.h Tue Sep 19 16:33:07 2023 -0400 +++ b/include/sys/win32/dark_theme.h Tue Sep 19 22:36:08 2023 -0400 @@ -1,7 +1,11 @@ #ifndef __sys__win32__dark_theme_h #define __sys__win32__dark_theme_h + namespace win32 { + bool DarkThemeAvailable(); bool IsInDarkTheme(); + } // namespace win32 + #endif // __sys__win32__dark_theme_h \ No newline at end of file
--- a/src/core/config.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/core/config.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -13,37 +13,37 @@ #include <limits.h> std::map<std::string, Themes> StringToTheme = { - {"Default", Themes::OS }, - {"Light", Themes::LIGHT}, - {"Dark", Themes::DARK } + {"Default", Themes::OS }, + {"Light", Themes::LIGHT}, + {"Dark", Themes::DARK } }; std::map<Themes, std::string> ThemeToString = { - {Themes::OS, "Default"}, - {Themes::LIGHT, "Light" }, - {Themes::DARK, "Dark" } + {Themes::OS, "Default"}, + {Themes::LIGHT, "Light" }, + {Themes::DARK, "Dark" } }; std::map<Anime::Services, std::string> ServiceToString{ - {Anime::Services::NONE, "None" }, - {Anime::Services::ANILIST, "AniList"} + {Anime::Services::NONE, "None" }, + {Anime::Services::ANILIST, "AniList"} }; std::map<std::string, Anime::Services> StringToService{ - {"None", Anime::Services::NONE }, - {"AniList", Anime::Services::ANILIST} + {"None", Anime::Services::NONE }, + {"AniList", Anime::Services::ANILIST} }; std::map<Anime::TitleLanguage, std::string> AnimeTitleToStringMap = { - {Anime::TitleLanguage::ROMAJI, "Romaji" }, - {Anime::TitleLanguage::NATIVE, "Native" }, - {Anime::TitleLanguage::ENGLISH, "English"} + {Anime::TitleLanguage::ROMAJI, "Romaji" }, + {Anime::TitleLanguage::NATIVE, "Native" }, + {Anime::TitleLanguage::ENGLISH, "English"} }; std::map<std::string, Anime::TitleLanguage> StringToAnimeTitleMap = { - {"Romaji", Anime::TitleLanguage::ROMAJI }, - {"Native", Anime::TitleLanguage::NATIVE }, - {"English", Anime::TitleLanguage::ENGLISH} + {"Romaji", Anime::TitleLanguage::ROMAJI }, + {"Native", Anime::TitleLanguage::NATIVE }, + {"English", Anime::TitleLanguage::ENGLISH} }; int Config::Load() { @@ -54,15 +54,15 @@ auto config_js = nlohmann::json::parse(config); service = StringToService[JSON::GetString(config_js, "/General/Service"_json_pointer)]; anime_list.language = StringToAnimeTitleMap[JSON::GetString( - config_js, "/Anime List/Display only aired episodes"_json_pointer, "Romaji")]; + config_js, "/Anime List/Display only aired episodes"_json_pointer, "Romaji")]; anime_list.display_aired_episodes = - JSON::GetBoolean(config_js, "/Anime List/Display only aired episodes"_json_pointer, true); + JSON::GetBoolean(config_js, "/Anime List/Display only aired episodes"_json_pointer, true); anime_list.display_available_episodes = - JSON::GetBoolean(config_js, "/Anime List/Display only available episodes in library"_json_pointer, true); + JSON::GetBoolean(config_js, "/Anime List/Display only available episodes in library"_json_pointer, true); anime_list.highlight_anime_if_available = - JSON::GetBoolean(config_js, "/Anime List/Highlight anime if available"_json_pointer, true); + JSON::GetBoolean(config_js, "/Anime List/Highlight anime if available"_json_pointer, true); anime_list.highlighted_anime_above_others = - JSON::GetBoolean(config_js, "/Anime List/Display highlighted anime above others"_json_pointer); + JSON::GetBoolean(config_js, "/Anime List/Display highlighted anime above others"_json_pointer); anilist.auth_token = JSON::GetString(config_js, "/Authorization/AniList/Auth Token"_json_pointer); anilist.username = JSON::GetString(config_js, "/Authorization/AniList/Username"_json_pointer); anilist.user_id = JSON::GetInt(config_js, "/Authorization/AniList/User ID"_json_pointer);
--- a/src/core/date.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/core/date.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -106,7 +106,8 @@ /* QDates don't (yet) support "missing" values */ if (year.get() && month.get() && day.get()) return QDate(*year, *month, *day); - else return QDate(); + else + return QDate(); } nlohmann::json Date::GetAsAniListJson() const {
--- a/src/core/filesystem.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/core/filesystem.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -1,22 +1,22 @@ #ifdef WIN32 -#include <shlobj.h> +# include <shlobj.h> #elif defined(MACOSX) -#include "sys/osx/filesystem.h" +# include "sys/osx/filesystem.h" #elif defined(__linux__) -#include <pwd.h> -#include <sys/types.h> +# include <pwd.h> +# include <sys/types.h> #endif #ifdef WIN32 -#define DELIM "\\" +# define DELIM "\\" #else -#define DELIM "/" -#include <unistd.h> -#include <errno.h> +# define DELIM "/" +# include <errno.h> +# include <unistd.h> #endif +#include "core/config.h" #include "core/filesystem.h" -#include "core/config.h" #include <limits.h> namespace Filesystem { @@ -26,8 +26,7 @@ size_t start; size_t end = 0; - while ((start = path.find_first_not_of(DELIM, end)) != std::string::npos) - { + while ((start = path.find_first_not_of(DELIM, end)) != std::string::npos) { end = path.find(DELIM, start); temp.append(path.substr(start, end - start)); #ifdef WIN32 @@ -73,14 +72,14 @@ #else // just assume POSIX if (getenv("HOME") != NULL) ret += getenv("HOME"); -#ifdef __linux__ +# ifdef __linux__ else ret += getpwuid(getuid())->pw_dir; -#endif // __linux__ +# endif // __linux__ if (!ret.empty()) ret += DELIM ".config" DELIM CONFIG_DIR DELIM CONFIG_NAME; -#endif // !WIN32 && !MACOSX +#endif // !WIN32 && !MACOSX return ret; } -} +} // namespace Filesystem
--- a/src/core/strings.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/core/strings.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -2,7 +2,8 @@ * strings.cpp: Useful functions for manipulating strings **/ #include "core/strings.h" -#include <codecvt> +#include <algorithm> +#include <cctype> #include <locale> #include <string> #include <vector> @@ -59,4 +60,19 @@ return RemoveHtmlTags(SanitizeLineEndings(string)); } +/* these functions suck for i18n!... + but we only use them with JSON + stuff anyway */ +std::string ToUpper(const std::string& string) { + std::string result(string); + std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return std::toupper(c); }); + return result; +} + +std::string ToLower(const std::string& string) { + std::string result(string); + std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return std::tolower(c); }); + return result; +} + } // namespace Strings
--- a/src/gui/dialog/information.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/dialog/information.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -13,7 +13,7 @@ #include <functional> InformationDialog::InformationDialog(Anime::Anime& anime, std::function<void()> accept, QWidget* parent) - : QDialog(parent) { + : QDialog(parent) { setFixedSize(842, 613); setWindowTitle(tr("Anime Information")); setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); @@ -33,7 +33,7 @@ /* anime title header text */ UiUtils::Paragraph* anime_title = - new UiUtils::Paragraph(QString::fromUtf8(anime.GetUserPreferredTitle().c_str()), main_widget); + new UiUtils::Paragraph(QString::fromUtf8(anime.GetUserPreferredTitle().c_str()), main_widget); anime_title->setReadOnly(true); anime_title->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); anime_title->setWordWrapMode(QTextOption::NoWrap); @@ -53,25 +53,25 @@ /* alt titles */ main_information_widget->layout()->addWidget(new UiUtils::SelectableTextParagraph( - "Alternative titles", QString::fromUtf8(Strings::Implode(anime.GetTitleSynonyms(), ", ").c_str()), - main_information_widget)); + "Alternative titles", QString::fromUtf8(Strings::Implode(anime.GetTitleSynonyms(), ", ").c_str()), + main_information_widget)); /* details */ QString details_data; QTextStream details_data_s(&details_data); - details_data_s << Translate::TranslateSeriesFormat(anime.GetFormat()).c_str() << "\n" - << anime.GetEpisodes() << "\n" - << Translate::TranslateListStatus(anime.GetUserStatus()).c_str() << "\n" - << Translate::TranslateSeriesSeason(anime.GetSeason()).c_str() << " " << anime.GetAirDate().GetYear() - << "\n" - << Strings::Implode(anime.GetGenres(), ", ").c_str() << "\n" - << anime.GetAudienceScore() << "%"; + details_data_s << Translate::ToString(anime.GetFormat()).c_str() << "\n" + << anime.GetEpisodes() << "\n" + << Translate::ToString(anime.GetUserStatus()).c_str() << "\n" + << Translate::ToString(anime.GetSeason()).c_str() << " " << anime.GetAirDate().GetYear() + << "\n" + << Strings::Implode(anime.GetGenres(), ", ").c_str() << "\n" + << anime.GetAudienceScore() << "%"; main_information_widget->layout()->addWidget(new UiUtils::LabelledTextParagraph( - "Details", "Type:\nEpisodes:\nStatus:\nSeason:\nGenres:\nScore:", details_data, main_information_widget)); + "Details", "Type:\nEpisodes:\nStatus:\nSeason:\nGenres:\nScore:", details_data, main_information_widget)); /* synopsis */ UiUtils::SelectableTextParagraph* synopsis = new UiUtils::SelectableTextParagraph( - "Synopsis", QString::fromUtf8(anime.GetSynopsis().c_str()), main_information_widget); + "Synopsis", QString::fromUtf8(anime.GetSynopsis().c_str()), main_information_widget); synopsis->GetParagraph()->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); ((QVBoxLayout*)main_information_widget->layout())->addWidget(synopsis);
--- a/src/gui/dialog/settings.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/dialog/settings.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -18,7 +18,7 @@ page_title->setFrameShape(QFrame::Panel); page_title->setFrameShadow(QFrame::Sunken); page_title->setStyleSheet( - "QLabel { font-size: 10pt; font-weight: bold; background-color: #ABABAB; color: white; }"); + "QLabel { font-size: 10pt; font-weight: bold; background-color: #ABABAB; color: white; }"); page_title->setFixedHeight(23); page_title->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); page_title->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
--- a/src/gui/dialog/settings/application.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/dialog/settings/application.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -52,18 +52,18 @@ lang_combo_box->addItem(tr("Native")); lang_combo_box->addItem(tr("English")); connect(lang_combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - [this](int index) { language = static_cast<Anime::TitleLanguage>(index); }); + [this](int index) { language = static_cast<Anime::TitleLanguage>(index); }); lang_combo_box->setCurrentIndex(static_cast<int>(language)); QCheckBox* hl_anime_box = - new QCheckBox(tr("Highlight anime if next episode is available in library folders"), appearance_group_box); + new QCheckBox(tr("Highlight anime if next episode is available in library folders"), appearance_group_box); QCheckBox* hl_above_anime_box = new QCheckBox(tr("Display highlighted anime above others"), appearance_group_box); connect(hl_anime_box, &QCheckBox::stateChanged, this, [this, hl_above_anime_box](int state) { highlight_anime_if_available = (state == Qt::Unchecked) ? false : true; hl_above_anime_box->setEnabled(state); }); connect(hl_above_anime_box, &QCheckBox::stateChanged, this, - [this](int state) { highlight_anime_if_available = (state == Qt::Unchecked) ? false : true; }); + [this](int state) { highlight_anime_if_available = (state == Qt::Unchecked) ? false : true; }); hl_anime_box->setCheckState(highlight_anime_if_available ? Qt::Checked : Qt::Unchecked); hl_above_anime_box->setCheckState(highlighted_anime_above_others ? Qt::Checked : Qt::Unchecked); hl_above_anime_box->setEnabled(hl_anime_box->checkState() != Qt::Unchecked); @@ -81,15 +81,15 @@ progress_group_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); QCheckBox* progress_display_aired_episodes = - new QCheckBox(tr("Display aired episodes (estimated)"), progress_group_box); + new QCheckBox(tr("Display aired episodes (estimated)"), progress_group_box); connect(progress_display_aired_episodes, &QCheckBox::stateChanged, this, - [this](int state) { display_aired_episodes = (state == Qt::Unchecked) ? false : true; }); + [this](int state) { display_aired_episodes = (state == Qt::Unchecked) ? false : true; }); progress_display_aired_episodes->setCheckState(display_aired_episodes ? Qt::Checked : Qt::Unchecked); QCheckBox* progress_display_available_episodes = - new QCheckBox(tr("Display available episodes in library folders"), progress_group_box); + new QCheckBox(tr("Display available episodes in library folders"), progress_group_box); connect(progress_display_available_episodes, &QCheckBox::stateChanged, this, - [this](int state) { display_available_episodes = (state == Qt::Unchecked) ? false : true; }); + [this](int state) { display_available_episodes = (state == Qt::Unchecked) ? false : true; }); progress_display_available_episodes->setCheckState(display_available_episodes ? Qt::Checked : Qt::Unchecked); QVBoxLayout* progress_layout = new QVBoxLayout;
--- a/src/gui/dialog/settings/services.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/dialog/settings/services.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -19,11 +19,11 @@ QComboBox* sync_combo_box = new QComboBox(sync_group_box); sync_combo_box->addItem(tr("AniList")); connect(sync_combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - [this](int index) { service = static_cast<Anime::Services>(index + 1); }); + [this](int index) { service = static_cast<Anime::Services>(index + 1); }); sync_combo_box->setCurrentIndex(static_cast<int>(service) - 1); QLabel* sync_note_label = - new QLabel(tr("Note: Minori is unable to synchronize multiple services at the same time."), sync_group_box); + new QLabel(tr("Note: Minori is unable to synchronize multiple services at the same time."), sync_group_box); QVBoxLayout* sync_layout = new QVBoxLayout; sync_layout->addWidget(sync_combo_box_label); @@ -51,7 +51,7 @@ QWidget* auth_widget = new QWidget(group_box); QLineEdit* username_entry = new QLineEdit(username, auth_widget); connect(username_entry, &QLineEdit::editingFinished, this, - [this, username_entry] { username = username_entry->text(); }); + [this, username_entry] { username = username_entry->text(); }); QPushButton* auth_button = new QPushButton(auth_widget); connect(auth_button, &QPushButton::clicked, this, [] { Services::AniList::AuthorizeUser(); });
--- a/src/gui/pages/anime_list.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/pages/anime_list.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -16,15 +16,14 @@ #include "gui/dialog/information.h" #include "gui/translate/anime.h" #include "services/anilist.h" +#include <QDebug> #include <QHBoxLayout> #include <QHeaderView> #include <QMenu> #include <QProgressBar> -#include <QDebug> #include <QShortcut> #include <QStylePainter> #include <QStyledItemDelegate> -#include <QAbstractItemModelTester> #include <cmath> AnimeListWidgetDelegate::AnimeListWidgetDelegate(QObject* parent) : QStyledItemDelegate(parent) { @@ -36,29 +35,29 @@ } void AnimeListWidgetDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, - const QModelIndex& index) const { + const QModelIndex& index) const { switch (index.column()) { -/* +#if 0 case AnimeListWidgetModel::AL_PROGRESS: { const int progress = static_cast<int>(index.data(Qt::UserRole).toReal()); const int episodes = - static_cast<int>(index.siblingAtColumn(AnimeListWidgetModel::AL_EPISODES).data(Qt::UserRole).toReal()); + static_cast<int>(index.siblingAtColumn(AnimeListWidgetModel::AL_EPISODES).data(Qt::UserRole).toReal()); int text_width = 59; QRectF text_rect(option.rect.x() + text_width, option.rect.y(), text_width, option.decorationSize.height()); painter->save(); painter->drawText(text_rect, "/", QTextOption(Qt::AlignCenter | Qt::AlignVCenter)); - // drawText(const QRectF &rectangle, const QString &text, const QTextOption &option = QTextOption()) - painter->drawText(QRectF(text_rect.x(), text_rect.y(), text_width / 2 - 2, text_rect.height()), - QString::number(progress), QTextOption(Qt::AlignRight | Qt::AlignVCenter)); - painter->drawText( - QRectF(text_rect.x() + text_width / 2 + 2, text_rect.y(), text_width / 2 - 2, text_rect.height()), - QString::number(episodes), QTextOption(Qt::AlignLeft | Qt::AlignVCenter)); - painter->restore(); - QStyledItemDelegate::paint(painter, option, index); - break; + // drawText(const QRectF &rectangle, const QString &text, const QTextOption &option = + QTextOption()) painter->drawText(QRectF(text_rect.x(), text_rect.y(), text_width / 2 - 2, + text_rect.height()), QString::number(progress), QTextOption(Qt::AlignRight | Qt::AlignVCenter)); + painter->drawText( + QRectF(text_rect.x() + text_width / 2 + 2, text_rect.y(), text_width / 2 - 2, text_rect.height()), + QString::number(episodes), QTextOption(Qt::AlignLeft | Qt::AlignVCenter)); + painter->restore(); + QStyledItemDelegate::paint(painter, option, index); + break; } -*/ +#endif default: QStyledItemDelegate::paint(painter, option, index); break; } } @@ -99,33 +98,33 @@ QVariant AnimeListWidgetModel::headerData(const int section, const Qt::Orientation orientation, const int role) const { if (role == Qt::DisplayRole) { switch (section) { - case AL_TITLE: return tr("Anime title"); - case AL_PROGRESS: return tr("Progress"); - case AL_EPISODES: return tr("Episodes"); - case AL_TYPE: return tr("Type"); - case AL_SCORE: return tr("Score"); - case AL_SEASON: return tr("Season"); - case AL_STARTED: return tr("Date started"); - case AL_COMPLETED: return tr("Date completed"); - case AL_NOTES: return tr("Notes"); - case AL_AVG_SCORE: return tr("Average score"); - case AL_UPDATED: return tr("Last updated"); - default: return {}; + case AL_TITLE: return tr("Anime title"); + case AL_PROGRESS: return tr("Progress"); + case AL_EPISODES: return tr("Episodes"); + case AL_TYPE: return tr("Type"); + case AL_SCORE: return tr("Score"); + case AL_SEASON: return tr("Season"); + case AL_STARTED: return tr("Date started"); + case AL_COMPLETED: return tr("Date completed"); + case AL_NOTES: return tr("Notes"); + case AL_AVG_SCORE: return tr("Average score"); + case AL_UPDATED: return tr("Last updated"); + default: return {}; } } else if (role == Qt::TextAlignmentRole) { switch (section) { - case AL_TITLE: - case AL_NOTES: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); - case AL_PROGRESS: - case AL_EPISODES: - case AL_TYPE: - case AL_SCORE: - case AL_AVG_SCORE: return QVariant(Qt::AlignCenter | Qt::AlignVCenter); - case AL_SEASON: - case AL_STARTED: - case AL_COMPLETED: - case AL_UPDATED: return QVariant(Qt::AlignRight | Qt::AlignVCenter); - default: return QAbstractListModel::headerData(section, orientation, role); + case AL_TITLE: + case AL_NOTES: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); + case AL_PROGRESS: + case AL_EPISODES: + case AL_TYPE: + case AL_SCORE: + case AL_AVG_SCORE: return QVariant(Qt::AlignCenter | Qt::AlignVCenter); + case AL_SEASON: + case AL_STARTED: + case AL_COMPLETED: + case AL_UPDATED: return QVariant(Qt::AlignRight | Qt::AlignVCenter); + default: return QAbstractListModel::headerData(section, orientation, role); } } return QAbstractListModel::headerData(section, orientation, role); @@ -136,56 +135,56 @@ return QVariant(); switch (role) { case Qt::DisplayRole: - switch (index.column()) { - case AL_TITLE: return QString::fromUtf8(list[index.row()].GetUserPreferredTitle().c_str()); - case AL_PROGRESS: - return QString::number(list[index.row()].GetUserProgress()) + "/" + QString::number(list[index.row()].GetEpisodes()); - case AL_EPISODES: return list[index.row()].GetEpisodes(); - case AL_SCORE: return list[index.row()].GetUserScore(); - case AL_TYPE: return QString::fromStdString(Translate::TranslateSeriesFormat(list[index.row()].GetFormat())); - case AL_SEASON: - return QString::fromStdString(Translate::TranslateSeriesSeason(list[index.row()].GetSeason())) + " " + - QString::number(list[index.row()].GetAirDate().GetYear()); - case AL_AVG_SCORE: return QString::number(list[index.row()].GetAudienceScore()) + "%"; - case AL_STARTED: return list[index.row()].GetUserDateStarted().GetAsQDate(); - case AL_COMPLETED: return list[index.row()].GetUserDateCompleted().GetAsQDate(); - case AL_UPDATED: { - if (list[index.row()].GetUserTimeUpdated() == 0) - return QString("-"); - Time::Duration duration(Time::GetSystemTime() - list[index.row()].GetUserTimeUpdated()); - return QString::fromUtf8(duration.AsRelativeString().c_str()); - } - case AL_NOTES: return QString::fromUtf8(list[index.row()].GetUserNotes().c_str()); - default: return ""; - } - break; + switch (index.column()) { + case AL_TITLE: return QString::fromUtf8(list[index.row()].GetUserPreferredTitle().c_str()); + case AL_PROGRESS: + return QString::number(list[index.row()].GetUserProgress()) + "/" + + QString::number(list[index.row()].GetEpisodes()); + case AL_EPISODES: return list[index.row()].GetEpisodes(); + case AL_SCORE: return list[index.row()].GetUserScore(); + case AL_TYPE: return QString::fromStdString(Translate::ToString(list[index.row()].GetFormat())); + case AL_SEASON: + return QString::fromStdString(Translate::ToString(list[index.row()].GetSeason())) + " " + + QString::number(list[index.row()].GetAirDate().GetYear()); + case AL_AVG_SCORE: return QString::number(list[index.row()].GetAudienceScore()) + "%"; + case AL_STARTED: return list[index.row()].GetUserDateStarted().GetAsQDate(); + case AL_COMPLETED: return list[index.row()].GetUserDateCompleted().GetAsQDate(); + case AL_UPDATED: { + if (list[index.row()].GetUserTimeUpdated() == 0) + return QString("-"); + Time::Duration duration(Time::GetSystemTime() - list[index.row()].GetUserTimeUpdated()); + return QString::fromUtf8(duration.AsRelativeString().c_str()); + } + case AL_NOTES: return QString::fromUtf8(list[index.row()].GetUserNotes().c_str()); + default: return ""; + } + break; case Qt::UserRole: - switch (index.column()) { - case AL_ID: return list[index.row()].GetId(); - case AL_PROGRESS: return list[index.row()].GetUserProgress(); - case AL_TYPE: return static_cast<int>(list[index.row()].GetFormat()); - case AL_SEASON: return list[index.row()].GetAirDate().GetAsQDate(); - case AL_AVG_SCORE: return list[index.row()].GetAudienceScore(); - case AL_UPDATED: return list[index.row()].GetUserTimeUpdated(); - default: return data(index, Qt::DisplayRole); - } - break; + switch (index.column()) { + case AL_PROGRESS: return list[index.row()].GetUserProgress(); + case AL_TYPE: return static_cast<int>(list[index.row()].GetFormat()); + case AL_SEASON: return list[index.row()].GetAirDate().GetAsQDate(); + case AL_AVG_SCORE: return list[index.row()].GetAudienceScore(); + case AL_UPDATED: return list[index.row()].GetUserTimeUpdated(); + default: return data(index, Qt::DisplayRole); + } + break; case Qt::TextAlignmentRole: - switch (index.column()) { - case AL_TITLE: - case AL_NOTES: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); - case AL_PROGRESS: - case AL_EPISODES: - case AL_TYPE: - case AL_SCORE: - case AL_AVG_SCORE: return QVariant(Qt::AlignCenter | Qt::AlignVCenter); - case AL_SEASON: - case AL_STARTED: - case AL_COMPLETED: - case AL_UPDATED: return QVariant(Qt::AlignRight | Qt::AlignVCenter); - default: break; - } - break; + switch (index.column()) { + case AL_TITLE: + case AL_NOTES: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); + case AL_PROGRESS: + case AL_EPISODES: + case AL_TYPE: + case AL_SCORE: + case AL_AVG_SCORE: return QVariant(Qt::AlignCenter | Qt::AlignVCenter); + case AL_SEASON: + case AL_STARTED: + case AL_COMPLETED: + case AL_UPDATED: return QVariant(Qt::AlignRight | Qt::AlignVCenter); + default: break; + } + break; } return QVariant(); } @@ -195,7 +194,7 @@ int i = 0; for (const auto& a : Anime::db.items) { if (a.second.IsInUserList() && a.first == id && a.second.GetUserStatus() == status) { - emit dataChanged(index(i), index(i)); + emit dataChanged(index(i), index(i)); } i++; } @@ -207,15 +206,28 @@ void AnimeListWidgetModel::RefreshList() { bool has_children = !!rowCount(index(0)); - if (has_children) beginResetModel(); + if (has_children) + beginResetModel(); + else { + int count = 0; + for (const auto& a : Anime::db.items) + if (a.second.IsInUserList() && a.second.GetUserStatus() == status) + count++; + beginInsertRows(index(0), 0, count - 1); + } + list.clear(); for (const auto& a : Anime::db.items) { if (a.second.IsInUserList() && a.second.GetUserStatus() == status) { - list.push_back(a.second); + list.push_back(a.second); } } - if (has_children) endResetModel(); + + if (has_children) + endResetModel(); + else + endInsertRows(); } int AnimeListWidget::VisibleColumnsCount() const { @@ -223,7 +235,7 @@ for (int i = 0, end = tree_view->header()->count(); i < end; i++) { if (!tree_view->isColumnHidden(i)) - count++; + count++; } return count; @@ -242,7 +254,6 @@ tree_view->setColumnHidden(AnimeListWidgetModel::AL_COMPLETED, true); tree_view->setColumnHidden(AnimeListWidgetModel::AL_UPDATED, true); tree_view->setColumnHidden(AnimeListWidgetModel::AL_NOTES, true); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_ID, true); } void AnimeListWidget::DisplayColumnHeaderMenu() { @@ -252,10 +263,10 @@ menu->setToolTipsVisible(true); for (int i = 0; i < AnimeListWidgetModel::NB_COLUMNS; i++) { - if (i == AnimeListWidgetModel::AL_TITLE || i == AnimeListWidgetModel::AL_ID) - continue; + if (i == AnimeListWidgetModel::AL_TITLE) + continue; const auto column_name = - sort_models[tab_bar->currentIndex()]->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); + sort_models[tab_bar->currentIndex()]->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); QAction* action = menu->addAction(column_name, this, [this, i](const bool checked) { if (!checked && (VisibleColumnsCount() <= 1)) return; @@ -288,26 +299,28 @@ menu->setTitle(tr("Column visibility")); menu->setToolTipsVisible(true); - const QItemSelection selection = sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection()); + const QItemSelection selection = + sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection()); if (!selection.indexes().first().isValid()) { return; } QAction* action = menu->addAction("Information", [this, selection] { const QModelIndex index = ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel()) - ->index(selection.indexes().first().row()); + ->index(selection.indexes().first().row()); Anime::Anime* anime = - ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index); + ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index); if (!anime) { return; } InformationDialog* dialog = new InformationDialog( - *anime, - [this, anime] { - ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->UpdateAnime(anime->GetId()); - }, - this); + *anime, + [this, anime] { + ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel()) + ->UpdateAnime(anime->GetId()); + }, + this); dialog->show(); dialog->raise(); @@ -319,22 +332,22 @@ void AnimeListWidget::ItemDoubleClicked() { /* throw out any other garbage */ const QItemSelection selection = - sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection()); + sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection()); if (!selection.indexes().first().isValid()) { return; } const QModelIndex index = ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel()) - ->index(selection.indexes().first().row()); + ->index(selection.indexes().first().row()); Anime::Anime* anime = - ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index); + ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index); InformationDialog* dialog = new InformationDialog( - *anime, - [this, anime] { - ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->UpdateAnime(anime->GetId()); - }, - this); + *anime, + [this, anime] { + ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->UpdateAnime(anime->GetId()); + }, + this); dialog->show(); dialog->raise(); @@ -424,14 +437,14 @@ tree_view->setFrameShape(QFrame::NoFrame); for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++) { - tab_bar->addTab(QString::fromStdString(Translate::TranslateListStatus(Anime::ListStatuses[i])) + " (" + QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")"); + tab_bar->addTab(QString::fromStdString(Translate::ToString(Anime::ListStatuses[i])) + " (" + + QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")"); sort_models[i] = new AnimeListWidgetSortFilter(tree_view); - AnimeListWidgetModel* model = new AnimeListWidgetModel(this, Anime::ListStatuses[i]); - new QAbstractItemModelTester(model, QAbstractItemModelTester::FailureReportingMode::Fatal, this); - sort_models[i]->setSourceModel(model); + sort_models[i]->setSourceModel(new AnimeListWidgetModel(this, Anime::ListStatuses[i])); sort_models[i]->setSortRole(Qt::UserRole); sort_models[i]->setSortCaseSensitivity(Qt::CaseInsensitive); } + tree_view->setModel(sort_models[0]); QHBoxLayout* layout = new QHBoxLayout; layout->addWidget(tree_view); @@ -443,16 +456,15 @@ connect(tree_view, &QWidget::customContextMenuRequested, this, &AnimeListWidget::DisplayListMenu); /* Enter & return keys */ - connect(new QShortcut(Qt::Key_Return, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, - this, &AnimeListWidget::ItemDoubleClicked); + connect(new QShortcut(Qt::Key_Return, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this, + &AnimeListWidget::ItemDoubleClicked); - connect(new QShortcut(Qt::Key_Enter, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, - this, &AnimeListWidget::ItemDoubleClicked); + connect(new QShortcut(Qt::Key_Enter, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this, + &AnimeListWidget::ItemDoubleClicked); tree_view->header()->setStretchLastSection(false); tree_view->header()->setContextMenuPolicy(Qt::CustomContextMenu); - connect(tree_view->header(), &QWidget::customContextMenuRequested, this, - &AnimeListWidget::DisplayColumnHeaderMenu); + connect(tree_view->header(), &QWidget::customContextMenuRequested, this, &AnimeListWidget::DisplayColumnHeaderMenu); connect(tab_bar, &QTabBar::currentChanged, this, [this](int index) { if (sort_models[index]) @@ -464,11 +476,24 @@ } void AnimeListWidget::RefreshList() { - for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++) { + for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++) ((AnimeListWidgetModel*)sort_models[i]->sourceModel())->RefreshList(); - } } +void AnimeListWidget::RefreshTabs() { + for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++) + tab_bar->setTabText(i, QString::fromStdString(Translate::ToString(Anime::ListStatuses[i])) + " (" + + QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")"); +} + +void AnimeListWidget::Refresh() { + RefreshList(); + RefreshTabs(); +} + +/* This function, really, really should not be called. + Ever. Why would you ever need to clear the anime list? + Also, this sucks. */ void AnimeListWidget::Reset() { while (tab_bar->count()) tab_bar->removeTab(0);
--- a/src/gui/pages/statistics.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/pages/statistics.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -1,8 +1,8 @@ #include "gui/pages/statistics.h" +#include "core/anime_db.h" +#include "core/session.h" #include "gui/pages/anime_list.h" #include "gui/ui_utils.h" -#include "core/session.h" -#include "core/anime_db.h" #include <QString> #include <QTextDocument> #include <QTextStream> @@ -18,13 +18,13 @@ setFrameShadow(QFrame::Sunken); UiUtils::LabelledTextParagraph* anime_list_paragraph = new UiUtils::LabelledTextParagraph( - "Anime list", - "Anime count:\nEpisode count:\nTime spent watching:\nTime to complete:\nAverage score:\nScore deviation:", "", - this); + "Anime list", + "Anime count:\nEpisode count:\nTime spent watching:\nTime to complete:\nAverage score:\nScore deviation:", "\n\n\n\n\n", + this); anime_list_data = anime_list_paragraph->GetParagraph(); UiUtils::LabelledTextParagraph* application_paragraph = - new UiUtils::LabelledTextParagraph("Minori", "Uptime:", "", this); + new UiUtils::LabelledTextParagraph("Minori", "Uptime:", "", this); application_data = application_paragraph->GetParagraph(); layout()->addWidget(anime_list_paragraph); @@ -49,9 +49,11 @@ } /* me abusing macros :) */ -#define ADD_TIME_SEGMENT(r, x, s, p) { \ - if (x > 0) \ - r << x << ((x == 1) ? s : p); } +#define ADD_TIME_SEGMENT(r, x, s, p) \ + { \ + if (x > 0) \ + r << x << ((x == 1) ? s : p); \ + } std::string StatisticsWidget::MinutesToDateString(int minutes) { /* ew */ int years = (minutes * (1 / 525949.2F)); @@ -76,7 +78,8 @@ int days = sec * (1 / 86400.0F) - (years * 365.2425F) - (months * 30.436875F); int hours = sec * (1 / 3600.0F) - (years * 8765.82F) - (months * 730.485F) - (days * 24); int minutes = (sec) * (1 / 60.0F) - (years * 525949.2F) - (months * 43829.1F) - (days * 1440.0F) - (hours * 60.0F); - int seconds = sec - (years * 31556952.0F) - (months * 2629746.0F) - (days * 86400.0F) - (hours * 3600.0F) - (minutes * 60.0F); + int seconds = + sec - (years * 31556952.0F) - (months * 2629746.0F) - (days * 86400.0F) - (hours * 3600.0F) - (minutes * 60.0F); std::ostringstream return_stream; ADD_TIME_SEGMENT(return_stream, years, " year ", " years "); ADD_TIME_SEGMENT(return_stream, months, " month ", " months ");
--- a/src/gui/sidebar.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/sidebar.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -16,7 +16,7 @@ viewport()->setAutoFillBackground(false); setStyleSheet("font-size: 12px"); connect(this, &QListWidget::currentRowChanged, this, - [this](int index) { emit CurrentItemChanged(RemoveSeparatorsFromIndex(index)); }); + [this](int index) { emit CurrentItemChanged(RemoveSeparatorsFromIndex(index)); }); } QListWidgetItem* SideBar::AddItem(QString name, QIcon icon) { @@ -61,7 +61,8 @@ return !(index.isValid() && index.flags() & Qt::ItemIsEnabled); } -QItemSelectionModel::SelectionFlags SideBar::selectionCommand(const QModelIndex& index, const QEvent*) const { +QItemSelectionModel::SelectionFlags SideBar::selectionCommand(const QModelIndex& index, + const QEvent*) const { if (IndexIsSeparator(index)) return QItemSelectionModel::NoUpdate; return QItemSelectionModel::ClearAndSelect;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/translate/anilist.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -0,0 +1,51 @@ +#include "gui/translate/anilist.h" + +namespace Translate::AniList { + +Anime::SeriesStatus ToSeriesStatus(std::string status) { + std::unordered_map<std::string, Anime::SeriesStatus> map = { + {"FINISHED", Anime::SeriesStatus::FINISHED }, + {"RELEASING", Anime::SeriesStatus::RELEASING }, + {"NOT_YET_RELEASED", Anime::SeriesStatus::NOT_YET_RELEASED}, + {"CANCELLED", Anime::SeriesStatus::CANCELLED }, + {"HIATUS", Anime::SeriesStatus::HIATUS } + }; + + if (!map.contains(status)) + return Anime::SeriesStatus::UNKNOWN; + return map[status]; +} + +Anime::SeriesSeason ToSeriesSeason(std::string season) { + std::unordered_map<std::string, Anime::SeriesSeason> map = { + {"WINTER", Anime::SeriesSeason::WINTER}, + {"SPRING", Anime::SeriesSeason::SPRING}, + {"SUMMER", Anime::SeriesSeason::SUMMER}, + {"FALL", Anime::SeriesSeason::FALL } + }; + + if (!map.contains(season)) + return Anime::SeriesSeason::UNKNOWN; + return map[season]; +} + +Anime::SeriesFormat ToSeriesFormat(std::string format) { + std::unordered_map<std::string, enum Anime::SeriesFormat> map = { + {"TV", Anime::SeriesFormat::TV }, + {"TV_SHORT", Anime::SeriesFormat::TV_SHORT}, + {"MOVIE", Anime::SeriesFormat::MOVIE }, + {"SPECIAL", Anime::SeriesFormat::SPECIAL }, + {"OVA", Anime::SeriesFormat::OVA }, + {"ONA", Anime::SeriesFormat::ONA }, + {"MUSIC", Anime::SeriesFormat::MUSIC }, + {"MANGA", Anime::SeriesFormat::MANGA }, + {"NOVEL", Anime::SeriesFormat::NOVEL }, + {"ONE_SHOT", Anime::SeriesFormat::ONE_SHOT} + }; + + if (!map.contains(format)) + return Anime::SeriesFormat::UNKNOWN; + return map[format]; +} + +} // namespace Translate::AniList \ No newline at end of file
--- a/src/gui/translate/anime.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/translate/anime.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -1,8 +1,9 @@ #include "core/anime.h" +#include "gui/translate/anime.h" namespace Translate { -std::string TranslateListStatus(const Anime::ListStatus status) { +std::string ToString(const Anime::ListStatus status) { switch (status) { case Anime::ListStatus::NOT_IN_LIST: return "Not in list"; case Anime::ListStatus::CURRENT: return "Currently watching"; @@ -14,7 +15,7 @@ } } -std::string TranslateSeriesFormat(const Anime::SeriesFormat format) { +std::string ToString(const Anime::SeriesFormat format) { switch (format) { case Anime::SeriesFormat::UNKNOWN: return "Unknown"; case Anime::SeriesFormat::TV: return "TV"; @@ -28,7 +29,7 @@ } } -std::string TranslateSeriesSeason(const Anime::SeriesSeason season) { +std::string ToString(const Anime::SeriesSeason season) { switch (season) { case Anime::SeriesSeason::UNKNOWN: return "Unknown"; case Anime::SeriesSeason::WINTER: return "Winter"; @@ -39,7 +40,7 @@ } } -std::string TranslateSeriesStatus(const Anime::SeriesStatus status) { +std::string ToString(const Anime::SeriesStatus status) { switch (status) { case Anime::SeriesStatus::UNKNOWN: return "Unknown"; case Anime::SeriesStatus::RELEASING: return "Currently airing";
--- a/src/gui/ui_utils.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/ui_utils.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -10,9 +10,9 @@ #include <QTextBlock> #include <QVBoxLayout> #ifdef MACOSX -#include "sys/osx/dark_theme.h" +# include "sys/osx/dark_theme.h" #else -#include "sys/win32/dark_theme.h" +# include "sys/win32/dark_theme.h" #endif namespace UiUtils { @@ -98,8 +98,9 @@ return paragraph; } -LabelledTextParagraph::LabelledTextParagraph(QString title, QString label, QString data, QWidget* parent) - : QWidget(parent) { +LabelledTextParagraph::LabelledTextParagraph(QString title, QString label, QString data, + QWidget* parent) + : QWidget(parent) { setLayout(new QVBoxLayout); header = new Header(title, this); @@ -107,13 +108,13 @@ // this is not accessible from the object because there's really // no reason to make it accessible... QWidget* content = new QWidget(this); - content->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + content->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); labels = new Paragraph(label, this); labels->setTextInteractionFlags(Qt::NoTextInteraction); labels->setAttribute(Qt::WidgetAttribute::WA_TransparentForMouseEvents); labels->setWordWrapMode(QTextOption::NoWrap); - labels->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + labels->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); labels->setFixedWidth(123); paragraph = new Paragraph(data, this); @@ -148,7 +149,8 @@ return paragraph; } -SelectableTextParagraph::SelectableTextParagraph(QString title, QString data, QWidget* parent) : QWidget(parent) { +SelectableTextParagraph::SelectableTextParagraph(QString title, QString data, QWidget* parent) + : QWidget(parent) { setLayout(new QVBoxLayout); header = new Header(title, this); @@ -199,8 +201,8 @@ QSize Paragraph::minimumSizeHint() const { QTextDocument* doc = document(); long h = (long)(blockBoundingGeometry(doc->findBlockByNumber(doc->blockCount() - 1)).bottom() + - (2 * doc->documentMargin())); - return QSize(QPlainTextEdit::sizeHint().width(), (long)h); + (2 * doc->documentMargin())); + return QSize(QPlainTextEdit::sizeHint().width(), h); } QSize Paragraph::sizeHint() const {
--- a/src/gui/window.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/gui/window.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -1,13 +1,13 @@ #include "gui/window.h" #include "core/config.h" #include "core/session.h" -#include "services/services.h" #include "gui/dialog/settings.h" #include "gui/pages/anime_list.h" #include "gui/pages/now_playing.h" #include "gui/pages/statistics.h" #include "gui/sidebar.h" #include "gui/ui_utils.h" +#include "services/services.h" #include <QApplication> #include <QFile> #include <QMainWindow> @@ -16,15 +16,11 @@ #include <QStackedWidget> #include <QTextStream> #if MACOSX -#include "sys/osx/dark_theme.h" +# include "sys/osx/dark_theme.h" #elif WIN32 -#include "sys/win32/dark_theme.h" +# include "sys/win32/dark_theme.h" #endif -/* note that this code was originally created for use in - wxWidgets, but I thought the API was a little meh, so - I switched to Qt. */ - enum class Pages { NOW_PLAYING, @@ -86,7 +82,7 @@ menu = menubar->addMenu("&Services"); action = menu->addAction("Synchronize &list", [this, stack] { Services::Synchronize(); - ((AnimeListWidget*)stack->widget((int)Pages::ANIME_LIST))->RefreshList(); + ((AnimeListWidget*)stack->widget((int)Pages::ANIME_LIST))->Refresh(); }); menu->addSeparator();
--- a/src/services/anilist.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/services/anilist.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -5,6 +5,7 @@ #include "core/json.h" #include "core/session.h" #include "core/strings.h" +#include "gui/translate/anilist.h" #include <QDesktopServices> #include <QInputDialog> #include <QLineEdit> @@ -16,20 +17,24 @@ #include <format> #define CLIENT_ID "13706" -using nlohmann::literals::operator "" _json_pointer; +using nlohmann::literals::operator"" _json_pointer; namespace Services::AniList { class Account { public: std::string Username() const { return session.config.anilist.username; } - void SetUsername(std::string const& username) { session.config.anilist.username = username; } + void SetUsername(std::string const& username) { + session.config.anilist.username = username; + } int UserId() const { return session.config.anilist.user_id; } void SetUserId(const int id) { session.config.anilist.user_id = id; } std::string AuthToken() const { return session.config.anilist.auth_token; } - void SetAuthToken(std::string const& auth_token) { session.config.anilist.auth_token = auth_token; } + void SetAuthToken(std::string const& auth_token) { + session.config.anilist.auth_token = auth_token; + } bool Authenticated() const { return !AuthToken().empty(); } }; @@ -47,9 +52,9 @@ std::string userdata; CURL* curl = curl_easy_init(); if (curl) { + std::string bearer = "Authorization: Bearer " + account.AuthToken(); list = curl_slist_append(list, "Accept: application/json"); list = curl_slist_append(list, "Content-Type: application/json"); - std::string bearer = "Authorization: Bearer " + account.AuthToken(); list = curl_slist_append(list, bearer.c_str()); curl_easy_setopt(curl, CURLOPT_URL, "https://graphql.anilist.co"); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); @@ -63,7 +68,8 @@ curl_easy_cleanup(curl); if (res != CURLE_OK) { QMessageBox box(QMessageBox::Icon::Critical, "", - QString("curl_easy_perform(curl) failed!: ") + QString(curl_easy_strerror(res))); + QString("curl_easy_perform(curl) failed!: ") + + QString(curl_easy_strerror(res))); box.exec(); return ""; } @@ -72,52 +78,45 @@ return ""; } -/* TODO: Move to Translate */ +void ParseListStatus(std::string status, Anime::Anime& anime) { + std::unordered_map<std::string, Anime::ListStatus> map = { + {"CURRENT", Anime::ListStatus::CURRENT }, + {"PLANNING", Anime::ListStatus::PLANNING }, + {"COMPLETED", Anime::ListStatus::COMPLETED}, + {"DROPPED", Anime::ListStatus::DROPPED }, + {"PAUSED", Anime::ListStatus::PAUSED } + }; -std::map<std::string, Anime::ListStatus> AniListStringToAnimeWatchingMap = { - {"CURRENT", Anime::ListStatus::CURRENT }, - {"PLANNING", Anime::ListStatus::PLANNING }, - {"COMPLETED", Anime::ListStatus::COMPLETED}, - {"DROPPED", Anime::ListStatus::DROPPED }, - {"PAUSED", Anime::ListStatus::PAUSED }, - {"REPEATING", Anime::ListStatus::CURRENT} -}; + if (status == "REPEATING") { + anime.SetUserIsRewatching(true); + anime.SetUserStatus(Anime::ListStatus::CURRENT); + return; + } -std::map<Anime::ListStatus, std::string> AniListAnimeWatchingToStringMap = { - {Anime::ListStatus::CURRENT, "CURRENT" }, - {Anime::ListStatus::PLANNING, "PLANNING" }, - {Anime::ListStatus::COMPLETED, "COMPLETED"}, - {Anime::ListStatus::DROPPED, "DROPPED" }, - {Anime::ListStatus::PAUSED, "PAUSED" } -}; + if (!map.contains(status)) { + anime.SetUserStatus(Anime::ListStatus::NOT_IN_LIST); + return; + } -std::map<std::string, Anime::SeriesStatus> AniListStringToAnimeAiringMap = { - {"FINISHED", Anime::SeriesStatus::FINISHED }, - {"RELEASING", Anime::SeriesStatus::RELEASING }, - {"NOT_YET_RELEASED", Anime::SeriesStatus::NOT_YET_RELEASED}, - {"CANCELLED", Anime::SeriesStatus::CANCELLED }, - {"HIATUS", Anime::SeriesStatus::HIATUS } -}; + anime.SetUserStatus(map[status]); +} -std::map<std::string, Anime::SeriesSeason> AniListStringToAnimeSeasonMap = { - {"WINTER", Anime::SeriesSeason::WINTER}, - {"SPRING", Anime::SeriesSeason::SPRING}, - {"SUMMER", Anime::SeriesSeason::SUMMER}, - {"FALL", Anime::SeriesSeason::FALL } -}; +std::string ListStatusToString(const Anime::Anime& anime) { + std::unordered_map<Anime::ListStatus, std::string> map = { + {Anime::ListStatus::CURRENT, "CURRENT" }, + {Anime::ListStatus::PLANNING, "PLANNING" }, + {Anime::ListStatus::COMPLETED, "COMPLETED"}, + {Anime::ListStatus::DROPPED, "DROPPED" }, + {Anime::ListStatus::PAUSED, "PAUSED" } + }; -std::map<std::string, enum Anime::SeriesFormat> AniListStringToAnimeFormatMap = { - {"TV", Anime::SeriesFormat::TV }, - {"TV_SHORT", Anime::SeriesFormat::TV_SHORT}, - {"MOVIE", Anime::SeriesFormat::MOVIE }, - {"SPECIAL", Anime::SeriesFormat::SPECIAL }, - {"OVA", Anime::SeriesFormat::OVA }, - {"ONA", Anime::SeriesFormat::ONA }, - {"MUSIC", Anime::SeriesFormat::MUSIC }, - {"MANGA", Anime::SeriesFormat::MANGA }, - {"NOVEL", Anime::SeriesFormat::NOVEL }, - {"ONE_SHOT", Anime::SeriesFormat::ONE_SHOT} -}; + if (anime.GetUserIsRewatching()) + return "REWATCHING"; + + if (!map.contains(anime.GetUserStatus())) + return "CURRENT"; + return map[anime.GetUserStatus()]; +} Date ParseDate(const nlohmann::json& json) { Date date; @@ -154,14 +153,14 @@ ParseTitle(json.at("/title"_json_pointer), anime); anime.SetEpisodes(JSON::GetInt(json, "/episodes"_json_pointer)); - anime.SetFormat(AniListStringToAnimeFormatMap[JSON::GetString(json, "/format"_json_pointer)]); + anime.SetFormat(Translate::AniList::ToSeriesFormat(JSON::GetString(json, "/format"_json_pointer))); - anime.SetAiringStatus(AniListStringToAnimeAiringMap[JSON::GetString(json, "/status"_json_pointer)]); + anime.SetAiringStatus(Translate::AniList::ToSeriesStatus(JSON::GetString(json, "/status"_json_pointer))); anime.SetAirDate(ParseDate(json["/startDate"_json_pointer])); anime.SetAudienceScore(JSON::GetInt(json, "/averageScore"_json_pointer)); - anime.SetSeason(AniListStringToAnimeSeasonMap[JSON::GetString(json, "/season"_json_pointer)]); + anime.SetSeason(Translate::AniList::ToSeriesSeason(JSON::GetString(json, "/season"_json_pointer))); anime.SetDuration(JSON::GetInt(json, "/duration"_json_pointer)); anime.SetSynopsis(Strings::TextifySynopsis(JSON::GetString(json, "/description"_json_pointer))); @@ -181,7 +180,7 @@ anime.SetUserScore(JSON::GetInt(json, "/score"_json_pointer)); anime.SetUserProgress(JSON::GetInt(json, "/progress"_json_pointer)); - anime.SetUserStatus(AniListStringToAnimeWatchingMap[JSON::GetString(json, "/status"_json_pointer)]); + ParseListStatus(JSON::GetString(json, "/status"_json_pointer), anime); anime.SetUserNotes(JSON::GetString(json, "/notes"_json_pointer)); anime.SetUserDateStarted(ParseDate(json["/startedAt"_json_pointer])); @@ -202,51 +201,51 @@ int GetAnimeList() { /* NOTE: these should be in the qrc file */ const std::string query = "query ($id: Int) {\n" - " MediaListCollection (userId: $id, type: ANIME) {\n" - " lists {\n" - " name\n" - " entries {\n" - " score\n" - " notes\n" - " status\n" - " progress\n" - " startedAt {\n" - " year\n" - " month\n" - " day\n" - " }\n" - " completedAt {\n" - " year\n" - " month\n" - " day\n" - " }\n" - " updatedAt\n" - " media {\n" - " id\n" - " title {\n" - " romaji\n" - " english\n" - " native\n" - " }\n" - " format\n" - " status\n" - " averageScore\n" - " season\n" - " startDate {\n" - " year\n" - " month\n" - " day\n" - " }\n" - " genres\n" - " episodes\n" - " duration\n" - " synonyms\n" - " description(asHtml: false)\n" - " }\n" - " }\n" - " }\n" - " }\n" - "}\n"; + " MediaListCollection (userId: $id, type: ANIME) {\n" + " lists {\n" + " name\n" + " entries {\n" + " score\n" + " notes\n" + " status\n" + " progress\n" + " startedAt {\n" + " year\n" + " month\n" + " day\n" + " }\n" + " completedAt {\n" + " year\n" + " month\n" + " day\n" + " }\n" + " updatedAt\n" + " media {\n" + " id\n" + " title {\n" + " romaji\n" + " english\n" + " native\n" + " }\n" + " format\n" + " status\n" + " averageScore\n" + " season\n" + " startDate {\n" + " year\n" + " month\n" + " day\n" + " }\n" + " genres\n" + " episodes\n" + " duration\n" + " synonyms\n" + " description(asHtml: false)\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}\n"; // clang-format off nlohmann::json json = { {"query", query}, @@ -269,7 +268,7 @@ int UpdateAnimeEntry(const Anime::Anime& anime) { /** * possible values: - * + * * int mediaId, * MediaListStatus status, * float score, @@ -285,21 +284,22 @@ * float[] advancedScores, * Date startedAt, * Date completedAt - **/ - const std::string query = - "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String) {\n" - " SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score, notes: " - "$notes) {\n" - " id\n" - " }\n" - "}\n"; + **/ + const std::string query = "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, " + "$score: Int, $notes: String) {\n" + " SaveMediaListEntry (mediaId: $media_id, progress: $progress, " + "status: $status, scoreRaw: $score, notes: " + "$notes) {\n" + " id\n" + " }\n" + "}\n"; // clang-format off nlohmann::json json = { {"query", query}, {"variables", { {"media_id", anime.GetId()}, {"progress", anime.GetUserProgress()}, - {"status", AniListAnimeWatchingToStringMap[anime.GetUserStatus()]}, + {"status", ListStatusToString(anime)}, {"score", anime.GetUserScore()}, {"notes", anime.GetUserNotes()} }} @@ -317,29 +317,29 @@ int AuthorizeUser() { /* Prompt for PIN */ - QDesktopServices::openUrl( - QUrl("https://anilist.co/api/v2/oauth/authorize?client_id=" CLIENT_ID "&response_type=token")); + QDesktopServices::openUrl(QUrl("https://anilist.co/api/v2/oauth/authorize?client_id=" CLIENT_ID + "&response_type=token")); bool ok; QString token = QInputDialog::getText( - 0, "Credentials needed!", "Please enter the code given to you after logging in to AniList:", QLineEdit::Normal, - "", &ok); + 0, "Credentials needed!", + "Please enter the code given to you after logging in to AniList:", QLineEdit::Normal, "", + &ok); if (ok && !token.isEmpty()) account.SetAuthToken(token.toStdString()); - else { // fail + else // fail return 0; - } const std::string query = "query {\n" - " Viewer {\n" - " id\n" - " name\n" - " mediaListOptions {\n" - " scoreFormat\n" - " }\n" - " }\n" - "}\n"; + " Viewer {\n" + " id\n" + " name\n" + " mediaListOptions {\n" + " scoreFormat\n" + " }\n" + " }\n" + "}\n"; nlohmann::json json = { - {"query", query} - }; + {"query", query} + }; auto ret = nlohmann::json::parse(SendRequest(json.dump())); ParseUser(json["Viewer"]); return 1;
--- a/src/services/services.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/services/services.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -1,6 +1,6 @@ +#include "services/services.h" #include "core/session.h" #include "services/anilist.h" -#include "services/services.h" namespace Services {
--- a/src/sys/osx/dark_theme.mm Tue Sep 19 16:33:07 2023 -0400 +++ b/src/sys/osx/dark_theme.mm Tue Sep 19 22:36:08 2023 -0400 @@ -12,10 +12,8 @@ bool IsInDarkTheme() { if (@available(macOS 10.14, *)) { - auto appearance = - [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:@[ - NSAppearanceNameAqua, NSAppearanceNameDarkAqua - ]]; + auto appearance = [NSApp.effectiveAppearance + bestMatchFromAppearancesWithNames:@[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]]; return [appearance isEqualToString:NSAppearanceNameDarkAqua]; } return false; @@ -24,16 +22,14 @@ void SetToDarkTheme() { // https://stackoverflow.com/questions/55925862/how-can-i-set-my-os-x-application-theme-in-code if (@available(macOS 10.14, *)) { - [NSApp setAppearance:[NSAppearance - appearanceNamed:NSAppearanceNameDarkAqua]]; + [NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]]; } } void SetToLightTheme() { // https://stackoverflow.com/questions/55925862/how-can-i-set-my-os-x-application-theme-in-code if (__builtin_available(macOS 10.14, *)) { - [NSApp - setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]]; + [NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]]; } }
--- a/src/sys/osx/filesystem.mm Tue Sep 19 16:33:07 2023 -0400 +++ b/src/sys/osx/filesystem.mm Tue Sep 19 22:36:08 2023 -0400 @@ -4,9 +4,8 @@ namespace osx { std::string GetApplicationSupportDirectory() { - NSArray* strings = NSSearchPathForDirectoriesInDomains( - NSApplicationSupportDirectory, NSUserDomainMask, true); + NSArray* strings = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, true); return std::string([[strings objectAtIndex:0] UTF8String]); } -} // namespace osx \ No newline at end of file +} // namespace osx
--- a/src/sys/win32/dark_theme.cpp Tue Sep 19 16:33:07 2023 -0400 +++ b/src/sys/win32/dark_theme.cpp Tue Sep 19 22:36:08 2023 -0400 @@ -17,10 +17,8 @@ } bool IsInDarkTheme() { - QSettings settings("HKEY_CURRENT_" - "USER\\Software\\Microsoft\\Windows\\CurrentVersion\\The" - "mes\\Personalize", - QSettings::NativeFormat); + QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", + QSettings::NativeFormat); return settings.value("AppsUseLightTheme", 1).toInt() == 0; }