Include a status bar for the picture loader.

This commit is contained in:
Lukas Brübach 2025-06-11 17:02:54 +02:00
parent a9716d6948
commit b936a9e379
14 changed files with 223 additions and 4 deletions

View file

@ -67,6 +67,8 @@ set(cockatrice_SOURCES
src/client/ui/line_edit_completer.cpp
src/client/ui/phases_toolbar.cpp
src/client/ui/picture_loader/picture_loader.cpp
src/client/ui/picture_loader/picture_loader_request_status_display_widget.cpp
src/client/ui/picture_loader/picture_loader_status_bar.cpp
src/client/ui/picture_loader/picture_loader_worker.cpp
src/client/ui/picture_loader/picture_loader_worker_work.cpp
src/client/ui/picture_loader/picture_to_load.cpp

View file

@ -7,6 +7,7 @@
#include <QDebug>
#include <QDirIterator>
#include <QFileInfo>
#include <QMainWindow>
#include <QMovie>
#include <QNetworkDiskCache>
#include <QNetworkRequest>
@ -15,6 +16,7 @@
#include <QScreen>
#include <QThread>
#include <algorithm>
#include <qstatusbar.h>
#include <utility>
// never cache more than 300 cards at once for a single deck
@ -27,6 +29,16 @@ PictureLoader::PictureLoader() : QObject(nullptr)
connect(&SettingsCache::instance(), &SettingsCache::picDownloadChanged, this, &PictureLoader::picDownloadChanged);
connect(worker, &PictureLoaderWorker::imageLoaded, this, &PictureLoader::imageLoaded);
statusBar = new PictureLoaderStatusBar(nullptr);
QMainWindow *mainWindow = qobject_cast<QMainWindow *>(QApplication::activeWindow());
if (mainWindow) {
mainWindow->statusBar()->addPermanentWidget(statusBar);
}
connect(worker, &PictureLoaderWorker::imageLoadQueued, statusBar, &PictureLoaderStatusBar::addQueuedImageLoad);
connect(worker, &PictureLoaderWorker::imageLoadSuccessful, statusBar,
&PictureLoaderStatusBar::addSuccessfulImageLoad);
}
PictureLoader::~PictureLoader()

View file

@ -2,6 +2,7 @@
#define PICTURELOADER_H
#include "../../../game/cards/card_info.h"
#include "picture_loader_status_bar.h"
#include "picture_loader_worker.h"
#include <QLoggingCategory>
@ -27,6 +28,7 @@ private:
void operator=(PictureLoader const &);
PictureLoaderWorker *worker;
PictureLoaderStatusBar *statusBar;
public:
static void getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size);

View file

@ -0,0 +1,32 @@
#include "picture_loader_request_status_display_widget.h"
PictureLoaderRequestStatusDisplayWidget::PictureLoaderRequestStatusDisplayWidget(QWidget *parent,
const QUrl &_url,
PictureLoaderWorkerWork *worker)
: QWidget(parent)
{
layout = new QHBoxLayout(this);
name = new QLabel(this);
name->setText(worker->cardToDownload.getCard()->getName());
setShortname = new QLabel(this);
setShortname->setText(worker->cardToDownload.getSetName());
providerId = new QLabel(this);
providerId->setText(worker->cardToDownload.getCard()->getProperty("uuid"));
startTime = new QLabel(this);
startTime->setText(QDateTime::currentDateTime().toString());
elapsedTime = new QLabel(this);
elapsedTime->setText("0");
finished = new QLabel(this);
finished->setText("False");
url = new QLabel(this);
url->setText(_url.toString());
layout->addWidget(name);
layout->addWidget(setShortname);
layout->addWidget(providerId);
layout->addWidget(startTime);
layout->addWidget(elapsedTime);
layout->addWidget(finished);
layout->addWidget(url);
}

View file

@ -0,0 +1,70 @@
#ifndef PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
#define PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
#include "../../../../../../../../../../mnt/games-hdd/coding/CLionProjects/Cockatrice/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QWidget>
struct PictureLoaderRequestStatus
{
};
class PictureLoaderRequestStatusDisplayWidget : public QWidget
{
Q_OBJECT
public:
PictureLoaderRequestStatusDisplayWidget(QWidget *parent, const QUrl &url, PictureLoaderWorkerWork *worker);
PictureLoaderWorkerWork *worker;
void setFinished()
{
finished->setText("True");
update();
repaint();
}
bool getFinished() const
{
return finished->text() == "True";
}
void setElapsedTime(const QString &_elapsedTime) const
{
elapsedTime->setText(_elapsedTime);
}
int queryElapsedSeconds()
{
if (!finished) {
elapsedTime->setText(
QString::number(QDateTime::fromString(startTime->text()).secsTo(QDateTime::currentDateTime())));
update();
repaint();
return QDateTime::fromString(startTime->text()).secsTo(QDateTime::currentDateTime());
}
return elapsedTime->text().toInt();
}
QString getStartTime() const
{
return startTime->text();
}
QString getUrl() const
{
return url->text();
}
private:
QHBoxLayout *layout;
QLabel *name;
QLabel *setShortname;
QLabel *providerId;
QLabel *startTime;
QLabel *elapsedTime;
QLabel *finished;
QLabel *url;
};
#endif // PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H

View file

@ -0,0 +1,55 @@
#include "picture_loader_status_bar.h"
#include "picture_loader_request_status_display_widget.h"
PictureLoaderStatusBar::PictureLoaderStatusBar(QWidget *parent) : QWidget(parent)
{
layout = new QHBoxLayout(this);
progressBar = new QProgressBar(this);
progressBar->setMaximum(0);
progressBar->setFormat("%v/%m");
layout->addWidget(progressBar);
loadLog = new SettingsButtonWidget(this);
layout->addWidget(loadLog);
cleaner = new QTimer(this);
cleaner->setInterval(1000);
connect(cleaner, &QTimer::timeout, this, &PictureLoaderStatusBar::cleanOldEntries);
cleaner->start();
setLayout(layout);
}
void PictureLoaderStatusBar::cleanOldEntries()
{
for (PictureLoaderRequestStatusDisplayWidget *statusDisplayWidget :
loadLog->popup->findChildren<PictureLoaderRequestStatusDisplayWidget *>()) {
statusDisplayWidget->queryElapsedSeconds();
if (statusDisplayWidget->getFinished() &&
QDateTime::fromString(statusDisplayWidget->getStartTime()).secsTo(QDateTime::currentDateTime()) > 10) {
loadLog->removeSettingsWidget(statusDisplayWidget);
progressBar->setMaximum(progressBar->maximum() - 1);
progressBar->setValue(progressBar->value() - 1);
}
}
}
void PictureLoaderStatusBar::addQueuedImageLoad(const QUrl &url, PictureLoaderWorkerWork *worker)
{
loadLog->addSettingsWidget(new PictureLoaderRequestStatusDisplayWidget(loadLog, url, worker));
progressBar->setMaximum(progressBar->maximum() + 1);
}
void PictureLoaderStatusBar::addSuccessfulImageLoad(const QUrl &url, PictureLoaderWorkerWork *worker)
{
Q_UNUSED(worker)
progressBar->setValue(progressBar->value() + 1);
for (PictureLoaderRequestStatusDisplayWidget *statusDisplayWidget :
loadLog->popup->findChildren<PictureLoaderRequestStatusDisplayWidget *>()) {
if (statusDisplayWidget->getUrl() == url) {
statusDisplayWidget->queryElapsedSeconds();
statusDisplayWidget->setFinished();
}
}
}

View file

@ -0,0 +1,29 @@
#ifndef PICTURE_LOADER_STATUS_BAR_H
#define PICTURE_LOADER_STATUS_BAR_H
#include "../widgets/quick_settings/settings_button_widget.h"
#include "picture_loader_worker_work.h"
#include <QHBoxLayout>
#include <QProgressBar>
#include <QWidget>
class PictureLoaderStatusBar : public QWidget
{
Q_OBJECT
public:
explicit PictureLoaderStatusBar(QWidget *parent);
public slots:
void addQueuedImageLoad(const QUrl &url, PictureLoaderWorkerWork *worker);
void addSuccessfulImageLoad(const QUrl &url, PictureLoaderWorkerWork *worker);
void cleanOldEntries();
private:
QHBoxLayout *layout;
QProgressBar *progressBar;
SettingsButtonWidget *loadLog;
QTimer *cleaner;
};
#endif // PICTURE_LOADER_STATUS_BAR_H

View file

@ -76,6 +76,7 @@ void PictureLoaderWorker::queueRequest(const QUrl &url, PictureLoaderWorkerWork
makeRequest(url, worker);
} else {
requestLoadQueue.append(qMakePair(url, worker));
emit imageLoadQueued(url, worker);
}
@ -86,6 +87,7 @@ QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url, PictureLoaderWo
// Check for cached redirects
QUrl cachedRedirect = getCachedRedirect(url);
if (!cachedRedirect.isEmpty()) {
emit imageLoadSuccessful(url, worker);
return makeRequest(cachedRedirect, worker);
}
@ -109,6 +111,9 @@ QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url, PictureLoaderWo
if (reply->error() == QNetworkReply::NoError) {
worker->picDownloadFinished(reply);
emit imageLoadSuccessful(url, worker);
} else if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 429) {
qInfo() << "Too many requests.";
}
reply->deleteLater();
});

View file

@ -74,6 +74,8 @@ private slots:
signals:
void startLoadQueue();
void imageLoaded(CardInfoPtr card, const QImage &image);
void imageLoadQueued(const QUrl &url, PictureLoaderWorkerWork *worker);
void imageLoadSuccessful(const QUrl &url, PictureLoaderWorkerWork *worker);
};
#endif // PICTURE_LOADER_WORKER_H

View file

@ -169,10 +169,6 @@ void PictureLoaderWorkerWork::picDownloadFinished(QNetworkReply *reply)
return;
}
if (statusCode == 429) {
qWarning() << "Scryfall API limit reached!";
}
// peek is used to keep the data in the buffer for use by QImageReader
const QByteArray &picData = reply->peek(reply->size());

View file

@ -26,6 +26,11 @@ void SettingsButtonWidget::addSettingsWidget(QWidget *toAdd) const
popup->addSettingsWidget(toAdd);
}
void SettingsButtonWidget::removeSettingsWidget(QWidget *toRemove) const
{
popup->removeSettingsWidget(toRemove);
}
void SettingsButtonWidget::setButtonIcon(QPixmap iconMap)
{
button->setIcon(iconMap);

View file

@ -13,6 +13,7 @@ class SettingsButtonWidget : public QWidget
public:
explicit SettingsButtonWidget(QWidget *parent = nullptr);
void addSettingsWidget(QWidget *toAdd) const;
void removeSettingsWidget(QWidget *toRemove) const;
void setButtonIcon(QPixmap iconMap);
protected:
@ -25,6 +26,7 @@ private slots:
private:
QHBoxLayout *layout;
QToolButton *button;
public:
SettingsPopupWidget *popup;
};

View file

@ -29,6 +29,12 @@ void SettingsPopupWidget::addSettingsWidget(QWidget *toAdd) const
containerLayout->addWidget(toAdd); // Add to containerWidget's layout
}
void SettingsPopupWidget::removeSettingsWidget(QWidget *toRemove) const
{
containerLayout->removeWidget(toRemove);
toRemove->deleteLater();
}
void SettingsPopupWidget::adjustSizeToFitScreen()
{
QScreen *screen = QApplication::screenAt(this->pos());

View file

@ -13,6 +13,7 @@ class SettingsPopupWidget : public QWidget
public:
explicit SettingsPopupWidget(QWidget *parent = nullptr);
void addSettingsWidget(QWidget *toAdd) const;
void removeSettingsWidget(QWidget *toRemove) const;
void adjustSizeToFitScreen();
signals: