view src/gui/dialog/information.cc @ 348:6b0768158dcd

text: redesign almost every widget i.e. Paragraph is now a QLabel, etc etc, some things will probably break, idc
author Paper <paper@paper.us.eu.org>
date Tue, 25 Jun 2024 11:19:54 -0400
parents 5d3c9b31aa6e
children
line wrap: on
line source

#include "gui/dialog/information.h"
#include "core/anime.h"
#include "core/anime_db.h"
#include "core/session.h"
#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/poster.h"
#include "gui/widgets/text.h"
#include "gui/window.h"

#include <QCheckBox>
#include <QComboBox>
#include <QDateEdit>
#include <QDebug>
#include <QDialogButtonBox>
#include <QLabel>
#include <QLineEdit>
#include <QPlainTextEdit>
#include <QSpinBox>
#include <QStringList>
#include <QTextStream>
#include <QVBoxLayout>

#include <functional>
#include <iostream>
#ifdef WIN32
#	include "sys/win32/dark_theme.h"
#endif

/* TODO: Taiga disables rendering of the tab widget entirely when the anime is not part of a list,
   which sucks. Think of a better way to implement this later. */
void InformationDialog::SaveData(Anime::Anime* anime) {
	if (!anime->IsInUserList())
		return;

	anime->SetUserProgress(_progress);
	anime->SetUserScore(_score);
	anime->SetUserIsRewatching(_rewatching);
	anime->SetUserStatus(_status);
	anime->SetUserNotes(_notes);
	anime->SetUserDateStarted(_started);
	anime->SetUserDateCompleted(_completed);
}

InformationDialog::InformationDialog(Anime::Anime* anime, std::function<void(Anime::Anime*)> accept, enum Pages page,
									 QWidget* parent)
	: QDialog(parent) {
	/* ack. lots of brackets here, but MUCH, MUCH MUCH better than what it used to be */
	setFixedSize(842, 613);
	setWindowTitle(tr("Anime Information"));
	setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);

	{
		QPalette pal;
		pal.setColor(QPalette::Window, pal.color(QPalette::Base));
		setPalette(pal);
	}

	QVBoxLayout* full_layout = new QVBoxLayout(this);

	{
		/* this handles the actual page. */
		QWidget* widget = new QWidget(this);
		QHBoxLayout* layout = new QHBoxLayout(widget);

		{
			/* Sidebar */
			QWidget* sidebar = new QWidget(widget);
			QVBoxLayout* sidebar_layout = new QVBoxLayout(sidebar);
			{
				/* Poster */
				Poster* poster = new Poster(*anime, sidebar);
				sidebar_layout->addWidget(poster);
			}
			sidebar_layout->setContentsMargins(0, 0, 0, 0);
			sidebar_layout->addStretch();
			layout->addWidget(sidebar);
		}

		{
			/* ... everything else. */
			QWidget* main_widget = new QWidget(widget);
			QVBoxLayout* main_layout = new QVBoxLayout(main_widget);

			main_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

			{
				/* Anime title */
				TextWidgets::Title* anime_title = new TextWidgets::Title(main_widget);
				anime_title->SetText(anime->GetUserPreferredTitle());
				main_layout->addWidget(anime_title);
			}

			{
				/* Tab widget, contains main info and settings */
				QTabWidget* tabbed_widget = new QTabWidget(main_widget);
				tabbed_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

				{
					/* Main information */
					AnimeInfoWidget* main_information_widget = new AnimeInfoWidget(*anime, tabbed_widget);
					tabbed_widget->addTab(main_information_widget, tr("Main information"));
				}

				if (anime->IsInUserList()) {
					/* My list and settings */
					QWidget* settings_widget = new QWidget(tabbed_widget);
					settings_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);

					QVBoxLayout* settings_layout = new QVBoxLayout(settings_widget);

					TextWidgets::Header* header = new TextWidgets::Header(settings_widget);
					header->SetText(Strings::Translate("Anime list"));
					settings_layout->addWidget(header);

					{
						/* Anime List */
						QWidget* sg_anime_list_content = new QWidget(settings_widget);

						constexpr int LAYOUT_HORIZ_SPACING = 25;
						constexpr int LAYOUT_VERT_SPACING = 5;
						constexpr int LAYOUT_ITEM_WIDTH = 175;

						QVBoxLayout* al_layout = new QVBoxLayout(sg_anime_list_content);
						al_layout->setSpacing(LAYOUT_VERT_SPACING);
						al_layout->setContentsMargins(12, 0, 0, 0);

						/* Helper function for creating sections, reduces clutter. */
						const auto CREATE_SECTION = [](QWidget* parent, std::function<void(QWidget*, QGridLayout*)> x) {
							QWidget* section = new QWidget(parent);
							QGridLayout* layout = new QGridLayout(section);
							layout->setHorizontalSpacing(LAYOUT_HORIZ_SPACING);
							layout->setVerticalSpacing(LAYOUT_VERT_SPACING);
							layout->setContentsMargins(0, 0, 0, 0);
							x(section, layout);
							parent->layout()->addWidget(section);
						};

						CREATE_SECTION(sg_anime_list_content, [this, &anime](QWidget* section, QGridLayout* layout) {
							{
								/* Episodes watched... */
								layout->addWidget(new QLabel(tr("Episodes watched:"), section), 0, 0);

								QSpinBox* spin_box = new QSpinBox(section);
								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(_progress = anime->GetUserProgress());
								spin_box->setFixedWidth(LAYOUT_ITEM_WIDTH);
								layout->addWidget(spin_box, 1, 0);
							}

							{
								/* Rewatching? */
								QCheckBox* checkbox = new QCheckBox(tr("Rewatching"));
								connect(checkbox, QOverload<int>::of(&QCheckBox::stateChanged), this,
										[this](int state) { _rewatching = (state == Qt::Checked); });
								checkbox->setCheckState((_rewatching = anime->GetUserIsRewatching()) ? Qt::Checked
																									 : Qt::Unchecked);
								checkbox->setFixedWidth(LAYOUT_ITEM_WIDTH);
								layout->addWidget(checkbox, 1, 1);
							}
							layout->setColumnStretch(layout->columnCount(), 1);
						});

						CREATE_SECTION(sg_anime_list_content, [this, &anime](QWidget* section, QGridLayout* layout) {
							{
								/* Status */
								layout->addWidget(new QLabel(tr("Status:"), section), 0, 0);

								QComboBox* combo_box = new QComboBox(section);

								_status = anime->GetUserStatus();
								for (unsigned int i = 0; i < Anime::ListStatuses.size(); i++) {
									combo_box->addItem(Strings::ToQString(Translate::ToLocalString(Anime::ListStatuses[i])),
													   static_cast<int>(Anime::ListStatuses[i]));
									if (Anime::ListStatuses[i] == _status)
										combo_box->setCurrentIndex(i);
								}

								connect(combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
										[this, combo_box](int) {
											_status = static_cast<Anime::ListStatus>(combo_box->currentData().toInt());
										});

								/* this should NEVER, EVER, be NOT_IN_LIST */
								combo_box->setFixedWidth(LAYOUT_ITEM_WIDTH);
								layout->addWidget(combo_box, 1, 0);
							}

							{
								/* Score */
								layout->addWidget(new QLabel(tr("Score:"), section), 0, 1);

								QSpinBox* spin_box = new QSpinBox(section);
								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(_score = anime->GetUserScore());
								spin_box->setFixedWidth(LAYOUT_ITEM_WIDTH);
								layout->addWidget(spin_box, 1, 1);
							}
							layout->setColumnStretch(layout->columnCount(), 1);
						});

						CREATE_SECTION(sg_anime_list_content, [this, &anime](QWidget* section, QGridLayout* layout) {
							layout->addWidget(new QLabel(tr("Notes:"), section), 0, 0);

							QLineEdit* line_edit = new QLineEdit(section);
							connect(line_edit, &QLineEdit::textChanged, this, [this](const QString& text) {
								/* this sucks but I don't really want to implement anything smarter :) */
								_notes = Strings::ToUtf8String(text);
							});
							line_edit->setText(Strings::ToQString(_notes = anime->GetUserNotes()));
							line_edit->setPlaceholderText(tr("Enter your notes about this anime"));
							layout->addWidget(line_edit, 1, 0);
						});

						CREATE_SECTION(sg_anime_list_content, [this, &anime](QWidget* section, QGridLayout* layout) {
							/* Started */
							{
								layout->addWidget(new QLabel(tr("Date started:"), section), 0, 0);

								OptionalDate* date = new OptionalDate(true, section);
								connect(date, &OptionalDate::DataChanged, this,
										[this](bool enabled, Date date) { _started = enabled ? date : Date(); });
								date->setFixedWidth(LAYOUT_ITEM_WIDTH);
								_started = anime->GetUserDateStarted();
								if (!_started.IsValid()) {
									date->SetEnabled(false);
									_started = anime->GetStartedDate();
								}
								date->SetDate(_started);
								layout->addWidget(date, 1, 0);
							}

							/* Completed */
							{
								layout->addWidget(new QLabel(tr("Date completed:"), section), 0, 1);

								OptionalDate* date = new OptionalDate(true, section);
								connect(date, &OptionalDate::DataChanged, this,
										[this](bool enabled, Date date) { _completed = enabled ? date : Date(); });
								date->setFixedWidth(LAYOUT_ITEM_WIDTH);
								_completed = anime->GetUserDateCompleted();
								if (!_completed.IsValid()) {
									date->SetEnabled(false);
									_completed = anime->GetCompletedDate();
								}
								date->SetDate(_completed);
								layout->addWidget(date, 1, 1);
							}
							layout->setColumnStretch(layout->columnCount(), 1);
						});

						settings_layout->addWidget(sg_anime_list_content);
					}

					/*
					{
						// commenting this out until it actually gets implemented :)

						settings_layout->addWidget(new TextWidgets::Header(tr("Local settings"), settings_widget));

						QWidget* sg_local_content = new QWidget(settings_widget);
						QVBoxLayout* sg_local_layout = new QVBoxLayout(sg_local_content);
						sg_local_layout->setSpacing(5);
						sg_local_layout->setContentsMargins(12, 0, 0, 0);

						CREATE_SECTION(sg_local_content, [this, &anime](QWidget* section, QGridLayout* layout){
							layout->addWidget(new QLabel(tr("Alternative titles:"), section), 0, 0);

							QLineEdit* line_edit = new QLineEdit("", section);
							line_edit->setPlaceholderText(
								tr("Enter alternative titles here, separated by a semicolon (i.e. Title 1; Title 2)"));
							layout->addWidget(line_edit, 1, 0);

							QCheckBox* checkbox = new QCheckBox(tr("Use the first alternative title to search for
					torrents")); layout->addWidget(checkbox, 2, 0);
						});

						settings_layout->addWidget(sg_local_content);
					}
					*/

					settings_layout->addStretch();

					tabbed_widget->addTab(settings_widget, tr("My list and settings"));
				}
				tabbed_widget->setCurrentIndex(static_cast<int>(page));
				main_layout->addWidget(tabbed_widget);
				main_layout->setContentsMargins(0, 0, 0, 0);
				main_layout->setSpacing(12);
			}

			layout->addWidget(main_widget);
		}
		layout->setSpacing(12);
		layout->setContentsMargins(0, 0, 0, 0);
		full_layout->addWidget(widget);
	}

	{
		/* Dialog box buttons */
		QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
		connect(button_box, &QDialogButtonBox::accepted, this, [this, accept, anime] {
			SaveData(anime);
			accept(anime);
			QDialog::accept();
		});
		connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
		full_layout->addWidget(button_box, 0, Qt::AlignBottom);
	}
}

void InformationDialog::showEvent(QShowEvent* event) {
	QDialog::showEvent(event);
#ifdef WIN32
	win32::SetTitleBarsToBlack(session.config.theme.IsInDarkTheme());
#endif
}