From b936a9e379216cbea1b0fdc772a2727576a4cf32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Wed, 11 Jun 2025 17:02:54 +0200 Subject: [PATCH] Include a status bar for the picture loader. --- cockatrice/CMakeLists.txt | 2 + .../ui/picture_loader/picture_loader.cpp | 12 ++++ .../client/ui/picture_loader/picture_loader.h | 2 + ...e_loader_request_status_display_widget.cpp | 32 +++++++++ ...ure_loader_request_status_display_widget.h | 70 +++++++++++++++++++ .../picture_loader_status_bar.cpp | 55 +++++++++++++++ .../picture_loader_status_bar.h | 29 ++++++++ .../picture_loader/picture_loader_worker.cpp | 5 ++ .../ui/picture_loader/picture_loader_worker.h | 2 + .../picture_loader_worker_work.cpp | 4 -- .../quick_settings/settings_button_widget.cpp | 5 ++ .../quick_settings/settings_button_widget.h | 2 + .../quick_settings/settings_popup_widget.cpp | 6 ++ .../quick_settings/settings_popup_widget.h | 1 + 14 files changed, 223 insertions(+), 4 deletions(-) create mode 100644 cockatrice/src/client/ui/picture_loader/picture_loader_request_status_display_widget.cpp create mode 100644 cockatrice/src/client/ui/picture_loader/picture_loader_request_status_display_widget.h create mode 100644 cockatrice/src/client/ui/picture_loader/picture_loader_status_bar.cpp create mode 100644 cockatrice/src/client/ui/picture_loader/picture_loader_status_bar.h diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index e05460768..846167d93 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -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 diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader.cpp b/cockatrice/src/client/ui/picture_loader/picture_loader.cpp index 61ea8d0ad..1d6681b63 100644 --- a/cockatrice/src/client/ui/picture_loader/picture_loader.cpp +++ b/cockatrice/src/client/ui/picture_loader/picture_loader.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include // 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(QApplication::activeWindow()); + if (mainWindow) { + mainWindow->statusBar()->addPermanentWidget(statusBar); + } + + connect(worker, &PictureLoaderWorker::imageLoadQueued, statusBar, &PictureLoaderStatusBar::addQueuedImageLoad); + connect(worker, &PictureLoaderWorker::imageLoadSuccessful, statusBar, + &PictureLoaderStatusBar::addSuccessfulImageLoad); } PictureLoader::~PictureLoader() diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader.h b/cockatrice/src/client/ui/picture_loader/picture_loader.h index e2769f567..87ebfa862 100644 --- a/cockatrice/src/client/ui/picture_loader/picture_loader.h +++ b/cockatrice/src/client/ui/picture_loader/picture_loader.h @@ -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 @@ -27,6 +28,7 @@ private: void operator=(PictureLoader const &); PictureLoaderWorker *worker; + PictureLoaderStatusBar *statusBar; public: static void getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size); diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader_request_status_display_widget.cpp b/cockatrice/src/client/ui/picture_loader/picture_loader_request_status_display_widget.cpp new file mode 100644 index 000000000..a77eac2f4 --- /dev/null +++ b/cockatrice/src/client/ui/picture_loader/picture_loader_request_status_display_widget.cpp @@ -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); +} \ No newline at end of file diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader_request_status_display_widget.h b/cockatrice/src/client/ui/picture_loader/picture_loader_request_status_display_widget.h new file mode 100644 index 000000000..20c77ee56 --- /dev/null +++ b/cockatrice/src/client/ui/picture_loader/picture_loader_request_status_display_widget.h @@ -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 +#include +#include + +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 diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader_status_bar.cpp b/cockatrice/src/client/ui/picture_loader/picture_loader_status_bar.cpp new file mode 100644 index 000000000..7cd214e93 --- /dev/null +++ b/cockatrice/src/client/ui/picture_loader/picture_loader_status_bar.cpp @@ -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()) { + 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()) { + if (statusDisplayWidget->getUrl() == url) { + statusDisplayWidget->queryElapsedSeconds(); + statusDisplayWidget->setFinished(); + } + } +} \ No newline at end of file diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader_status_bar.h b/cockatrice/src/client/ui/picture_loader/picture_loader_status_bar.h new file mode 100644 index 000000000..6a507cbb0 --- /dev/null +++ b/cockatrice/src/client/ui/picture_loader/picture_loader_status_bar.h @@ -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 +#include +#include + +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 diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader_worker.cpp b/cockatrice/src/client/ui/picture_loader/picture_loader_worker.cpp index 2401d5c67..8c43b795b 100644 --- a/cockatrice/src/client/ui/picture_loader/picture_loader_worker.cpp +++ b/cockatrice/src/client/ui/picture_loader/picture_loader_worker.cpp @@ -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(); }); diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader_worker.h b/cockatrice/src/client/ui/picture_loader/picture_loader_worker.h index 11c13ba36..097de7ba2 100644 --- a/cockatrice/src/client/ui/picture_loader/picture_loader_worker.h +++ b/cockatrice/src/client/ui/picture_loader/picture_loader_worker.h @@ -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 diff --git a/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.cpp b/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.cpp index bcba87297..bc9787767 100644 --- a/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.cpp +++ b/cockatrice/src/client/ui/picture_loader/picture_loader_worker_work.cpp @@ -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()); diff --git a/cockatrice/src/client/ui/widgets/quick_settings/settings_button_widget.cpp b/cockatrice/src/client/ui/widgets/quick_settings/settings_button_widget.cpp index 0818050d8..17087c8bc 100644 --- a/cockatrice/src/client/ui/widgets/quick_settings/settings_button_widget.cpp +++ b/cockatrice/src/client/ui/widgets/quick_settings/settings_button_widget.cpp @@ -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); diff --git a/cockatrice/src/client/ui/widgets/quick_settings/settings_button_widget.h b/cockatrice/src/client/ui/widgets/quick_settings/settings_button_widget.h index 4234ed438..de2723399 100644 --- a/cockatrice/src/client/ui/widgets/quick_settings/settings_button_widget.h +++ b/cockatrice/src/client/ui/widgets/quick_settings/settings_button_widget.h @@ -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; }; diff --git a/cockatrice/src/client/ui/widgets/quick_settings/settings_popup_widget.cpp b/cockatrice/src/client/ui/widgets/quick_settings/settings_popup_widget.cpp index 258f1163e..9b2e55e0f 100644 --- a/cockatrice/src/client/ui/widgets/quick_settings/settings_popup_widget.cpp +++ b/cockatrice/src/client/ui/widgets/quick_settings/settings_popup_widget.cpp @@ -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()); diff --git a/cockatrice/src/client/ui/widgets/quick_settings/settings_popup_widget.h b/cockatrice/src/client/ui/widgets/quick_settings/settings_popup_widget.h index d57c123c4..6b6157b45 100644 --- a/cockatrice/src/client/ui/widgets/quick_settings/settings_popup_widget.h +++ b/cockatrice/src/client/ui/widgets/quick_settings/settings_popup_widget.h @@ -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: