view src/gui/dialog/information.cc @ 337:a7d4e5107531

dep/animone: REFACTOR ALL THE THINGS 1: animone now has its own syntax divergent from anisthesia, making different platforms actually have their own sections 2: process names in animone are now called `comm' (this will probably break things). this is what its called in bsd/linux so I'm just going to use it everywhere 3: the X11 code now checks for the existence of a UTF-8 window title and passes it if available 4: ANYTHING THATS NOT LINUX IS 100% UNTESTED AND CAN AND WILL BREAK! I still actually need to test the bsd code. to be honest I'm probably going to move all of the bsds into separate files because they're all essentially different operating systems at this point
author Paper <paper@paper.us.eu.org>
date Wed, 19 Jun 2024 12:51:15 -0400
parents 5d3c9b31aa6e
children 6b0768158dcd
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(Strings::ToQString(anime->GetUserPreferredTitle()), main_widget);
				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);
					settings_layout->addWidget(new TextWidgets::Header(tr("Anime list"), settings_widget));

					{
						/* 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
}