view src/gui/pages/seasons.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 b5d6c27c308f
children 83e6ba09338f
line wrap: on
line source

#include "gui/pages/seasons.h"

#include "core/anime_db.h"
#include "core/strings.h"
#include "gui/widgets/anime_button.h"
#include "gui/translate/anime.h"
#include "services/services.h"

#include <QDate>
#include <QFrame>
#include <QListWidget>
#include <QListWidgetItem>
#include <QMenu>
#include <QToolBar>
#include <QToolButton>
#include <QVBoxLayout>

#include <iostream>

SeasonsPageSearchThread::SeasonsPageSearchThread(QObject* parent) : QThread(parent) {
}

void SeasonsPageSearchThread::AddToQueue(Anime::Season season) {
	queue_mutex_.lock();
	queue_.push(season);
	queue_mutex_.unlock();
}

void SeasonsPageSearchThread::run() {
	queue_mutex_.lock();

	while (!queue_.empty() && !isInterruptionRequested()) {
		Anime::Season season = queue_.front();

		/* unlock the mutex for a long blocking operation, so items
		 * can be added without worry */
		queue_mutex_.unlock();

		if (Services::GetSeason(season))
			emit ReceivedSeason(season);

		queue_mutex_.lock();

		queue_.pop();
	}

	queue_mutex_.unlock();
}

static SeasonsPageSearchThread search_thread_;

/* ------------------------------------------------------------------------------------- */

static constexpr Date::Year GetClosestDecade(Date::Year year) {
	return year - (year % 10);
}

void SeasonsPage::Refresh() {
	setUpdatesEnabled(false);

	if (!buttons)
		return;

	buttons->clear();

	for (const auto& id : Anime::db.GetAllAnimeForSeason(season_)) {
		QListWidgetItem* item = new QListWidgetItem;
		AnimeButton* button = new AnimeButton(this);
		button->SetAnime(Anime::db.items[id]);
		item->setSizeHint(button->sizeHint());
		buttons->addItem(item);
		buttons->setItemWidget(item, button);
	}

	season_button.setText(Strings::ToQString(Translate::ToLocalString(season_)));

	setUpdatesEnabled(true);
}

void SeasonsPage::SetSeason(Anime::Season season) {
	season_ = season;

	Refresh();
}

SeasonsPage::SeasonsPage(QWidget* parent) : QFrame(parent) {
	setBackgroundRole(QPalette::Base);
	setFrameShape(QFrame::Box);
	setFrameShadow(QFrame::Sunken);

	QVBoxLayout* full_layout = new QVBoxLayout(this);

	{
		/* Toolbar */
		QToolBar* toolbar = new QToolBar(this);
		toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
		toolbar->setIconSize(QSize(16, 16));
		toolbar->setMovable(false);

		{
			/* XXX this last year probably shouldn't be hardcoded */
			static const Anime::Season last_season(Anime::Season::Name::Winter, 1960);
			Anime::Season current_season(Date(QDate::currentDate()));
			const Date::Year year_before_collapse = GetClosestDecade(current_season.year) - 10;

			/* year -> menu for that year */
			std::map<Date::Year, QMenu*> menu_map;

			auto create_season_menu = [&](QWidget* parent, Anime::Season season){
				QMenu*& menu = menu_map[season.year];
				if (!menu)
					menu = new QMenu(QString::number(season.year), parent);

				QAction* action = menu->addAction(Strings::ToQString(Translate::ToLocalString(season)));
				connect(action, &QAction::triggered, this, [this, season] {
					SetSeason(season);
				});
			};

			for (Anime::Season s = current_season; s >= last_season; --s)
				create_season_menu(&season_button, s);

			/* ------------------------------------------------------- */
			/* now actually generate the full menu */

			QMenu* full_menu = new QMenu(&season_button);

			for (Date::Year c = current_season.year; c >= year_before_collapse; c--)
				full_menu->addMenu(menu_map[c]);

			full_menu->addSeparator();

			/* collapse each menu into a decade */
			for (Date::Year c = year_before_collapse - 10; c >= last_season.year; c -= 10) {
				QMenu* decade_menu = new QMenu(tr("%1s").arg(QString::number(c)), parent);
				for (Date::Year i = c + 9; i >= c; i--)
					decade_menu->addMenu(menu_map[i]);
				full_menu->addMenu(decade_menu);
			}

			season_button.setMenu(full_menu);
			season_button.setPopupMode(QToolButton::InstantPopup);

			toolbar->addWidget(&season_button);
		}

		toolbar->addSeparator();

		{
			toolbar->addAction(QIcon(":/icons/16x16/arrow-circle-315.png"), tr("Refresh data"), [this]{
				search_thread_.AddToQueue(season_);
				if (!search_thread_.isRunning())
					search_thread_.start();
			});
		}

		toolbar->addSeparator();

		{
			QToolButton* button = new QToolButton(toolbar);

			{
				/* links */
				QMenu* menu = new QMenu(button);
				menu->addAction(tr("Airing status"));
				menu->addAction(tr("List status"));
				menu->addAction(tr("Type"));
				button->setMenu(menu);
			}

			button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
			button->setIcon(QIcon(":/icons/16x16/category.png"));
			button->setText(tr("Group by:"));
			button->setPopupMode(QToolButton::InstantPopup);
			toolbar->addWidget(button);
		}

		{
			QToolButton* button = new QToolButton(toolbar);

			{
				/* links */
				QMenu* menu = new QMenu(button);
				menu->addAction(tr("Airing date"));
				menu->addAction(tr("Episodes"));
				menu->addAction(tr("Popularity"));
				menu->addAction(tr("Score"));
				menu->addAction(tr("Title"));
				button->setMenu(menu);
			}

			button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
			button->setIcon(QIcon(":/icons/16x16/sort-quantity-descending.png"));
			button->setText(tr("Sort by:"));
			button->setPopupMode(QToolButton::InstantPopup);
			toolbar->addWidget(button);
		}

		{
			QToolButton* button = new QToolButton(toolbar);

			{
				/* links */
				QMenu* menu = new QMenu(button);
				menu->addAction(tr("Images"));
				menu->addAction(tr("Details"));
				button->setMenu(menu);
			}

			button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
			button->setIcon(QIcon(":/icons/16x16/ui-scroll-pane-detail.png"));
			button->setText(tr("View:"));
			button->setPopupMode(QToolButton::InstantPopup);
			toolbar->addWidget(button);
		}

		full_layout->addWidget(toolbar);
	}

	{
		QFrame* line = new QFrame(this);
		line->setFrameShape(QFrame::HLine);
		line->setFrameShadow(QFrame::Sunken);
		line->setLineWidth(1);
		full_layout->addWidget(line);
	}

	{
		buttons = new QListWidget(this);
		buttons->setFlow(QListView::LeftToRight);
		buttons->setWrapping(true);
		buttons->setContentsMargins(4, 4, 4, 4);
		buttons->setSpacing(2);
		buttons->setResizeMode(QListView::Adjust);

		full_layout->addWidget(buttons);
	}

	full_layout->setContentsMargins(0, 0, 0, 0);
	full_layout->setSpacing(0);

	connect(&search_thread_, &SeasonsPageSearchThread::ReceivedSeason, this, [this](Anime::Season season) {
		if (season == season_)
			Refresh();
	});

	/* Do NOT move this up in this function, buttons HAS to be initialized */
	SetSeason({Anime::Season::Name::Summer, 2011U});
}