Mercurial > minori
changeset 51:75c804f713b2
window: add about window,
*: use tr() when applicable (useful for i18n)
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Mon, 25 Sep 2023 20:29:26 -0400 |
parents | 10868c3fb2be |
children | 0c4138de2ea7 |
files | CMakeLists.txt include/core/anime.h include/core/date.h include/core/session.h include/core/version.h include/gui/dialog/about.h include/gui/dialog/information.h include/gui/widgets/optional_date.h src/core/date.cpp src/gui/dialog/about.cpp src/gui/dialog/information.cpp src/gui/pages/anime_list.cpp src/gui/pages/statistics.cpp src/gui/translate/anime.cpp src/gui/widgets/optional_date.cpp src/gui/widgets/text.cpp src/gui/window.cpp |
diffstat | 17 files changed, 363 insertions(+), 141 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Mon Sep 25 13:50:56 2023 -0400 +++ b/CMakeLists.txt Mon Sep 25 20:29:26 2023 -0400 @@ -56,6 +56,7 @@ src/gui/widgets/optional_date.cpp # Dialogs + src/gui/dialog/about.cpp src/gui/dialog/information.cpp src/gui/dialog/settings.cpp src/gui/dialog/settings/application.cpp @@ -83,7 +84,7 @@ list(APPEND SRC_FILES src/sys/win32/dark_theme.cpp) endif() -add_executable(minori WIN32 ${SRC_FILES}) +add_executable(minori ${SRC_FILES}) # There's a bug in JFMC++ that keeps me from setting this to C++11. set_property(TARGET minori PROPERTY CXX_STANDARD 17) set_property(TARGET minori PROPERTY AUTOMOC ON)
--- a/include/core/anime.h Mon Sep 25 13:50:56 2023 -0400 +++ b/include/core/anime.h Mon Sep 25 20:29:26 2023 -0400 @@ -10,10 +10,10 @@ enum class ListStatus { NOT_IN_LIST, CURRENT, - PLANNING, COMPLETED, + PAUSED, DROPPED, - PAUSED + PLANNING }; constexpr std::array<ListStatus, 5> ListStatuses{ListStatus::CURRENT, ListStatus::COMPLETED, ListStatus::PAUSED, @@ -169,4 +169,4 @@ } // namespace Anime -#endif // __core__anime_h \ No newline at end of file +#endif // __core__anime_h
--- a/include/core/date.h Mon Sep 25 13:50:56 2023 -0400 +++ b/include/core/date.h Mon Sep 25 20:29:26 2023 -0400 @@ -6,18 +6,19 @@ class Date { public: Date(); - Date(int32_t y); - Date(int32_t y, int8_t m, int8_t d); + Date(unsigned int y); + Date(unsigned int y, unsigned int m, unsigned int d); + Date(const QDate& date); bool IsValid() const; - void SetYear(int32_t y); - void SetMonth(int8_t m); - void SetDay(int8_t d); + void SetYear(unsigned int y); + void SetMonth(unsigned int m); + void SetDay(unsigned int d); void VoidYear(); void VoidMonth(); void VoidDay(); - int32_t GetYear() const; - int8_t GetMonth() const; - int8_t GetDay() const; + unsigned int GetYear() const; + unsigned int GetMonth() const; + unsigned int GetDay() const; QDate GetAsQDate() const; nlohmann::json GetAsAniListJson() const; bool operator<(const Date& other) const; @@ -26,8 +27,10 @@ bool operator>=(const Date& other) const; private: - std::shared_ptr<int32_t> year; - std::shared_ptr<int8_t> month; - std::shared_ptr<int8_t> day; + /* note: it might be worth it to change these all to int, as + large bit precisions aren't exactly useful here... */ + std::shared_ptr<unsigned int> year; + std::shared_ptr<unsigned int> month; + std::shared_ptr<unsigned int> day; }; #endif // __core__date_h
--- a/include/core/session.h Mon Sep 25 13:50:56 2023 -0400 +++ b/include/core/session.h Mon Sep 25 20:29:26 2023 -0400 @@ -4,8 +4,10 @@ #include <QElapsedTimer> struct Session { + public: Config config; Session() { timer.start(); } + /* we literally *cannot* be lying to the user by doing this */ void IncrementRequests() { requests++; }; int GetRequests() { return requests; }; int uptime() { return timer.elapsed(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/core/version.h Mon Sep 25 20:29:26 2023 -0400 @@ -0,0 +1,6 @@ +#ifndef __core__version_h +#define __core__version_h + +#define MINORI_VERSION "v0.1alpha" + +#endif // __core__version_h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/gui/dialog/about.h Mon Sep 25 20:29:26 2023 -0400 @@ -0,0 +1,10 @@ +#ifndef __gui__dialog__about_h +#define __gui__dialog__about_h +#include <QDialog> + +class AboutWindow : public QDialog { + public: + AboutWindow(QWidget* parent = nullptr); +}; + +#endif // __gui__dialog__about_h
--- a/include/gui/dialog/information.h Mon Sep 25 13:50:56 2023 -0400 +++ b/include/gui/dialog/information.h Mon Sep 25 20:29:26 2023 -0400 @@ -2,9 +2,8 @@ #define __gui__dialog__information_h #include <QDialog> #include <functional> -namespace Anime { -class Anime; -} +#include "core/date.h" +#include "core/anime.h" class InformationDialog : public QDialog { Q_OBJECT @@ -13,7 +12,15 @@ InformationDialog(const Anime::Anime& anime, std::function<void()> accept, QWidget* parent = nullptr); private: - int id; + unsigned int id; + unsigned int progress; + unsigned int episodes; + unsigned int score; + bool rewatching; + Anime::ListStatus status; + std::string notes; + Date started; + Date completed; void SaveData(); }; #endif // __gui__dialog__information_h
--- a/include/gui/widgets/optional_date.h Mon Sep 25 13:50:56 2023 -0400 +++ b/include/gui/widgets/optional_date.h Mon Sep 25 20:29:26 2023 -0400 @@ -1,21 +1,29 @@ #ifndef __gui__widgets__optional_date_h #define __gui__widgets__optional_date_h #include <QWidget> +#include "core/date.h" class QCheckBox; class QDateEdit; class QDate; class OptionalDate : public QWidget { + Q_OBJECT + public: OptionalDate(QWidget* parent = nullptr); OptionalDate(bool enabled, QWidget* parent = nullptr); QDateEdit* GetDateEdit(); QCheckBox* GetCheckBox(); void SetDate(QDate date); + void SetDate(Date date); + Date GetDate(); void SetEnabled(bool enabled); bool IsEnabled(); + signals: + void DataChanged(bool checked, Date date); + private: QDateEdit* _dateedit; QCheckBox* _checkbox;
--- a/src/core/date.cpp Mon Sep 25 13:50:56 2023 -0400 +++ b/src/core/date.cpp Mon Sep 25 20:29:26 2023 -0400 @@ -1,6 +1,7 @@ #include "core/date.h" #include "core/json.h" #include <QDate> +#include <QDebug> #include <cstdint> #include <tuple> @@ -30,16 +31,22 @@ Date::Date() { } -Date::Date(int32_t y) { +Date::Date(unsigned int y) { SetYear(y); } -Date::Date(int32_t y, int8_t m, int8_t d) { +Date::Date(unsigned int y, unsigned int m, unsigned int d) { SetYear(y); SetMonth(m); SetDay(d); } +Date::Date(const QDate& date) { + SetYear(date.year()); + SetMonth(date.month()); + SetDay(date.day()); +} + void Date::VoidYear() { year.reset(); } @@ -52,34 +59,34 @@ day.reset(); } -void Date::SetYear(int32_t y) { - year.reset(new int32_t(MAX(0, y))); +void Date::SetYear(unsigned int y) { + year.reset(new unsigned int(MAX(0U, y))); } -void Date::SetMonth(int8_t m) { - month.reset(new int8_t(CLAMP(m, 1, 12))); +void Date::SetMonth(unsigned int m) { + month.reset(new unsigned int(CLAMP(m, 1U, 12U))); } -void Date::SetDay(int8_t d) { - day.reset(new int8_t(CLAMP(d, 1, 31))); +void Date::SetDay(unsigned int d) { + day.reset(new unsigned int(CLAMP(d, 1U, 31U))); } -int32_t Date::GetYear() const { - int32_t* ptr = year.get(); +unsigned int Date::GetYear() const { + unsigned int* ptr = year.get(); if (ptr != nullptr) return *year; return -1; } -int8_t Date::GetMonth() const { - int8_t* ptr = month.get(); +unsigned int Date::GetMonth() const { + unsigned int* ptr = month.get(); if (ptr != nullptr) return *month; return -1; } -int8_t Date::GetDay() const { - int8_t* ptr = day.get(); +unsigned int Date::GetDay() const { + unsigned int* ptr = day.get(); if (ptr != nullptr) return *day; return -1; @@ -90,8 +97,8 @@ } bool Date::operator<(const Date& other) const { - int y = GetYear(), m = GetMonth(), d = GetDay(); - int o_y = other.GetYear(), o_m = other.GetMonth(), o_d = other.GetDay(); + unsigned int y = GetYear(), m = GetMonth(), d = GetDay(); + unsigned int o_y = other.GetYear(), o_m = other.GetMonth(), o_d = other.GetDay(); return std::tie(y, m, d) < std::tie(o_y, o_m, o_d); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/dialog/about.cpp Mon Sep 25 20:29:26 2023 -0400 @@ -0,0 +1,118 @@ +#include "core/version.h" +#include "gui/widgets/text.h" +#include "gui/dialog/about.h" +#include "core/json.h" +#include <curl/curl.h> +#include <QFont> +#include <QTextCharFormat> +#include <QTextBrowser> +#include <QTextCursor> +#include <QHBoxLayout> + +#define CONCAT_VERSION_NX(major, minor, patch) \ + ("v" #major "." #minor "." #patch) + +#define CONCAT_VERSION(major, minor, patch) \ + CONCAT_VERSION_NX(major, minor, patch) + +#define SET_TITLE_FONT(font, format, cursor) \ + { \ + font = cursor.charFormat().font(); \ + font.setPointSize(10); \ + format.setFont(font); \ + cursor.setCharFormat(format); \ + } + +#define SET_PARAGRAPH_FONT(font, format, cursor) \ + { \ + font = cursor.charFormat().font(); \ + font.setPointSize(8); \ + format.setFont(font); \ + cursor.setCharFormat(format); \ + } + +#define SET_FONT_BOLD(font, format, cursor) \ + { \ + font = cursor.charFormat().font(); \ + font.setBold(true); \ + format.setFont(font); \ + cursor.setCharFormat(format); \ + } + +#define UNSET_FONT_BOLD(font, format, cursor) \ + { \ + font = cursor.charFormat().font(); \ + font.setBold(false); \ + format.setFont(font); \ + cursor.setCharFormat(format); \ + } + +#define SET_FORMAT_HYPERLINK(format, cursor, link) \ + { \ + format.setAnchor(true); \ + format.setAnchorHref(link); \ + cursor.setCharFormat(format); \ + } +#define UNSET_FORMAT_HYPERLINK(format, cursor) \ + { \ + format.setAnchor(false); \ + format.setAnchorHref(""); \ + cursor.setCharFormat(format); \ + } + +AboutWindow::AboutWindow(QWidget* parent) : QDialog(parent) { + setWindowTitle(tr("About Minori")); + setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); + setLayout(new QHBoxLayout); + + QPalette pal = QPalette(); + pal.setColor(QPalette::Window, pal.color(QPalette::Base)); + setPalette(pal); + setAutoFillBackground(true); + + QFont font; + QTextCharFormat format; + QTextBrowser* paragraph = new QTextBrowser(this); + paragraph->setOpenExternalLinks(true); + QTextCursor cursor = paragraph->textCursor(); + SET_TITLE_FONT(font, format, cursor); + SET_FONT_BOLD(font, format, cursor); + cursor.insertText("Minori"); + UNSET_FONT_BOLD(font, format, cursor); + cursor.insertText(" " MINORI_VERSION); + SET_PARAGRAPH_FONT(font, format, cursor); + cursor.insertBlock(); + cursor.insertBlock(); + SET_FONT_BOLD(font, format, cursor); + cursor.insertText(tr("Author:")); + UNSET_FONT_BOLD(font, format, cursor); + cursor.insertBlock(); + cursor.insertText(tr("Paper")); + cursor.insertBlock(); + cursor.insertBlock(); + SET_FONT_BOLD(font, format, cursor); + cursor.insertText(tr("Third party components:")); + UNSET_FONT_BOLD(font, format, cursor); + cursor.insertBlock(); + SET_FORMAT_HYPERLINK(format, cursor, "https://github.com/nlohmann/json"); + cursor.insertText(tr("JSON for Modern C++ ") + CONCAT_VERSION(NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH)); + UNSET_FORMAT_HYPERLINK(format, cursor); + cursor.insertText(", "); + { + curl_version_info_data* data = curl_version_info(CURLVERSION_NOW); + SET_FORMAT_HYPERLINK(format, cursor, "https://curl.se/"); + cursor.insertText(tr("libcurl v") + data->version); + UNSET_FORMAT_HYPERLINK(format, cursor); + cursor.insertText(", "); + } + SET_FORMAT_HYPERLINK(format, cursor, "https://p.yusukekamiyamane.com/"); + cursor.insertText(tr("Fugue Icons ") + CONCAT_VERSION(3, 5, 6)); + UNSET_FORMAT_HYPERLINK(format, cursor); + cursor.insertBlock(); + cursor.insertBlock(); + SET_FONT_BOLD(font, format, cursor); + cursor.insertText(tr("Links:")); + UNSET_FONT_BOLD(font, format, cursor); + cursor.insertBlock(); + layout()->addWidget(paragraph); +}
--- a/src/gui/dialog/information.cpp Mon Sep 25 13:50:56 2023 -0400 +++ b/src/gui/dialog/information.cpp Mon Sep 25 20:29:26 2023 -0400 @@ -25,6 +25,13 @@ which sucks. Think of a better way to implement this later. */ void InformationDialog::SaveData() { Anime::Anime& anime = Anime::db.items[id]; + anime.SetUserProgress(progress); + anime.SetUserScore(score); + anime.SetUserIsRewatching(rewatching); + anime.SetUserStatus(status); + anime.SetUserNotes(notes); + anime.SetUserDateStarted(started); + anime.SetUserDateCompleted(completed); } InformationDialog::InformationDialog(const Anime::Anime& anime, std::function<void()> accept, QWidget* parent) @@ -56,6 +63,7 @@ main_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + id = anime.GetId(); /* anime title header text */ TextWidgets::Paragraph* anime_title = new TextWidgets::Paragraph(QString::fromUtf8(anime.GetUserPreferredTitle().c_str()), main_widget); @@ -89,7 +97,7 @@ /* alt titles */ main_information_widget->layout()->addWidget(new TextWidgets::SelectableTextParagraph( - "Alternative titles", QString::fromUtf8(Strings::Implode(anime.GetTitleSynonyms(), ", ").c_str()), + tr("Alternative titles"), QString::fromUtf8(Strings::Implode(anime.GetTitleSynonyms(), ", ").c_str()), main_information_widget)); /* details */ @@ -102,11 +110,11 @@ << Strings::Implode(anime.GetGenres(), ", ").c_str() << "\n" << anime.GetAudienceScore() << "%"; main_information_widget->layout()->addWidget(new TextWidgets::LabelledTextParagraph( - "Details", "Type:\nEpisodes:\nStatus:\nSeason:\nGenres:\nScore:", details_data, main_information_widget)); + tr("Details"), tr("Type:\nEpisodes:\nStatus:\nSeason:\nGenres:\nScore:"), details_data, main_information_widget)); /* synopsis */ TextWidgets::SelectableTextParagraph* synopsis = new TextWidgets::SelectableTextParagraph( - "Synopsis", QString::fromUtf8(anime.GetSynopsis().c_str()), main_information_widget); + tr("Synopsis"), QString::fromUtf8(anime.GetSynopsis().c_str()), main_information_widget); synopsis->GetParagraph()->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); main_information_widget->layout()->addWidget(synopsis); @@ -178,16 +186,23 @@ subsection->layout()->addWidget(new QLabel(tr("Episodes watched:"), subsection)); QSpinBox* spin_box = new QSpinBox(subsection); + connect(spin_box, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int i) { + progress = i; + }); spin_box->setRange(0, anime.GetEpisodes()); spin_box->setSingleStep(1); - spin_box->setValue(anime.GetUserProgress()); + spin_box->setValue(progress = anime.GetUserProgress()); subsection->layout()->addWidget(spin_box); }); CREATE_SUBSECTION({ subsection->layout()->addWidget(new QLabel(tr(" "), subsection)); - QCheckBox* rewatched_checkbox = new QCheckBox("Rewatching"); - subsection->layout()->addWidget(rewatched_checkbox); + QCheckBox* checkbox = new QCheckBox(tr("Rewatching")); + connect(checkbox, QOverload<int>::of(&QCheckBox::stateChanged), this, [this](int state) { + rewatching = (state == Qt::Checked); + }); + checkbox->setCheckState(anime.GetUserIsRewatching() ? Qt::Checked : Qt::Unchecked); + subsection->layout()->addWidget(checkbox); }); }); CREATE_SECTION(sg_anime_list_content, { @@ -201,15 +216,22 @@ QComboBox* combo_box = new QComboBox(subsection); combo_box->addItems(string_list); + connect(combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int i) { + status = Anime::ListStatuses[i]; + }); + combo_box->setCurrentIndex(static_cast<int>(status = anime.GetUserStatus())-1); subsection->layout()->addWidget(combo_box); }); CREATE_SUBSECTION({ subsection->layout()->addWidget(new QLabel(tr("Score:"), subsection)); QSpinBox* spin_box = new QSpinBox(subsection); + connect(spin_box, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int i) { + score = i; + }); spin_box->setRange(0, 100); spin_box->setSingleStep(5); - spin_box->setValue(anime.GetUserScore()); + spin_box->setValue(score = anime.GetUserScore()); subsection->layout()->addWidget(spin_box); }); }); @@ -218,7 +240,12 @@ CREATE_FULL_WIDTH_SUBSECTION({ subsection->layout()->addWidget(new QLabel(tr("Notes:"), subsection)); - QLineEdit* line_edit = new QLineEdit(QString::fromStdString(anime.GetUserNotes()), subsection); + QLineEdit* line_edit = new QLineEdit(subsection); + connect(line_edit, &QLineEdit::textChanged, this, [this](const QString& text) { + /* this sucks but I don't really want to implement anything smarter :) */ + notes = text.toStdString(); + }); + line_edit->setText(QString::fromStdString(notes = anime.GetUserNotes())); line_edit->setPlaceholderText(tr("Enter your notes about this anime")); subsection->layout()->addWidget(line_edit); }); @@ -229,14 +256,30 @@ subsection->layout()->addWidget(new QLabel(tr("Date started:"), subsection)); OptionalDate* date = new OptionalDate(true, subsection); - date->SetDate(QDate(2000, 1, 1)); + connect(date, &OptionalDate::DataChanged, this, [this](bool enabled, Date date) { + started = (enabled) ? date : Date(); + }); + started = anime.GetUserDateStarted(); + if (!started.IsValid()) { + date->SetEnabled(false); + started = anime.GetAirDate(); + } + date->SetDate(started); subsection->layout()->addWidget(date); }); CREATE_SUBSECTION({ subsection->layout()->addWidget(new QLabel(tr("Date completed:"), subsection)); OptionalDate* date = new OptionalDate(true, subsection); - date->SetDate(QDate(2000, 1, 1)); + connect(date, &OptionalDate::DataChanged, this, [this](bool enabled, Date date) { + completed = (enabled) ? date : Date(); + }); + completed = anime.GetUserDateCompleted(); + if (!completed.IsValid()) { + date->SetEnabled(false); + completed = anime.GetAirDate(); + } + date->SetDate(completed); subsection->layout()->addWidget(date); }); }); @@ -259,7 +302,7 @@ tr("Enter alternative titles here, separated by a semicolon (i.e. Title 1; Title 2)")); subsection->layout()->addWidget(line_edit); - QCheckBox* checkbox = new QCheckBox("Use the first alternative title to search for torrents"); + QCheckBox* checkbox = new QCheckBox(tr("Use the first alternative title to search for torrents")); subsection->layout()->addWidget(checkbox); }); }); @@ -270,8 +313,8 @@ static_cast<QBoxLayout*>(settings_widget->layout())->addStretch(); - tabbed_widget->addTab(main_information_widget, "Main information"); - tabbed_widget->addTab(settings_widget, "My list and settings"); + tabbed_widget->addTab(main_information_widget, tr("Main information")); + tabbed_widget->addTab(settings_widget, tr("My list and settings")); QVBoxLayout* main_layout = new QVBoxLayout; main_layout->addWidget(anime_title); @@ -286,6 +329,7 @@ QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(button_box, &QDialogButtonBox::accepted, this, [this, accept] { + SaveData(); accept(); QDialog::accept(); });
--- a/src/gui/pages/anime_list.cpp Mon Sep 25 13:50:56 2023 -0400 +++ b/src/gui/pages/anime_list.cpp Mon Sep 25 20:29:26 2023 -0400 @@ -47,8 +47,8 @@ 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 = + painter->drawText(text_rect, tr("/"), 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( @@ -306,7 +306,7 @@ return; } - QAction* action = menu->addAction("Information", [this, selection] { + 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 = @@ -315,13 +315,9 @@ return; } - InformationDialog* dialog = new InformationDialog( - *anime, - [this, anime] { - ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel()) - ->UpdateAnime(anime->GetId()); - }, - this); + InformationDialog* dialog = new InformationDialog(*anime, [this] { + Refresh(); + }, this); dialog->show(); dialog->raise(); @@ -343,12 +339,9 @@ Anime::Anime* anime = ((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); + InformationDialog* dialog = new InformationDialog(*anime, [this] { + Refresh(); + }, this); dialog->show(); dialog->raise();
--- a/src/gui/pages/statistics.cpp Mon Sep 25 13:50:56 2023 -0400 +++ b/src/gui/pages/statistics.cpp Mon Sep 25 20:29:26 2023 -0400 @@ -23,13 +23,13 @@ setAutoFillBackground(true); TextWidgets::LabelledTextParagraph* anime_list_paragraph = new TextWidgets::LabelledTextParagraph( - "Anime list", - "Anime count:\nEpisode count:\nTime spent watching:\nTime to complete:\nAverage score:\nScore deviation:", "\n\n\n\n\n\n", + tr("Anime list"), + tr("Anime count:\nEpisode count:\nTime spent watching:\nTime to complete:\nAverage score:\nScore deviation:"), "\n\n\n\n\n\n", this); anime_list_data = anime_list_paragraph->GetParagraph(); TextWidgets::LabelledTextParagraph* application_paragraph = - new TextWidgets::LabelledTextParagraph("Minori", "Uptime:\nRequests made:", "\n\n", this); + new TextWidgets::LabelledTextParagraph(tr("Minori"), tr("Uptime:\nRequests made:"), "\n\n", this); application_data = application_paragraph->GetParagraph(); layout()->addWidget(anime_list_paragraph);
--- a/src/gui/translate/anime.cpp Mon Sep 25 13:50:56 2023 -0400 +++ b/src/gui/translate/anime.cpp Mon Sep 25 20:29:26 2023 -0400 @@ -1,53 +1,54 @@ #include "core/anime.h" #include "gui/translate/anime.h" +#include <QCoreApplication> namespace Translate { 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"; - case Anime::ListStatus::PLANNING: return "Plan to watch"; - case Anime::ListStatus::COMPLETED: return "Completed"; - case Anime::ListStatus::DROPPED: return "Dropped"; - case Anime::ListStatus::PAUSED: return "On hold"; + case Anime::ListStatus::NOT_IN_LIST: return QCoreApplication::tr("Not in list").toStdString(); + case Anime::ListStatus::CURRENT: return QCoreApplication::tr("Currently watching").toStdString(); + case Anime::ListStatus::PLANNING: return QCoreApplication::tr("Plan to watch").toStdString(); + case Anime::ListStatus::COMPLETED: return QCoreApplication::tr("Completed").toStdString(); + case Anime::ListStatus::DROPPED: return QCoreApplication::tr("Dropped").toStdString(); + case Anime::ListStatus::PAUSED: return QCoreApplication::tr("On hold").toStdString(); default: return ""; } } std::string ToString(const Anime::SeriesFormat format) { switch (format) { - case Anime::SeriesFormat::UNKNOWN: return "Unknown"; - case Anime::SeriesFormat::TV: return "TV"; - case Anime::SeriesFormat::TV_SHORT: return "TV short"; - case Anime::SeriesFormat::OVA: return "OVA"; - case Anime::SeriesFormat::MOVIE: return "Movie"; - case Anime::SeriesFormat::SPECIAL: return "Special"; - case Anime::SeriesFormat::ONA: return "ONA"; - case Anime::SeriesFormat::MUSIC: return "Music"; + case Anime::SeriesFormat::UNKNOWN: return QCoreApplication::tr("Unknown").toStdString(); + case Anime::SeriesFormat::TV: return QCoreApplication::tr("TV").toStdString(); + case Anime::SeriesFormat::TV_SHORT: return QCoreApplication::tr("TV short").toStdString(); + case Anime::SeriesFormat::OVA: return QCoreApplication::tr("OVA").toStdString(); + case Anime::SeriesFormat::MOVIE: return QCoreApplication::tr("Movie").toStdString(); + case Anime::SeriesFormat::SPECIAL: return QCoreApplication::tr("Special").toStdString(); + case Anime::SeriesFormat::ONA: return QCoreApplication::tr("ONA").toStdString(); + case Anime::SeriesFormat::MUSIC: return QCoreApplication::tr("Music").toStdString(); default: return ""; } } std::string ToString(const Anime::SeriesSeason season) { switch (season) { - case Anime::SeriesSeason::UNKNOWN: return "Unknown"; - case Anime::SeriesSeason::WINTER: return "Winter"; - case Anime::SeriesSeason::SUMMER: return "Summer"; - case Anime::SeriesSeason::FALL: return "Fall"; - case Anime::SeriesSeason::SPRING: return "Spring"; + case Anime::SeriesSeason::UNKNOWN: return QCoreApplication::tr("Unknown").toStdString(); + case Anime::SeriesSeason::WINTER: return QCoreApplication::tr("Winter").toStdString(); + case Anime::SeriesSeason::SUMMER: return QCoreApplication::tr("Summer").toStdString(); + case Anime::SeriesSeason::FALL: return QCoreApplication::tr("Fall").toStdString(); + case Anime::SeriesSeason::SPRING: return QCoreApplication::tr("Spring").toStdString(); default: return ""; } } std::string ToString(const Anime::SeriesStatus status) { switch (status) { - case Anime::SeriesStatus::UNKNOWN: return "Unknown"; - case Anime::SeriesStatus::RELEASING: return "Currently airing"; - case Anime::SeriesStatus::FINISHED: return "Finished airing"; - case Anime::SeriesStatus::NOT_YET_RELEASED: return "Not yet aired"; - case Anime::SeriesStatus::CANCELLED: return "Cancelled"; - case Anime::SeriesStatus::HIATUS: return "On hiatus"; + case Anime::SeriesStatus::UNKNOWN: return QCoreApplication::tr("Unknown").toStdString(); + case Anime::SeriesStatus::RELEASING: return QCoreApplication::tr("Currently airing").toStdString(); + case Anime::SeriesStatus::FINISHED: return QCoreApplication::tr("Finished airing").toStdString(); + case Anime::SeriesStatus::NOT_YET_RELEASED: return QCoreApplication::tr("Not yet aired").toStdString(); + case Anime::SeriesStatus::CANCELLED: return QCoreApplication::tr("Cancelled").toStdString(); + case Anime::SeriesStatus::HIATUS: return QCoreApplication::tr("On hiatus").toStdString(); default: return ""; } }
--- a/src/gui/widgets/optional_date.cpp Mon Sep 25 13:50:56 2023 -0400 +++ b/src/gui/widgets/optional_date.cpp Mon Sep 25 20:29:26 2023 -0400 @@ -1,4 +1,5 @@ #include "gui/widgets/optional_date.h" +#include "core/date.h" #include <QCheckBox> #include <QDateEdit> #include <QHBoxLayout> @@ -12,7 +13,6 @@ layout->setMargin(0); _checkbox = new QCheckBox(this); - _checkbox->setCheckState(enabled ? Qt::Checked : Qt::Unchecked); _checkbox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); layout->addWidget(_checkbox, 0, Qt::AlignVCenter); @@ -25,10 +25,17 @@ layout->addWidget(_dateedit); SetEnabled(enabled); - connect(_checkbox, &QCheckBox::stateChanged, this, [this](int state) { SetEnabled(state == Qt::Checked); }); + connect(_checkbox, &QCheckBox::stateChanged, this, [this](int state) { + SetEnabled(state == Qt::Checked); + emit DataChanged(IsEnabled(), GetDate()); + }); + connect(_dateedit, &QDateEdit::dateChanged, this, [this](QDate) { + emit DataChanged(IsEnabled(), GetDate()); + }); } void OptionalDate::SetEnabled(bool enabled) { + _checkbox->setCheckState(enabled ? Qt::Checked : Qt::Unchecked); _dateedit->setEnabled(enabled); } @@ -40,6 +47,15 @@ _dateedit->setDate(date); } +void OptionalDate::SetDate(Date date) { + if (!date.IsValid()) return; + SetDate(date.GetAsQDate()); +} + +Date OptionalDate::GetDate() { + return Date(_dateedit->date()); +} + QDateEdit* OptionalDate::GetDateEdit() { return _dateedit; } @@ -47,3 +63,5 @@ QCheckBox* OptionalDate::GetCheckBox() { return _checkbox; } + +#include "gui/widgets/moc_optional_date.cpp"
--- a/src/gui/widgets/text.cpp Mon Sep 25 13:50:56 2023 -0400 +++ b/src/gui/widgets/text.cpp Mon Sep 25 20:29:26 2023 -0400 @@ -146,7 +146,6 @@ /* inherits QPlainTextEdit and gives a much more reasonable minimum size */ Paragraph::Paragraph(QString text, QWidget* parent) : QPlainTextEdit(text, parent) { - setReadOnly(true); setTextInteractionFlags(Qt::TextBrowserInteraction); setFrameShape(QFrame::NoFrame); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
--- a/src/gui/window.cpp Mon Sep 25 13:50:56 2023 -0400 +++ b/src/gui/window.cpp Mon Sep 25 20:29:26 2023 -0400 @@ -3,6 +3,7 @@ #include "core/session.h" #include "gui/dark_theme.h" #include "gui/dialog/settings.h" +#include "gui/dialog/about.h" #include "gui/pages/anime_list.h" #include "gui/pages/now_playing.h" #include "gui/pages/statistics.h" @@ -37,15 +38,15 @@ main_widget = new QWidget(parent); SideBar* sidebar = new SideBar(main_widget); - sidebar->AddItem("Now Playing", SideBar::CreateIcon(":/icons/16x16/film.png")); + sidebar->AddItem(tr("Now Playing"), SideBar::CreateIcon(":/icons/16x16/film.png")); sidebar->AddSeparator(); - sidebar->AddItem("Anime List", SideBar::CreateIcon(":/icons/16x16/document-list.png")); - sidebar->AddItem("History", SideBar::CreateIcon(":/icons/16x16/clock-history-frame.png")); - sidebar->AddItem("Statistics", SideBar::CreateIcon(":/icons/16x16/chart.png")); + sidebar->AddItem(tr("Anime List"), SideBar::CreateIcon(":/icons/16x16/document-list.png")); + sidebar->AddItem(tr("History"), SideBar::CreateIcon(":/icons/16x16/clock-history-frame.png")); + sidebar->AddItem(tr("Statistics"), SideBar::CreateIcon(":/icons/16x16/chart.png")); sidebar->AddSeparator(); - sidebar->AddItem("Search", SideBar::CreateIcon(":/icons/16x16/magnifier.png")); - sidebar->AddItem("Seasons", SideBar::CreateIcon(":/icons/16x16/calendar.png")); - sidebar->AddItem("Torrents", SideBar::CreateIcon(":/icons/16x16/feed.png")); + sidebar->AddItem(tr("Search"), SideBar::CreateIcon(":/icons/16x16/magnifier.png")); + sidebar->AddItem(tr("Seasons"), SideBar::CreateIcon(":/icons/16x16/calendar.png")); + sidebar->AddItem(tr("Torrents"), SideBar::CreateIcon(":/icons/16x16/feed.png")); sidebar->setFixedWidth(128); sidebar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); @@ -67,26 +68,26 @@ /* Menu Bar */ QAction* action; QMenuBar* menubar = new QMenuBar(parent); - QMenu* menu = menubar->addMenu("&File"); + QMenu* menu = menubar->addMenu(tr("&File")); - QMenu* submenu = menu->addMenu("&Library folders"); - action = submenu->addAction("&Add new folder..."); + QMenu* submenu = menu->addMenu(tr("&Library folders")); + action = submenu->addAction(tr("&Add new folder...")); - action = menu->addAction("&Scan available episodes"); + action = menu->addAction(tr("&Scan available episodes")); menu->addSeparator(); - action = menu->addAction("Play &next episode"); + action = menu->addAction(tr("Play &next episode")); action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N)); - action = menu->addAction("Play &random episode"); + action = menu->addAction(tr("Play &random episode")); action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R)); menu->addSeparator(); - action = menu->addAction("E&xit", qApp, &QApplication::quit); + action = menu->addAction(tr("E&xit"), qApp, &QApplication::quit); - menu = menubar->addMenu("&Services"); - action = menu->addAction("Synchronize &list", [this, stack] { + menu = menubar->addMenu(tr("&Services")); + action = menu->addAction(tr("Synchronize &list"), [this, stack] { Services::Synchronize(); ((AnimeListWidget*)stack->widget((int)Pages::ANIME_LIST))->Refresh(); }); @@ -94,75 +95,75 @@ menu->addSeparator(); - submenu = menu->addMenu("&AniList"); - action = submenu->addAction("Go to my &profile"); - action = submenu->addAction("Go to my &stats"); + submenu = menu->addMenu(tr("&AniList")); + action = submenu->addAction(tr("Go to my &profile")); + action = submenu->addAction(tr("Go to my &stats")); - submenu = menu->addMenu("&Kitsu"); - action = submenu->addAction("Go to my &feed"); - action = submenu->addAction("Go to my &library"); - action = submenu->addAction("Go to my &profile"); + submenu = menu->addMenu(tr("&Kitsu")); + action = submenu->addAction(tr("Go to my &feed")); + action = submenu->addAction(tr("Go to my &library")); + action = submenu->addAction(tr("Go to my &profile")); - submenu = menu->addMenu("&MyAnimeList"); - action = submenu->addAction("Go to my p&anel"); - action = submenu->addAction("Go to my &profile"); - action = submenu->addAction("Go to my &history"); + submenu = menu->addMenu(tr("&MyAnimeList")); + action = submenu->addAction(tr("Go to my p&anel")); + action = submenu->addAction(tr("Go to my &profile")); + action = submenu->addAction(tr("Go to my &history")); - menu = menubar->addMenu("&Tools"); - submenu = menu->addMenu("&Export anime list"); - action = submenu->addAction("Export as &Markdown..."); - action = submenu->addAction("Export as MyAnimeList &XML..."); + menu = menubar->addMenu(tr("&Tools")); + submenu = menu->addMenu(tr("&Export anime list")); + action = submenu->addAction(tr("Export as &Markdown...")); + action = submenu->addAction(tr("Export as MyAnimeList &XML...")); menu->addSeparator(); - action = menu->addAction("Enable anime &recognition"); + action = menu->addAction(tr("Enable anime &recognition")); action->setCheckable(true); - action = menu->addAction("Enable auto &sharing"); + action = menu->addAction(tr("Enable auto &sharing")); action->setCheckable(true); - action = menu->addAction("Enable &auto synchronization"); + action = menu->addAction(tr("Enable &auto synchronization")); action->setCheckable(true); menu->addSeparator(); - action = menu->addAction("&Settings", [this] { + action = menu->addAction(tr("&Settings"), [this] { SettingsDialog dialog(this); dialog.exec(); }); action->setMenuRole(QAction::PreferencesRole); - menu = menubar->addMenu("&View"); + menu = menubar->addMenu(tr("&View")); std::map<QAction*, int> page_to_index_map = {}; QActionGroup* pages_group = new QActionGroup(this); pages_group->setExclusive(true); - action = pages_group->addAction(menu->addAction("&Now Playing")); + action = pages_group->addAction(menu->addAction(tr("&Now Playing"))); action->setCheckable(true); page_to_index_map[action] = 0; - action = pages_group->addAction(menu->addAction("&Anime List")); + action = pages_group->addAction(menu->addAction(tr("&Anime List"))); page_to_index_map[action] = 1; action->setCheckable(true); action->setChecked(true); - action = pages_group->addAction(menu->addAction("&History")); + action = pages_group->addAction(menu->addAction(tr("&History"))); action->setCheckable(true); page_to_index_map[action] = 2; - action = pages_group->addAction(menu->addAction("&Statistics")); + action = pages_group->addAction(menu->addAction(tr("&Statistics"))); action->setCheckable(true); page_to_index_map[action] = 3; - action = pages_group->addAction(menu->addAction("S&earch")); + action = pages_group->addAction(menu->addAction(tr("S&earch"))); action->setCheckable(true); page_to_index_map[action] = 4; - action = pages_group->addAction(menu->addAction("Se&asons")); + action = pages_group->addAction(menu->addAction(tr("Se&asons"))); action->setCheckable(true); page_to_index_map[action] = 5; - action = pages_group->addAction(menu->addAction("&Torrents")); + action = pages_group->addAction(menu->addAction(tr("&Torrents"))); action->setCheckable(true); page_to_index_map[action] = 6; @@ -176,10 +177,14 @@ } }); menu->addSeparator(); - menu->addAction("Show sidebar"); + menu->addAction(tr("Show sidebar")); - menu = menubar->addMenu("&Help"); - action = menu->addAction("About &Qt", qApp, [this] { qApp->aboutQt(); }); + menu = menubar->addMenu(tr("&Help")); + action = menu->addAction(tr("About Minori"), this, [this] { + AboutWindow dialog(this); + dialog.exec(); + }); + action = menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); action->setMenuRole(QAction::AboutQtRole); setMenuBar(menubar);