Mercurial > minori
changeset 64:fe719c109dbc
*: update
1. add media tracking ability, and it displays info on the `now playing` page
2. the `now playing` page now actually shows something
3. renamed every page class to be more accurate to what it is
4. ...
line wrap: on
line diff
--- a/CMakeLists.txt Sun Oct 01 06:39:47 2023 -0400 +++ b/CMakeLists.txt Sun Oct 01 23:15:43 2023 -0400 @@ -7,8 +7,15 @@ enable_language(OBJCXX) endif() +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") + +option(BUILD_SHARED_LIBS "Build using shared libraries" ON) +option(USE_QT6 "Build with Qt 6 instead of Qt 5" OFF) + add_subdirectory(dep/anitomy) -# add_subdirectory(dep/animia) +add_subdirectory(dep/animia) add_subdirectory(dep/pugixml) # Fix for mingw64 @@ -24,6 +31,7 @@ set(LIBRARIES ${CURL_LIBRARIES} anitomy + animia ) if(USE_QT6) @@ -67,6 +75,7 @@ # Custom widgets + src/gui/widgets/anime_info.cpp src/gui/widgets/sidebar.cpp src/gui/widgets/text.cpp src/gui/widgets/optional_date.cpp @@ -86,6 +95,9 @@ src/services/services.cpp src/services/anilist.cpp + # Tracking + src/track/media.cpp + # Qt resources rc/icons.qrc dep/darkstyle/darkstyle.qrc @@ -105,13 +117,13 @@ set_property(TARGET minori PROPERTY AUTOMOC ON) set_property(TARGET minori PROPERTY AUTORCC ON) -target_include_directories(minori PUBLIC ${CURL_INCLUDE_DIRS} PRIVATE include dep/pugixml/src dep/animia/include) +target_include_directories(minori PUBLIC ${CURL_INCLUDE_DIRS} PRIVATE include dep/pugixml/src dep/animia/include dep/anitomy) if(USE_QT6) target_include_directories(minori PUBLIC ${Qt6Widgets_INCLUDE_DIRS}) else() target_include_directories(minori PUBLIC ${Qt5Widgets_INCLUDE_DIRS}) endif() -target_compile_options(minori PRIVATE -Wall -Wpedantic -Wextra -Wsuggest-override) +target_compile_options(minori PRIVATE -Wall -Wpedantic -Wextra -Wsuggest-override -Wold-style-cast) if(APPLE) target_compile_definitions(minori PUBLIC MACOSX) elseif(WIN32)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dep/animia/.clang-format Sun Oct 01 23:15:43 2023 -0400 @@ -0,0 +1,30 @@ +--- +BasedOnStyle: LLVM +UseTab: ForIndentation +PointerAlignment: Left +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +AccessModifierOffset: 4 + +IndentCaseLabels: true +IndentAccessModifiers: true +IndentPPDirectives: AfterHash + +BreakBeforeBraces: Attach +BreakStringLiterals: true + +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Left +AlignEscapedNewlines: DontAlign +AlignConsecutiveMacros: true + +AllowShortIfStatementsOnASingleLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortCaseLabelsOnASingleLine: true + +--- +Language: Cpp +Standard: Cpp11
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dep/animia/.hgignore Sun Oct 01 23:15:43 2023 -0400 @@ -0,0 +1,40 @@ +syntax: glob + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +syntax: regexp + +# Build dir +^build/ +^test/build/ \ No newline at end of file
--- a/dep/animia/CMakeLists.txt Sun Oct 01 06:39:47 2023 -0400 +++ b/dep/animia/CMakeLists.txt Sun Oct 01 23:15:43 2023 -0400 @@ -11,10 +11,14 @@ list(APPEND SRC_FILES src/win32.cpp) endif() add_library(animia SHARED ${SRC_FILES}) -set_target_properties(animia PROPERTIES - PUBLIC_HEADER animia/animia.h CXX_STANDARD 17) +set_target_properties(animia PROPERTIES CXX_STANDARD 17) target_include_directories(animia PRIVATE include) +install(TARGETS animia + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) + if(BUILD_TESTS) project(test LANGUAGES CXX) add_executable(test test/main.cpp)
--- a/dep/animia/test/CMakeLists.txt Sun Oct 01 06:39:47 2023 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -add_subdirectory(.. ${CMAKE_CURRENT_BINARY_DIR}/animia) -project(test LANGUAGES CXX) -add_executable(test main.cpp) - -target_include_directories(test PUBLIC ../include) \ No newline at end of file
--- a/include/core/anime_db.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/core/anime_db.h Sun Oct 01 23:15:43 2023 -0400 @@ -2,6 +2,7 @@ #define __core__anime_db_h #include "core/anime.h" #include <unordered_map> +#include <string> namespace Anime { @@ -15,6 +16,7 @@ double GetAverageScore(); double GetScoreDeviation(); int GetListsAnimeAmount(ListStatus status); + int GetAnimeFromTitle(std::string title); }; extern Database db;
--- a/include/core/json.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/core/json.h Sun Oct 01 23:15:43 2023 -0400 @@ -1,10 +1,15 @@ #ifndef __core__json_h #define __core__json_h + #include "../../dep/json/json.h" + namespace JSON { + std::string GetString(nlohmann::json const& json, nlohmann::json::json_pointer const& ptr, std::string def = ""); int GetInt(nlohmann::json const& json, nlohmann::json::json_pointer const& ptr, int def = 0); bool GetBoolean(nlohmann::json const& json, nlohmann::json::json_pointer const& ptr, bool def = false); double GetDouble(nlohmann::json const& json, nlohmann::json::json_pointer const& ptr, double def = 0); + } // namespace JSON + #endif // __core__json_h \ No newline at end of file
--- a/include/core/strings.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/core/strings.h Sun Oct 01 23:15:43 2023 -0400 @@ -4,6 +4,8 @@ #include <string> #include <vector> +class QString; + namespace Strings { /* Implode function: takes a vector of strings and turns it @@ -22,7 +24,11 @@ std::string ToLower(const std::string& string); std::wstring ToWstring(const std::string& string); +std::wstring ToWstring(const QString& string); std::string ToUtf8String(const std::wstring& wstring); +std::string ToUtf8String(const QString& string); +QString ToQString(const std::string& string); +QString ToQString(const std::wstring& wstring); }; // namespace Strings #endif // __core__strings_h \ No newline at end of file
--- a/include/gui/pages/anime_list.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/gui/pages/anime_list.h Sun Oct 01 23:15:43 2023 -0400 @@ -8,27 +8,27 @@ #include <QWidget> #include <vector> -class AnimeListWidgetDelegate : public QStyledItemDelegate { +class AnimeListPageDelegate : public QStyledItemDelegate { Q_OBJECT public: - explicit AnimeListWidgetDelegate(QObject* parent); + explicit AnimeListPageDelegate(QObject* parent); QWidget* createEditor(QWidget*, const QStyleOptionViewItem&, const QModelIndex&) const override; void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; }; -class AnimeListWidgetSortFilter : public QSortFilterProxyModel { +class AnimeListPageSortFilter : public QSortFilterProxyModel { Q_OBJECT public: - AnimeListWidgetSortFilter(QObject* parent = nullptr); + AnimeListPageSortFilter(QObject* parent = nullptr); protected: bool lessThan(const QModelIndex& l, const QModelIndex& r) const override; }; -class AnimeListWidgetModel : public QAbstractListModel { +class AnimeListPageModel : public QAbstractListModel { Q_OBJECT public: @@ -48,8 +48,8 @@ NB_COLUMNS }; - AnimeListWidgetModel(QWidget* parent, Anime::ListStatus _status); - ~AnimeListWidgetModel() override = default; + AnimeListPageModel(QWidget* parent, Anime::ListStatus _status); + ~AnimeListPageModel() override = default; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; @@ -65,11 +65,11 @@ /* todo: rename these to "page" or something more sensible than "widget" */ -class AnimeListWidget : public QWidget { +class AnimeListPage : public QWidget { Q_OBJECT public: - AnimeListWidget(QWidget* parent); + AnimeListPage(QWidget* parent); void Refresh(); void Reset(); @@ -94,6 +94,6 @@ QTabBar* tab_bar; QTreeView* tree_view; QRect panelRect; - AnimeListWidgetSortFilter* sort_models[5]; + AnimeListPageSortFilter* sort_models[5]; }; #endif // __gui__pages__anime_list_h \ No newline at end of file
--- a/include/gui/pages/history.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/gui/pages/history.h Sun Oct 01 23:15:43 2023 -0400 @@ -2,11 +2,11 @@ #define __gui__pages__history_h #include <QWidget> -class HistoryWidget : public QWidget { +class HistoryPage : public QWidget { Q_OBJECT public: - HistoryWidget(QWidget* parent = nullptr); + HistoryPage(QWidget* parent = nullptr); }; #endif // __gui__pages__history_h
--- a/include/gui/pages/now_playing.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/gui/pages/now_playing.h Sun Oct 01 23:15:43 2023 -0400 @@ -1,12 +1,19 @@ #ifndef __gui__pages__now_playing_h #define __gui__pages__now_playing_h -#include <QWidget> +#include <QFrame> -class NowPlayingWidget : public QWidget { +class QStackedWidget; + +class NowPlayingPage : public QFrame { Q_OBJECT public: - NowPlayingWidget(QWidget* parent = nullptr); + NowPlayingPage(QWidget* parent = nullptr); + void SetDefault(); + void SetPlaying(int id); + + private: + QStackedWidget* stack; }; #endif // __gui__pages__now_playing_h
--- a/include/gui/pages/search.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/gui/pages/search.h Sun Oct 01 23:15:43 2023 -0400 @@ -2,11 +2,11 @@ #define __gui__pages__search_h #include <QWidget> -class SearchWidget : public QWidget { +class SearchPage : public QWidget { Q_OBJECT public: - SearchWidget(QWidget* parent = nullptr); + SearchPage(QWidget* parent = nullptr); }; #endif // __gui__pages__search_h
--- a/include/gui/pages/seasons.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/gui/pages/seasons.h Sun Oct 01 23:15:43 2023 -0400 @@ -2,11 +2,11 @@ #define __gui__pages__seasons_h #include <QWidget> -class SeasonsWidget : public QWidget { +class SeasonsPage : public QWidget { Q_OBJECT public: - SeasonsWidget(QWidget* parent = nullptr); + SeasonsPage(QWidget* parent = nullptr); }; #endif // __gui__pages__seasons_h
--- a/include/gui/pages/statistics.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/gui/pages/statistics.h Sun Oct 01 23:15:43 2023 -0400 @@ -1,15 +1,18 @@ #ifndef __gui__pages__statistics_h #define __gui__pages__statistics_h -#include "gui/pages/anime_list.h" #include <QFrame> -#include <QPlainTextEdit> #include <QWidget> +//#include "gui/widgets/text.h" -class StatisticsWidget : public QFrame { +namespace TextWidgets { + class Paragraph; +} + +class StatisticsPage : public QFrame { Q_OBJECT public: - StatisticsWidget(QWidget* parent = nullptr); + StatisticsPage(QWidget* parent = nullptr); void UpdateStatistics(); protected: @@ -19,7 +22,7 @@ std::string MinutesToDateString(int minutes); std::string SecondsToDateString(int seconds); - QPlainTextEdit* anime_list_data; + TextWidgets::Paragraph* anime_list_data; // QPlainTextEdit* score_distribution_title; // QPlainTextEdit* score_distribution_labels; @@ -28,6 +31,6 @@ /* we don't HAVE a local database (yet ;)) */ // QPlainTextEdit* local_database_data; - QPlainTextEdit* application_data; + TextWidgets::Paragraph* application_data; }; #endif // __gui__pages__statistics_h \ No newline at end of file
--- a/include/gui/pages/torrents.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/gui/pages/torrents.h Sun Oct 01 23:15:43 2023 -0400 @@ -2,11 +2,11 @@ #define __gui__pages__torrents_h #include <QWidget> -class TorrentsWidget : public QWidget { +class TorrentsPage : public QWidget { Q_OBJECT public: - TorrentsWidget(QWidget* parent = nullptr); + TorrentsPage(QWidget* parent = nullptr); }; #endif // __gui__pages__torrents_h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/gui/widgets/anime_info.h Sun Oct 01 23:15:43 2023 -0400 @@ -0,0 +1,16 @@ +#ifndef __gui__widgets__anime_info_h +#define __gui__widgets__anime_info_h +#include <QWidget> + +namespace Anime { + class Anime; +} + +class AnimeInfoWidget : public QWidget { + Q_OBJECT + + public: + AnimeInfoWidget(const Anime::Anime& anime, QWidget* parent = nullptr); +}; + +#endif // __gui__widgets__anime_info_h
--- a/include/gui/widgets/text.h Sun Oct 01 06:39:47 2023 -0400 +++ b/include/gui/widgets/text.h Sun Oct 01 23:15:43 2023 -0400 @@ -1,20 +1,21 @@ #ifndef __gui__ui_utils_h #define __gui__ui_utils_h + #include <QFrame> #include <QLabel> #include <QPlainTextEdit> #include <QSize> #include <QString> #include <QWidget> + namespace TextWidgets { -void SetPlainTextEditData(QPlainTextEdit* text_edit, QString data); class Header : public QWidget { Q_OBJECT public: Header(QString title, QWidget* parent = nullptr); - void SetTitle(QString title); + void SetText(QString title); private: QLabel* static_text_title; @@ -26,6 +27,7 @@ public: Paragraph(QString text, QWidget* parent = nullptr); + void SetText(QString text); QSize minimumSizeHint() const override; QSize sizeHint() const override; }; @@ -73,5 +75,14 @@ Header* header; Paragraph* paragraph; }; -}; // namespace TextWidgets + +class Title : public Paragraph { + Q_OBJECT + + public: + Title(QString title, QWidget* parent = nullptr); +}; + +} // namespace TextWidgets + #endif // __gui__ui_utils_h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/track/media.h Sun Oct 01 23:15:43 2023 -0400 @@ -0,0 +1,14 @@ +#ifndef __track__media_h +#define __track__media_h +#include "core/filesystem.h" + +namespace Track { +namespace Media { + +Filesystem::Path GetCurrentPlaying(); +std::string GetFileTitle(Filesystem::Path path); + +} // namespace Media +} // namespace Track + +#endif // __track__media_h
--- a/src/core/anime_db.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/core/anime_db.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -1,5 +1,7 @@ #include "core/anime_db.h" #include "core/anime.h" +#include "core/strings.h" +#include <QDebug> namespace Anime { @@ -79,13 +81,28 @@ int amt = 0; for (const auto& a : items) { if (a.second.IsInUserList() && a.second.GetUserScore()) { - squares_sum += std::pow((double)a.second.GetUserScore() - avg, 2); + squares_sum += std::pow(static_cast<double>(a.second.GetUserScore()) - avg, 2); amt++; } } return (amt > 0) ? std::sqrt(squares_sum / amt) : 0; } +int Database::GetAnimeFromTitle(std::string title) { + if (title.empty()) + return 0; + for (const auto& a : items) { + if (a.second.GetUserPreferredTitle().find(title) != std::string::npos) + return a.second.GetId(); + for (const auto& t : a.second.GetTitleSynonyms()) { + if (t.find(title) != std::string::npos) { + return a.second.GetId(); + } + } + } + return 0; +} + Database db; } // namespace Anime \ No newline at end of file
--- a/src/core/filesystem.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/core/filesystem.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -67,17 +67,20 @@ } std::string Path::Basename() const { - return _path.substr(0, _path.find_last_of(DELIM)); + unsigned long long pos = _path.find_last_of(DELIM); + return pos != std::string::npos ? _path.substr(pos+1, _path.length()) : ""; } std::string Path::Stem() const { std::string basename = Basename(); - return basename.substr(0, basename.find_last_of(".")); + unsigned long long pos = basename.find_last_of("."); + return pos != std::string::npos ? basename.substr(0, pos) : ""; } std::string Path::Extension() const { std::string basename = Basename(); - return basename.substr(basename.find_last_of("."), basename.length()); + unsigned long long pos = basename.find_last_of("."); + return pos != std::string::npos ? basename.substr(pos+1, basename.length()) : ""; } Path Path::GetParent() const {
--- a/src/core/strings.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/core/strings.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -2,6 +2,8 @@ * strings.cpp: Useful functions for manipulating strings **/ #include "core/strings.h" +#include <QByteArray> +#include <QString> #include <algorithm> #include <cctype> #include <codecvt> @@ -62,8 +64,8 @@ } /* these functions suck for i18n!... - but we only use them with JSON - stuff anyway */ + 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); }); @@ -81,9 +83,28 @@ return converter.from_bytes(string); } +std::wstring ToWstring(const QString& string) { + std::wstring arr(string.size(), L'\0'); + string.toWCharArray(&arr.front()); + return arr; +} + std::string ToUtf8String(const std::wstring& wstring) { std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter; return converter.to_bytes(wstring); } +std::string ToUtf8String(const QString& string) { + QByteArray ba = string.toUtf8(); + return std::string(ba.data(), ba.size()); +} + +QString ToQString(const std::string& string) { + return QString::fromUtf8(string.c_str(), string.length()); +} + +QString ToQString(const std::wstring& wstring) { + return QString::fromWCharArray(wstring.c_str(), wstring.length()); +} + } // namespace Strings
--- a/src/core/time.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/core/time.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -44,15 +44,15 @@ } int64_t Duration::InMinutes() { - return std::llround((double)length / 60.0); + return std::llround(static_cast<double>(length) / 60.0); } int64_t Duration::InHours() { - return std::llround((double)length / 3600.0); + return std::llround(static_cast<double>(length) / 3600.0); } int64_t Duration::InDays() { - return std::llround((double)length / 86400.0); + return std::llround(static_cast<double>(length) / 86400.0); } int64_t GetSystemTime() {
--- a/src/gui/dialog/about.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/dialog/about.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -62,7 +62,7 @@ AboutWindow::AboutWindow(QWidget* parent) : QDialog(parent) { setWindowTitle(tr("About Minori")); setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); - setLayout(new QHBoxLayout); + QHBoxLayout* layout = new QHBoxLayout(this); QPalette pal = QPalette(); pal.setColor(QPalette::Window, pal.color(QPalette::Base)); @@ -127,5 +127,5 @@ cursor.insertText(tr("Links:")); UNSET_FONT_BOLD(font, format, cursor); cursor.insertBlock(); - layout()->addWidget(paragraph); + layout->addWidget(paragraph); }
--- a/src/gui/dialog/information.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/dialog/information.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -5,6 +5,7 @@ #include "core/strings.h" #include "gui/pages/anime_list.h" #include "gui/translate/anime.h" +#include "gui/widgets/anime_info.h" #include "gui/widgets/optional_date.h" #include "gui/widgets/text.h" #include "gui/window.h" @@ -65,60 +66,15 @@ id = anime.GetId(); /* anime title header text */ - TextWidgets::Paragraph* anime_title = - new TextWidgets::Paragraph(QString::fromUtf8(anime.GetUserPreferredTitle().c_str()), main_widget); - anime_title->setReadOnly(true); - anime_title->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - anime_title->setWordWrapMode(QTextOption::NoWrap); - anime_title->setFrameShape(QFrame::NoFrame); - anime_title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - anime_title->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - anime_title->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - { - QFont font(anime_title->font()); - font.setPointSize(12); - anime_title->setFont(font); - } - - { - QPalette pal; - pal.setColor(QPalette::Window, Qt::transparent); - pal.setColor(QPalette::WindowText, Qt::blue); - } + TextWidgets::Title* anime_title = + new TextWidgets::Title(QString::fromStdString(anime.GetUserPreferredTitle()), main_widget); /* tabbed widget */ QTabWidget* tabbed_widget = new QTabWidget(main_widget); tabbed_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); /* main info tab */ - QWidget* main_information_widget = new QWidget(tabbed_widget); - main_information_widget->setLayout(new QVBoxLayout); - - /* alt titles */ - main_information_widget->layout()->addWidget(new TextWidgets::SelectableTextParagraph( - tr("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::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 TextWidgets::LabelledTextParagraph(tr("Details"), tr("Type:\nEpisodes:\nStatus:\nSeason:\nGenres:\nScore:"), - details_data, main_information_widget)); - - /* synopsis */ - TextWidgets::SelectableTextParagraph* synopsis = new TextWidgets::SelectableTextParagraph( - tr("Synopsis"), QString::fromUtf8(anime.GetSynopsis().c_str()), main_information_widget); - - synopsis->GetParagraph()->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - main_information_widget->layout()->addWidget(synopsis); + AnimeInfoWidget* main_information_widget = new AnimeInfoWidget(anime, tabbed_widget); QWidget* settings_widget = new QWidget(tabbed_widget); settings_widget->setLayout(new QVBoxLayout); @@ -136,29 +92,6 @@ #define LAYOUT_HORIZ_SPACING 25 #define LAYOUT_VERT_SPACING 5 #define LAYOUT_ITEM_WIDTH 175 -/* Creates a subsection with a width of 175 */ -#define CREATE_SUBSECTION(x) \ - { \ - QWidget* subsection = new QWidget(section); \ - subsection->setLayout(new QVBoxLayout); \ - subsection->setFixedWidth(LAYOUT_ITEM_WIDTH); \ - subsection->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); \ - subsection->layout()->setSpacing(LAYOUT_VERT_SPACING); \ - subsection->layout()->setContentsMargins(0, 0, 0, 0); \ - x; \ - layout->addWidget(subsection); \ - } -/* Creates a section in the parent `a` */ -#define CREATE_SECTION(a, x) \ - { \ - QWidget* section = new QWidget(a); \ - QHBoxLayout* layout = new QHBoxLayout(section); \ - layout->setSpacing(LAYOUT_HORIZ_SPACING); \ - layout->setContentsMargins(0, 0, 0, 0); \ - x; \ - layout->addStretch(); \ - a->layout()->addWidget(section); \ - } /* Creates a subsection that takes up whatever space is necessary */ #define CREATE_FULL_WIDTH_SUBSECTION(x) \ { \ @@ -170,6 +103,10 @@ x; \ layout->addWidget(subsection); \ } + +/* Creates a subsection with a width of 175 */ +#define CREATE_SUBSECTION(x) CREATE_FULL_WIDTH_SUBSECTION(x subsection->setFixedWidth(LAYOUT_ITEM_WIDTH);) + /* Creates a section in the parent `a` */ #define CREATE_FULL_WIDTH_SECTION(a, x) \ { \ @@ -181,6 +118,9 @@ a->layout()->addWidget(section); \ } +/* Creates a section in the parent `a` */ +#define CREATE_SECTION(a, x) CREATE_FULL_WIDTH_SECTION(a, x layout->addStretch();) + CREATE_SECTION(sg_anime_list_content, { /* Episodes watched section */ CREATE_SUBSECTION({ @@ -304,7 +244,7 @@ #undef CREATE_FULL_WIDTH_SECTION #undef CREATE_FULL_WIDTH_SUBSECTION - static_cast<QBoxLayout*>(settings_widget->layout())->addStretch(); + reinterpret_cast<QBoxLayout*>(settings_widget->layout())->addStretch(); tabbed_widget->addTab(main_information_widget, tr("Main information")); tabbed_widget->addTab(settings_widget, tr("My list and settings"));
--- a/src/gui/dialog/settings.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/dialog/settings.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -56,9 +56,9 @@ } void SettingsDialog::OnOK() { - QStackedWidget* stacked = (QStackedWidget*)layout->itemAt(1)->widget(); + QStackedWidget* stacked = reinterpret_cast<QStackedWidget*>(layout->itemAt(1)->widget()); for (int i = 0; i < stacked->count(); i++) { - ((SettingsPage*)stacked->widget(i))->SaveInfo(); + reinterpret_cast<SettingsPage*>(stacked->widget(i))->SaveInfo(); } QDialog::accept(); }
--- a/src/gui/pages/anime_list.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/pages/anime_list.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -27,22 +27,22 @@ #include <QStyledItemDelegate> #include <cmath> -AnimeListWidgetDelegate::AnimeListWidgetDelegate(QObject* parent) : QStyledItemDelegate(parent) { +AnimeListPageDelegate::AnimeListPageDelegate(QObject* parent) : QStyledItemDelegate(parent) { } -QWidget* AnimeListWidgetDelegate::createEditor(QWidget*, const QStyleOptionViewItem&, const QModelIndex&) const { +QWidget* AnimeListPageDelegate::createEditor(QWidget*, const QStyleOptionViewItem&, const QModelIndex&) const { // no edit 4 u return nullptr; } -void AnimeListWidgetDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, - const QModelIndex& index) const { +void AnimeListPageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const { switch (index.column()) { #if 0 - case AnimeListWidgetModel::AL_PROGRESS: { + case AnimeListPageModel::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(AnimeListPageModel::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()); @@ -63,10 +63,10 @@ } } -AnimeListWidgetSortFilter::AnimeListWidgetSortFilter(QObject* parent) : QSortFilterProxyModel(parent) { +AnimeListPageSortFilter::AnimeListPageSortFilter(QObject* parent) : QSortFilterProxyModel(parent) { } -bool AnimeListWidgetSortFilter::lessThan(const QModelIndex& l, const QModelIndex& r) const { +bool AnimeListPageSortFilter::lessThan(const QModelIndex& l, const QModelIndex& r) const { QVariant left = sourceModel()->data(l, sortRole()); QVariant right = sourceModel()->data(r, sortRole()); @@ -81,22 +81,22 @@ } } -AnimeListWidgetModel::AnimeListWidgetModel(QWidget* parent, Anime::ListStatus _status) : QAbstractListModel(parent) { +AnimeListPageModel::AnimeListPageModel(QWidget* parent, Anime::ListStatus _status) : QAbstractListModel(parent) { status = _status; return; } -int AnimeListWidgetModel::rowCount(const QModelIndex& parent) const { +int AnimeListPageModel::rowCount(const QModelIndex& parent) const { return list.size(); (void)(parent); } -int AnimeListWidgetModel::columnCount(const QModelIndex& parent) const { +int AnimeListPageModel::columnCount(const QModelIndex& parent) const { return NB_COLUMNS; (void)(parent); } -QVariant AnimeListWidgetModel::headerData(const int section, const Qt::Orientation orientation, const int role) const { +QVariant AnimeListPageModel::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"); @@ -131,7 +131,7 @@ return QAbstractListModel::headerData(section, orientation, role); } -QVariant AnimeListWidgetModel::data(const QModelIndex& index, int role) const { +QVariant AnimeListPageModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); switch (role) { @@ -190,7 +190,7 @@ return QVariant(); } -void AnimeListWidgetModel::UpdateAnime(int id) { +void AnimeListPageModel::UpdateAnime(int id) { /* meh... it might be better to just reinit the entire list */ int i = 0; for (const auto& a : Anime::db.items) { @@ -201,11 +201,11 @@ } } -Anime::Anime* AnimeListWidgetModel::GetAnimeFromIndex(QModelIndex index) { +Anime::Anime* AnimeListPageModel::GetAnimeFromIndex(QModelIndex index) { return &list.at(index.row()); } -void AnimeListWidgetModel::RefreshList() { +void AnimeListPageModel::RefreshList() { bool has_children = !!rowCount(index(0)); if (has_children) beginResetModel(); @@ -231,7 +231,7 @@ endInsertRows(); } -int AnimeListWidget::VisibleColumnsCount() const { +int AnimeListPage::VisibleColumnsCount() const { int count = 0; for (int i = 0, end = tree_view->header()->count(); i < end; i++) { @@ -242,29 +242,29 @@ return count; } -void AnimeListWidget::SetColumnDefaults() { - tree_view->setColumnHidden(AnimeListWidgetModel::AL_SEASON, false); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_TYPE, false); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_UPDATED, false); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_PROGRESS, false); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_SCORE, false); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_TITLE, false); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_EPISODES, true); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_AVG_SCORE, true); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_STARTED, true); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_COMPLETED, true); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_UPDATED, true); - tree_view->setColumnHidden(AnimeListWidgetModel::AL_NOTES, true); +void AnimeListPage::SetColumnDefaults() { + tree_view->setColumnHidden(AnimeListPageModel::AL_SEASON, false); + tree_view->setColumnHidden(AnimeListPageModel::AL_TYPE, false); + tree_view->setColumnHidden(AnimeListPageModel::AL_UPDATED, false); + tree_view->setColumnHidden(AnimeListPageModel::AL_PROGRESS, false); + tree_view->setColumnHidden(AnimeListPageModel::AL_SCORE, false); + tree_view->setColumnHidden(AnimeListPageModel::AL_TITLE, false); + tree_view->setColumnHidden(AnimeListPageModel::AL_EPISODES, true); + tree_view->setColumnHidden(AnimeListPageModel::AL_AVG_SCORE, true); + tree_view->setColumnHidden(AnimeListPageModel::AL_STARTED, true); + tree_view->setColumnHidden(AnimeListPageModel::AL_COMPLETED, true); + tree_view->setColumnHidden(AnimeListPageModel::AL_UPDATED, true); + tree_view->setColumnHidden(AnimeListPageModel::AL_NOTES, true); } -void AnimeListWidget::DisplayColumnHeaderMenu() { +void AnimeListPage::DisplayColumnHeaderMenu() { QMenu* menu = new QMenu(this); menu->setAttribute(Qt::WA_DeleteOnClose); menu->setTitle(tr("Column visibility")); menu->setToolTipsVisible(true); - for (int i = 0; i < AnimeListWidgetModel::NB_COLUMNS; i++) { - if (i == AnimeListWidgetModel::AL_TITLE) + for (int i = 0; i < AnimeListPageModel::NB_COLUMNS; i++) { + if (i == AnimeListPageModel::AL_TITLE) continue; const auto column_name = sort_models[tab_bar->currentIndex()]->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); @@ -294,7 +294,7 @@ (void)(resetAction); } -void AnimeListWidget::DisplayListMenu() { +void AnimeListPage::DisplayListMenu() { QMenu* menu = new QMenu(this); menu->setAttribute(Qt::WA_DeleteOnClose); menu->setTitle(tr("Column visibility")); @@ -307,10 +307,10 @@ } QAction* action = menu->addAction(tr("Information"), [this, selection] { - const QModelIndex index = ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel()) - ->index(selection.indexes().first().row()); - Anime::Anime* anime = - ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index); + AnimeListPageModel* source_model = + reinterpret_cast<AnimeListPageModel*>(sort_models[tab_bar->currentIndex()]->sourceModel()); + const QModelIndex index = source_model->index(selection.indexes().first().row()); + Anime::Anime* anime = source_model->GetAnimeFromIndex(index); if (!anime) { return; } @@ -330,7 +330,7 @@ menu->popup(QCursor::pos()); } -void AnimeListWidget::ItemDoubleClicked() { +void AnimeListPage::ItemDoubleClicked() { /* throw out any other garbage */ const QItemSelection selection = sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection()); @@ -338,10 +338,11 @@ return; } - const QModelIndex index = ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel()) - ->index(selection.indexes().first().row()); - Anime::Anime* anime = - ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index); + AnimeListPageModel* source_model = + reinterpret_cast<AnimeListPageModel*>(sort_models[tab_bar->currentIndex()]->sourceModel()); + + const QModelIndex index = source_model->index(selection.indexes().first().row()); + Anime::Anime* anime = source_model->GetAnimeFromIndex(index); InformationDialog* dialog = new InformationDialog( *anime, @@ -356,7 +357,7 @@ dialog->activateWindow(); } -void AnimeListWidget::paintEvent(QPaintEvent*) { +void AnimeListPage::paintEvent(QPaintEvent*) { QStylePainter p(this); QStyleOptionTabWidgetFrame opt; @@ -365,16 +366,16 @@ p.drawPrimitive(QStyle::PE_FrameTabWidget, opt); } -void AnimeListWidget::resizeEvent(QResizeEvent* e) { +void AnimeListPage::resizeEvent(QResizeEvent* e) { QWidget::resizeEvent(e); SetupLayout(); } -void AnimeListWidget::showEvent(QShowEvent*) { +void AnimeListPage::showEvent(QShowEvent*) { SetupLayout(); } -void AnimeListWidget::InitBasicStyle(QStyleOptionTabWidgetFrame* option) const { +void AnimeListPage::InitBasicStyle(QStyleOptionTabWidgetFrame* option) const { if (!option) return; @@ -384,7 +385,7 @@ option->tabBarRect = tab_bar->geometry(); } -void AnimeListWidget::InitStyle(QStyleOptionTabWidgetFrame* option) const { +void AnimeListPage::InitStyle(QStyleOptionTabWidgetFrame* option) const { if (!option) return; @@ -406,7 +407,7 @@ option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this); } -void AnimeListWidget::SetupLayout() { +void AnimeListPage::SetupLayout() { QStyleOptionTabWidgetFrame option; InitStyle(&option); @@ -419,7 +420,7 @@ tree_view->parentWidget()->setGeometry(contentsRect); } -AnimeListWidget::AnimeListWidget(QWidget* parent) : QWidget(parent) { +AnimeListPage::AnimeListPage(QWidget* parent) : QWidget(parent) { /* Tab bar */ tab_bar = new QTabBar(this); tab_bar->setExpanding(false); @@ -428,7 +429,7 @@ /* Tree view... */ QWidget* tree_widget = new QWidget(this); tree_view = new QTreeView(tree_widget); - tree_view->setItemDelegate(new AnimeListWidgetDelegate(tree_view)); + tree_view->setItemDelegate(new AnimeListPageDelegate(tree_view)); tree_view->setUniformRowHeights(true); tree_view->setAllColumnsShowFocus(false); tree_view->setAlternatingRowColors(true); @@ -442,8 +443,8 @@ for (unsigned int i = 0; i < ARRAYSIZE(sort_models); 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); - sort_models[i]->setSourceModel(new AnimeListWidgetModel(this, Anime::ListStatuses[i])); + sort_models[i] = new AnimeListPageSortFilter(tree_view); + sort_models[i]->setSourceModel(new AnimeListPageModel(this, Anime::ListStatuses[i])); sort_models[i]->setSortRole(Qt::UserRole); sort_models[i]->setSortCaseSensitivity(Qt::CaseInsensitive); } @@ -455,19 +456,19 @@ tree_widget->setLayout(layout); /* Double click stuff */ - connect(tree_view, &QAbstractItemView::doubleClicked, this, &AnimeListWidget::ItemDoubleClicked); - connect(tree_view, &QWidget::customContextMenuRequested, this, &AnimeListWidget::DisplayListMenu); + connect(tree_view, &QAbstractItemView::doubleClicked, this, &AnimeListPage::ItemDoubleClicked); + connect(tree_view, &QWidget::customContextMenuRequested, this, &AnimeListPage::DisplayListMenu); /* Enter & return keys */ connect(new QShortcut(Qt::Key_Return, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this, - &AnimeListWidget::ItemDoubleClicked); + &AnimeListPage::ItemDoubleClicked); connect(new QShortcut(Qt::Key_Enter, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this, - &AnimeListWidget::ItemDoubleClicked); + &AnimeListPage::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, &AnimeListPage::DisplayColumnHeaderMenu); connect(tab_bar, &QTabBar::currentChanged, this, [this](int index) { if (sort_models[index]) @@ -478,18 +479,18 @@ setFocusProxy(tab_bar); } -void AnimeListWidget::RefreshList() { +void AnimeListPage::RefreshList() { for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++) - ((AnimeListWidgetModel*)sort_models[i]->sourceModel())->RefreshList(); + reinterpret_cast<AnimeListPageModel*>(sort_models[i]->sourceModel())->RefreshList(); } -void AnimeListWidget::RefreshTabs() { +void AnimeListPage::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() { +void AnimeListPage::Refresh() { RefreshList(); RefreshTabs(); } @@ -497,7 +498,7 @@ /* 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() { +void AnimeListPage::Reset() { while (tab_bar->count()) tab_bar->removeTab(0); for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++)
--- a/src/gui/pages/history.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/pages/history.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -1,6 +1,6 @@ #include "gui/pages/history.h" -HistoryWidget::HistoryWidget(QWidget* parent) : QWidget(parent) { +HistoryPage::HistoryPage(QWidget* parent) : QWidget(parent) { } #include "gui/pages/moc_history.cpp"
--- a/src/gui/pages/now_playing.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/pages/now_playing.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -1,6 +1,83 @@ #include "gui/pages/now_playing.h" +#include "core/anime_db.h" +#include "gui/widgets/anime_info.h" +#include "gui/widgets/text.h" +#include <QLabel> +#include <QStackedWidget> +#include <QVBoxLayout> +#include <QWidget> + +namespace NowPlayingPages { + +class Default : public QWidget { + Q_OBJECT + + public: + Default(QWidget* parent = nullptr); +}; + +class Playing : public QWidget { + Q_OBJECT + + public: + Playing(QWidget* parent = nullptr); + + void SetPlayingAnime(int id) { + if (info.get()) + layout()->removeWidget(info.get()); + info.reset(new AnimeInfoWidget(Anime::db.items[id])); + layout()->addWidget(info.get()); + } + + private: + std::unique_ptr<AnimeInfoWidget> info = nullptr; +}; + +Default::Default(QWidget* parent) : QWidget(parent) { + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); -NowPlayingWidget::NowPlayingWidget(QWidget* parent) : QWidget(parent) { + layout->addStretch(); +} + +Playing::Playing(QWidget* parent) : QWidget(parent) { + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); +} + +} // namespace NowPlayingPages + +NowPlayingPage::NowPlayingPage(QWidget* parent) : QFrame(parent) { + QVBoxLayout* layout = new QVBoxLayout(this); + + setFrameShape(QFrame::Box); + setFrameShadow(QFrame::Sunken); + + QPalette pal = QPalette(); + pal.setColor(QPalette::Window, pal.color(QPalette::Base)); + setPalette(pal); + setAutoFillBackground(true); + + TextWidgets::Title* title = new TextWidgets::Title(tr("Now Playing"), this); + layout->addWidget(title); + + stack = new QStackedWidget(this); + stack->addWidget(new NowPlayingPages::Default(stack)); + stack->addWidget(new NowPlayingPages::Playing(stack)); + layout->addWidget(stack); + + layout->addStretch(); + SetDefault(); +} + +void NowPlayingPage::SetDefault() { + stack->setCurrentIndex(0); +} + +void NowPlayingPage::SetPlaying(int id) { + reinterpret_cast<NowPlayingPages::Playing*>(stack->widget(1))->SetPlayingAnime(id); + stack->setCurrentIndex(1); } #include "gui/pages/moc_now_playing.cpp" +#include "now_playing.moc"
--- a/src/gui/pages/search.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/pages/search.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -1,6 +1,6 @@ #include "gui/pages/search.h" -SearchWidget::SearchWidget(QWidget* parent) : QWidget(parent) { +SearchPage::SearchPage(QWidget* parent) : QWidget(parent) { } #include "gui/pages/moc_search.cpp"
--- a/src/gui/pages/seasons.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/pages/seasons.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -1,6 +1,6 @@ #include "gui/pages/seasons.h" -SeasonsWidget::SeasonsWidget(QWidget* parent) : QWidget(parent) { +SeasonsPage::SeasonsPage(QWidget* parent) : QWidget(parent) { } #include "gui/pages/moc_seasons.cpp"
--- a/src/gui/pages/statistics.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/pages/statistics.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -11,10 +11,10 @@ #include <QWidget> #include <sstream> -StatisticsWidget::StatisticsWidget(QWidget* parent) : QFrame(parent) { - setLayout(new QVBoxLayout); +StatisticsPage::StatisticsPage(QWidget* parent) : QFrame(parent) { + QVBoxLayout* layout = new QVBoxLayout(this); - setFrameShape(QFrame::Panel); + setFrameShape(QFrame::Box); setFrameShadow(QFrame::Sunken); QPalette pal = QPalette(); @@ -32,9 +32,9 @@ new TextWidgets::LabelledTextParagraph(tr("Minori"), tr("Uptime:\nRequests made:"), "\n\n", this); application_data = application_paragraph->GetParagraph(); - layout()->addWidget(anime_list_paragraph); - layout()->addWidget(application_paragraph); - ((QBoxLayout*)layout())->addStretch(); + layout->addWidget(anime_list_paragraph); + layout->addWidget(application_paragraph); + layout->addStretch(); QTimer* timer = new QTimer(this); connect(timer, &QTimer::timeout, this, [this] { @@ -44,17 +44,15 @@ timer->start(1000); // update statistics every second } -void StatisticsWidget::showEvent(QShowEvent*) { +void StatisticsPage::showEvent(QShowEvent*) { UpdateStatistics(); } /* me abusing macros :) */ #define ADD_TIME_SEGMENT(r, x, s, p) \ - { \ - if (x > 0) \ - r << x << ((x == 1) ? s : p); \ - } -std::string StatisticsWidget::MinutesToDateString(int minutes) { + if (x > 0) \ + r << x << ((x == 1) ? s : p) +std::string StatisticsPage::MinutesToDateString(int minutes) { /* ew */ int years = (minutes * (1 / 525949.2F)); int months = (minutes * (1 / 43829.1F)) - (years * 12); @@ -71,7 +69,7 @@ return return_stream.str(); } -std::string StatisticsWidget::SecondsToDateString(int sec) { +std::string StatisticsPage::SecondsToDateString(int sec) { /* this is all fairly unnecessary, but works:tm: */ int years = sec * (1 / 31556952.0F); int months = sec * (1 / 2629746.0F) - (years * 12); @@ -92,7 +90,7 @@ } #undef ADD_TIME_SEGMENT -void StatisticsWidget::UpdateStatistics() { +void StatisticsPage::UpdateStatistics() { /* Anime list */ QString string = ""; QTextStream ts(&string); @@ -102,14 +100,14 @@ ts << MinutesToDateString(Anime::db.GetTotalPlannedAmount()).c_str() << '\n'; ts << Anime::db.GetAverageScore() << '\n'; ts << Anime::db.GetScoreDeviation(); - TextWidgets::SetPlainTextEditData(anime_list_data, string); + anime_list_data->SetText(string); string = ""; ts << QString::fromUtf8(SecondsToDateString(session.uptime() / 1000).c_str()) << '\n'; ts << session.GetRequests(); /* Application */ // UiUtils::SetPlainTextEditData(application_data, QString::number(session.uptime() / 1000)); - TextWidgets::SetPlainTextEditData(application_data, string); + application_data->SetText(string); } #include "gui/pages/moc_statistics.cpp"
--- a/src/gui/pages/torrents.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/pages/torrents.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -1,6 +1,6 @@ #include "gui/pages/torrents.h" -TorrentsWidget::TorrentsWidget(QWidget* parent) : QWidget(parent) { +TorrentsPage::TorrentsPage(QWidget* parent) : QWidget(parent) { } #include "gui/pages/moc_torrents.cpp"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/widgets/anime_info.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -0,0 +1,38 @@ +#include "gui/widgets/anime_info.h" +#include "core/anime.h" +#include "core/strings.h" +#include "gui/translate/anime.h" +#include "gui/widgets/text.h" +#include <QHBoxLayout> +#include <QTextStream> + +AnimeInfoWidget::AnimeInfoWidget(const Anime::Anime& anime, QWidget* parent) : QWidget(parent) { + QVBoxLayout* layout = new QVBoxLayout(this); + + /* alt titles */ + TextWidgets::SelectableTextParagraph* title = new TextWidgets::SelectableTextParagraph( + tr("Alternative titles"), QString::fromUtf8(Strings::Implode(anime.GetTitleSynonyms(), ", ").c_str()), this); + title->GetParagraph()->setWordWrapMode(QTextOption::NoWrap); + layout->addWidget(title); + + /* details */ + QString details_data; + QTextStream details_data_s(&details_data); + 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() << "%"; + layout->addWidget(new TextWidgets::LabelledTextParagraph( + tr("Details"), tr("Type:\nEpisodes:\nStatus:\nSeason:\nGenres:\nScore:"), details_data, this)); + + /* synopsis */ + TextWidgets::SelectableTextParagraph* synopsis = + new TextWidgets::SelectableTextParagraph(tr("Synopsis"), QString::fromUtf8(anime.GetSynopsis().c_str()), this); + + synopsis->GetParagraph()->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + layout->addWidget(synopsis); +} + +#include "gui/widgets/moc_anime_info.cpp"
--- a/src/gui/widgets/text.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/widgets/text.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -10,7 +10,7 @@ namespace TextWidgets { Header::Header(QString title, QWidget* parent) : QWidget(parent) { - setLayout(new QVBoxLayout); + QVBoxLayout* layout = new QVBoxLayout(this); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); static_text_title = new QLabel(title, this); @@ -18,6 +18,7 @@ QFont font = static_text_title->font(); font.setWeight(QFont::Bold); static_text_title->setFont(font); + /* FIXME: is this needed? */ static_text_title->setFixedHeight(16); static_text_line = new QFrame(this); @@ -25,38 +26,38 @@ static_text_line->setFrameShadow(QFrame::Sunken); static_text_line->setFixedHeight(2); - layout()->addWidget(static_text_title); - layout()->addWidget(static_text_line); - layout()->setSpacing(0); - layout()->setContentsMargins(0, 0, 0, 0); + layout->addWidget(static_text_title); + layout->addWidget(static_text_line); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); } -void Header::SetTitle(QString title) { - static_text_title->setText(title); +void Header::SetText(QString text) { + static_text_title->setText(text); } TextParagraph::TextParagraph(QString title, QString data, QWidget* parent) : QWidget(parent) { - setLayout(new QVBoxLayout); + QVBoxLayout* layout = new QVBoxLayout(this); header = new Header(title, this); QWidget* content = new QWidget(this); - content->setLayout(new QHBoxLayout); + QHBoxLayout* content_layout = new QHBoxLayout(content); paragraph = new Paragraph(data, this); paragraph->setTextInteractionFlags(Qt::NoTextInteraction); paragraph->setAttribute(Qt::WidgetAttribute::WA_TransparentForMouseEvents); paragraph->setWordWrapMode(QTextOption::NoWrap); - content->layout()->addWidget(paragraph); - content->layout()->setSpacing(0); - content->layout()->setContentsMargins(0, 0, 0, 0); + content_layout->addWidget(paragraph); + content_layout->setSpacing(0); + content_layout->setContentsMargins(0, 0, 0, 0); content->setContentsMargins(12, 0, 0, 0); - layout()->addWidget(header); - layout()->addWidget(paragraph); - layout()->setSpacing(0); - layout()->setContentsMargins(0, 0, 0, 0); + layout->addWidget(header); + layout->addWidget(paragraph); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); } Header* TextParagraph::GetHeader() { @@ -69,7 +70,7 @@ LabelledTextParagraph::LabelledTextParagraph(QString title, QString label, QString data, QWidget* parent) : QWidget(parent) { - setLayout(new QVBoxLayout); + QVBoxLayout* layout = new QVBoxLayout(this); header = new Header(title, this); @@ -97,10 +98,10 @@ content->setContentsMargins(12, 0, 0, 0); - layout()->addWidget(header); - layout()->addWidget(content); - layout()->setSpacing(0); - layout()->setContentsMargins(0, 0, 0, 0); + layout->addWidget(header); + layout->addWidget(content); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); } Header* LabelledTextParagraph::GetHeader() { @@ -116,24 +117,24 @@ } SelectableTextParagraph::SelectableTextParagraph(QString title, QString data, QWidget* parent) : QWidget(parent) { - setLayout(new QVBoxLayout); + QVBoxLayout* layout = new QVBoxLayout(this); header = new Header(title, this); QWidget* content = new QWidget(this); - content->setLayout(new QHBoxLayout); + QHBoxLayout* content_layout = new QHBoxLayout(content); paragraph = new Paragraph(data, content); - content->layout()->addWidget(paragraph); - content->layout()->setSpacing(0); - content->layout()->setContentsMargins(0, 0, 0, 0); + content_layout->addWidget(paragraph); + content_layout->setSpacing(0); + content_layout->setContentsMargins(0, 0, 0, 0); content->setContentsMargins(12, 0, 0, 0); - layout()->addWidget(header); - layout()->addWidget(content); - layout()->setSpacing(0); - layout()->setContentsMargins(0, 0, 0, 0); + layout->addWidget(header); + layout->addWidget(content); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); } Header* SelectableTextParagraph::GetHeader() { @@ -158,8 +159,19 @@ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); } +void Paragraph::SetText(QString text) { + QTextDocument* document = new QTextDocument(this); + document->setDocumentLayout(new QPlainTextDocumentLayout(document)); + document->setPlainText(text); + setDocument(document); +} + /* highly based upon... some stackoverflow answer for PyQt */ QSize Paragraph::minimumSizeHint() const { + return QSize(0, 0); +} + +QSize Paragraph::sizeHint() const { QTextDocument* doc = document(); doc->adjustSize(); long h = 0; @@ -169,16 +181,23 @@ return QSize(doc->size().width(), h); } -QSize Paragraph::sizeHint() const { - return minimumSizeHint(); -} +Title::Title(QString title, QWidget* parent) : Paragraph(title, parent) { + setReadOnly(true); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setWordWrapMode(QTextOption::NoWrap); + setFrameShape(QFrame::NoFrame); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); -/* this is still actually useful, so we'll keep it */ -void SetPlainTextEditData(QPlainTextEdit* text_edit, QString data) { - QTextDocument* document = new QTextDocument(text_edit); - document->setDocumentLayout(new QPlainTextDocumentLayout(document)); - document->setPlainText(data); - text_edit->setDocument(document); + QFont fnt(font()); + fnt.setPointSize(12); + setFont(fnt); + + QPalette pal(palette()); + pal.setColor(QPalette::Window, Qt::transparent); + pal.setColor(QPalette::Text, QColor(0x00, 0x33, 0x99)); + setPalette(pal); } } // namespace TextWidgets
--- a/src/gui/window.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/gui/window.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -1,6 +1,8 @@ #include "gui/window.h" +#include "core/anime_db.h" #include "core/config.h" #include "core/session.h" +#include "core/strings.h" #include "gui/dark_theme.h" #include "gui/dialog/about.h" #include "gui/dialog/settings.h" @@ -13,8 +15,10 @@ #include "gui/pages/torrents.h" #include "gui/widgets/sidebar.h" #include "services/services.h" +#include "track/media.h" #include <QActionGroup> #include <QApplication> +#include <QDebug> #include <QFile> #include <QMainWindow> #include <QMenuBar> @@ -58,16 +62,16 @@ sidebar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); QStackedWidget* stack = new QStackedWidget(main_widget); - stack->addWidget(new NowPlayingWidget(main_widget)); - stack->addWidget(new AnimeListWidget(main_widget)); - stack->addWidget(new HistoryWidget(main_widget)); - stack->addWidget(new StatisticsWidget(main_widget)); - stack->addWidget(new SearchWidget(main_widget)); - stack->addWidget(new SeasonsWidget(main_widget)); - stack->addWidget(new TorrentsWidget(main_widget)); + stack->addWidget(new NowPlayingPage(main_widget)); + stack->addWidget(new AnimeListPage(main_widget)); + stack->addWidget(new HistoryPage(main_widget)); + stack->addWidget(new StatisticsPage(main_widget)); + stack->addWidget(new SearchPage(main_widget)); + stack->addWidget(new SeasonsPage(main_widget)); + stack->addWidget(new TorrentsPage(main_widget)); connect(sidebar, &SideBar::CurrentItemChanged, stack, &QStackedWidget::setCurrentIndex); - sidebar->SetCurrentItem((int)Pages::ANIME_LIST); + sidebar->SetCurrentItem(static_cast<int>(Pages::ANIME_LIST)); /* Menu Bar */ QAction* action; @@ -93,7 +97,7 @@ menu = menubar->addMenu(tr("&Services")); action = menu->addAction(tr("Synchronize &list"), [stack] { Services::Synchronize(); - ((AnimeListWidget*)stack->widget((int)Pages::ANIME_LIST))->Refresh(); + reinterpret_cast<AnimeListPage*>(stack->widget(static_cast<int>(Pages::ANIME_LIST)))->Refresh(); }); action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S)); @@ -181,7 +185,7 @@ menu->addAction(tr("Show sidebar")); menu = menubar->addMenu(tr("&Help")); - action = menu->addAction(tr("About Minori"), this, [this] { + action = menu->addAction(tr("&About Minori"), this, [this] { AboutWindow dialog(this); dialog.exec(); }); @@ -195,6 +199,22 @@ layout->addWidget(stack); setCentralWidget(main_widget); + QTimer* timer = new QTimer(this); + connect(timer, &QTimer::timeout, this, [stack] { + NowPlayingPage* page = reinterpret_cast<NowPlayingPage*>(stack->widget(static_cast<int>(Pages::NOW_PLAYING))); + + Filesystem::Path p = Track::Media::GetCurrentPlaying(); + std::string title = Track::Media::GetFileTitle(p); + int id = Anime::db.GetAnimeFromTitle(title); + if (id == 0) { + page->SetDefault(); + return; + } + + page->SetPlaying(id); + }); + timer->start(5000); + DarkTheme::SetTheme(session.config.theme); }
--- a/src/services/anilist.cpp Sun Oct 01 06:39:47 2023 -0400 +++ b/src/services/anilist.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -6,7 +6,6 @@ #include "core/session.h" #include "core/strings.h" #include "gui/translate/anilist.h" -#include <QDebug> #include <QDesktopServices> #include <QInputDialog> #include <QLineEdit> @@ -17,7 +16,7 @@ #include <exception> #define CLIENT_ID "13706" -using nlohmann::literals::operator"" _json_pointer; +using namespace nlohmann::literals::json_literals; namespace Services { namespace AniList { @@ -39,7 +38,7 @@ static Account account; static size_t CurlWriteCallback(void* contents, size_t size, size_t nmemb, void* userdata) { - ((std::string*)userdata)->append((char*)contents, size * nmemb); + reinterpret_cast<std::string*>(userdata)->append(reinterpret_cast<char*>(contents), size * nmemb); return size * nmemb; } @@ -117,6 +116,8 @@ Date ParseDate(const nlohmann::json& json) { Date date; + /* JSON for Modern C++ warns here. I'm not too sure why, this code works when I set the + standard to C++17 :/ */ if (json.contains("/year"_json_pointer) && json.at("/year"_json_pointer).is_number()) date.SetYear(JSON::GetInt(json, "/year"_json_pointer)); else
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/track/media.cpp Sun Oct 01 23:15:43 2023 -0400 @@ -0,0 +1,38 @@ +#include "track/media.h" +#include "core/filesystem.h" +#include "core/strings.h" +#include "animia.h" +#include "anitomy/anitomy.h" +#include <string> +#include <vector> + +namespace Track { +namespace Media { + +Filesystem::Path GetCurrentPlaying() { + /* getting all open files */ + std::vector<int> pids = Animia::get_all_pids(); + for (int i : pids) { + if (Animia::get_process_name(i) == "mpc-hc64.exe") { + std::vector<std::string> files = Animia::filter_system_files(Animia::get_open_files(i)); + for (std::string s : files) { + Filesystem::Path p(s); + if (p.Extension() == "mkv") + return p; + } + } + } + return Filesystem::Path(); +} + +std::string GetFileTitle(Filesystem::Path path) { + anitomy::Anitomy anitomy; + anitomy.Parse(Strings::ToWstring(path.Basename())); + + const auto& elements = anitomy.elements(); + + return Strings::ToUtf8String(elements.get(anitomy::kElementAnimeTitle)); +} + +} // namespace Media +} // namespace Track