view src/gui/widgets/poster.cc @ 378:5912dafc6e28

anime: add poster cache :)
author Paper <paper@tflc.us>
date Wed, 05 Nov 2025 12:50:35 -0500
parents ea3a74ed2ef9
children
line wrap: on
line source

#include "gui/widgets/poster.h"
#include "core/anime_db.h"
#include "core/http.h"
#include "core/session.h"
#include "core/strings.h"
#include "gui/widgets/clickable_label.h"

#include <QByteArray>
#include <QDebug>
#include <QDesktopServices>
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <QPixmap>
#include <QThread>
#include <QUrl>

#include <iostream>

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

void GetPosterThread::SetId(int id)
{
	id_ = id;
}

void GetPosterThread::run()
{
	/* this sucks cuz we can't really STOP the thread easily
	 * without making it fully finish */
	QImage img = Anime::db.GetAnimePoster(id_);

	emit Finished(img);
}

Poster::Poster(QWidget *parent) : QFrame(parent)
{
	QHBoxLayout *layout = new QHBoxLayout(this);
	layout->setContentsMargins(1, 1, 1, 1);

	setCursor(Qt::PointingHandCursor);
	setFixedSize(150, 225); // FIXME need to kill this
	setFrameShape(QFrame::Box);
	setFrameShadow(QFrame::Plain);

	label_.setAlignment(Qt::AlignCenter);
	layout->addWidget(&label_);

	get_thread_ = new GetPosterThread(nullptr);
	connect(get_thread_, &GetPosterThread::Finished, this, &Poster::ImageDownloadFinished);
}

Poster::Poster(const Anime::Anime &anime, QWidget *parent) : Poster(parent)
{
	SetAnime(anime);
}

Poster::~Poster()
{
	/* schedule deletion of the thread */
	get_thread_->deleteLater();
}

void Poster::DownloadPoster()
{
	/* ;-; */
	get_thread_->wait();

	get_thread_->SetId(id_);
	get_thread_->start();
}

void Poster::SetAnime(const Anime::Anime &anime)
{
	label_.clear();

	id_ = anime.GetId();

	if (isVisible()) {
		DownloadPoster();
	} else {
		need_refresh_ = true;
	}

	std::optional<std::string> url = anime.GetServiceUrl(session.config.service);
	if (url)
		service_url_ = Strings::ToQString(url.value());

	if (clickable_) {
		label_.disconnect();
		connect(&label_, &ClickableLabel::clicked, this, [this] { QDesktopServices::openUrl(service_url_); });
	}
}

void Poster::showEvent(QShowEvent *event)
{
	if (need_refresh_) {
		DownloadPoster();
		need_refresh_ = false;
	}
}

void Poster::SetClickable(bool enabled)
{
	clickable_ = enabled;

	if (clickable_ && !service_url_.isEmpty()) {
		setCursor(Qt::PointingHandCursor);
		label_.disconnect();
		connect(&label_, &ClickableLabel::clicked, this, [this] { QDesktopServices::openUrl(service_url_); });
	} else {
		setCursor(Qt::ArrowCursor);
		label_.disconnect();
	}
}

void Poster::ImageDownloadFinished(const QImage &img)
{
	img_ = img;
	RenderToLabel();
}

void Poster::RenderToLabel()
{
	const QPixmap pixmap = QPixmap::fromImage(img_);
	if (pixmap.isNull())
		return;
	label_.setPixmap(pixmap.scaled(label_.size(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
}

bool Poster::hasHeightForWidth(void) const
{
	return true;
}

int Poster::heightForWidth(int w) const
{
	return static_cast<int>(static_cast<double>(w) * 225 / 150);
}

void Poster::resizeEvent(QResizeEvent *)
{
	RenderToLabel();
}

QSize Poster::minimumSizeHint() const
{
	return QSize(120, heightForWidth(120));
}

QSize Poster::sizeHint() const
{
	return QSize(150, heightForWidth(150));
}