New style for deck listing.

This commit is contained in:
Brübach, Lukas 2025-11-25 09:39:04 +01:00
parent 45c599cae9
commit 5a685beba2
2 changed files with 92 additions and 54 deletions

View file

@ -1,6 +1,10 @@
#include "archidekt_api_response_deck_entry_display_widget.h" #include "archidekt_api_response_deck_entry_display_widget.h"
#include "../../../../../card_picture_loader/card_picture_loader.h"
#include "../../../../cards/card_info_picture_with_text_overlay_widget.h" #include "../../../../cards/card_info_picture_with_text_overlay_widget.h"
#include "../../../../general/display/background_plate_widget.h"
#include "../../../../general/display/color_bar.h"
#include "archidekt_deck_preview_image_display_widget.h"
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
@ -9,6 +13,30 @@
#include <QPixmap> #include <QPixmap>
#include <QWidget> #include <QWidget>
QString timeAgo(const QString &timestamp)
{
QDateTime dt = QDateTime::fromString(timestamp, Qt::ISODate);
if (!dt.isValid())
return timestamp; // fallback if parsing fails
qint64 secs = dt.secsTo(QDateTime::currentDateTimeUtc());
if (secs < 60)
return QString("%1 seconds ago").arg(secs);
if (secs < 3600)
return QString("%1 minutes ago").arg(secs / 60);
if (secs < 86400)
return QString("%1 hours ago").arg(secs / 3600);
if (secs < 30*86400)
return QString("%1 days ago").arg(secs / 86400);
if (secs < 365*86400)
return QString("%1 months ago").arg(secs / (30*86400));
return QString("%1 years ago").arg(secs / (365*86400));
}
ArchidektApiResponseDeckEntryDisplayWidget::ArchidektApiResponseDeckEntryDisplayWidget( ArchidektApiResponseDeckEntryDisplayWidget::ArchidektApiResponseDeckEntryDisplayWidget(
QWidget *parent, QWidget *parent,
ArchidektApiResponseDeckListingContainer _response, ArchidektApiResponseDeckListingContainer _response,
@ -18,69 +46,72 @@ ArchidektApiResponseDeckEntryDisplayWidget::ArchidektApiResponseDeckEntryDisplay
layout = new QVBoxLayout(this); layout = new QVBoxLayout(this);
setLayout(layout); setLayout(layout);
this->setMaximumWidth(200); this->setMaximumWidth(400);
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
auto headerLayout = new QVBoxLayout(); auto headerLayout = new QVBoxLayout();
QLabel *deckNameLabel = new QLabel(QString("%1 (%2)").arg(response.getName()).arg(response.getSize())); previewWidget = new ArchidektDeckPreviewImageDisplayWidget(this);
deckNameLabel->setWordWrap(true); // Allow text to wrap
deckNameLabel->setStyleSheet("font-size: 14px; font-weight: bold;");
deckNameLabel->setMaximumWidth(200);
headerLayout->addWidget(deckNameLabel);
// Featured image (Deck Preview Image) previewWidget->setMaximumWidth(400);
picture = new QLabel(this); previewWidget->setMinimumHeight(300); // consistent height
picture->setText("Loading Image...");
picture->setAlignment(Qt::AlignCenter); // Set deck name (ellided)
picture->setMaximumWidth(200); {
QFontMetrics fm(previewWidget->topLeftLabel->font());
QString elided = fm.elidedText(response.getName(), Qt::ElideRight, 280);
previewWidget->topLeftLabel->setText(elided);
previewWidget->topLeftLabel->setToolTip(response.getName());
}
// Set count
previewWidget->topRightLabel->setText(QString::number(response.getSize()));
// EDH bracket (skip if 0)
if (response.getEDHBracket() != 0)
previewWidget->bottomLeftLabel->setText(QString("EDH: %1").arg(response.getEDHBracket()));
else
previewWidget->bottomLeftLabel->hide();
// Views
previewWidget->bottomRightLabel->setText(QString("Views: %1").arg(response.getViewCount()));
// Use preview->imageLabel for image loading
picture = previewWidget->imageLabel;
QNetworkRequest req(QUrl(response.getFeatured())); QNetworkRequest req(QUrl(response.getFeatured()));
imageNetworkManager->get(req); imageNetworkManager->get(req);
connect(imageNetworkManager, &QNetworkAccessManager::finished, this, connect(imageNetworkManager, &QNetworkAccessManager::finished, this,
&ArchidektApiResponseDeckEntryDisplayWidget::onPreviewImageLoadFinished); &ArchidektApiResponseDeckEntryDisplayWidget::onPreviewImageLoadFinished);
headerLayout->addWidget(picture); headerLayout->addWidget(previewWidget);
auto colors = response.getColors();
ColorBar *colorBar = new ColorBar(colors, this);
colorBar->setFixedHeight(22);
headerLayout->addWidget(colorBar);
// Create a shared plate for the labels
BackgroundPlateWidget *sharedPlate = new BackgroundPlateWidget(this);
sharedPlate->setFixedHeight(120); // Adjust height to fit all labels
QVBoxLayout *plateLayout = new QVBoxLayout(sharedPlate);
// Add labels to the plate layout
QLabel *ownerLabel = new QLabel(QString("Owner: %1").arg(response.getOwner().getName())); QLabel *ownerLabel = new QLabel(QString("Owner: %1").arg(response.getOwner().getName()));
ownerLabel->setWordWrap(true); plateLayout->addWidget(ownerLabel);
ownerLabel->setMaximumWidth(200);
headerLayout->addWidget(ownerLabel);
QLabel *edhBracketLabel = new QLabel(QString("EDH Bracket: %1").arg(response.getEDHBracket())); QLabel *createdAtLabel = new QLabel(QString("Created: %1").arg(timeAgo(response.getCreatedAt())));
edhBracketLabel->setWordWrap(true); plateLayout->addWidget(createdAtLabel);
edhBracketLabel->setMaximumWidth(200);
headerLayout->addWidget(edhBracketLabel);
QLabel *viewCountLabel = new QLabel(QString("Views: %1").arg(response.getViewCount())); QLabel *updatedAtLabel = new QLabel(QString("Updated: %1").arg(timeAgo(response.getUpdatedAt())));
viewCountLabel->setWordWrap(true); plateLayout->addWidget(updatedAtLabel);
viewCountLabel->setMaximumWidth(200);
headerLayout->addWidget(viewCountLabel);
QLabel *createdAtLabel = new QLabel(QString("Created: %1").arg(response.getCreatedAt())); // Add the shared plate to the header layout
createdAtLabel->setWordWrap(true); headerLayout->addWidget(sharedPlate);
createdAtLabel->setMaximumWidth(200);
QLabel *updatedAtLabel = new QLabel(QString("Updated: %1").arg(response.getUpdatedAt()));
updatedAtLabel->setWordWrap(true);
updatedAtLabel->setMaximumWidth(200);
headerLayout->addWidget(createdAtLabel);
headerLayout->addWidget(updatedAtLabel);
QLabel *colorsLabel = new QLabel("Colors: ");
QStringList colorNames;
for (auto color : response.getColors().keys()) {
colorNames << color;
}
if (colorNames.isEmpty()) {
colorsLabel->setText("Colors: None");
} else {
colorsLabel->setText("Colors: " + colorNames.join(", "));
}
colorsLabel->setWordWrap(true);
colorsLabel->setMaximumWidth(200);
headerLayout->addWidget(colorsLabel);
layout->addLayout(headerLayout); layout->addLayout(headerLayout);
@ -104,7 +135,12 @@ void ArchidektApiResponseDeckEntryDisplayWidget::onPreviewImageLoadFinished(QNet
} }
if (reply->error() != QNetworkReply::NoError) { if (reply->error() != QNetworkReply::NoError) {
picture->setText("Error loading"); QPixmap pixmap;
CardPictureLoader::getCardBackLoadingFailedPixmap(pixmap, QSize(400, 400));
picture->setPixmap(pixmap.scaled(400, 400, Qt::KeepAspectRatio, Qt::SmoothTransformation));
previewWidget->update();
previewWidget->updateGeometry();
reply->deleteLater(); reply->deleteLater();
return; return;
} }
@ -112,11 +148,12 @@ void ArchidektApiResponseDeckEntryDisplayWidget::onPreviewImageLoadFinished(QNet
QByteArray imageData = reply->readAll(); QByteArray imageData = reply->readAll();
QPixmap pixmap; QPixmap pixmap;
if (pixmap.loadFromData(imageData)) { if (!pixmap.loadFromData(imageData)) {
picture->setPixmap(pixmap.scaled(150, 150, Qt::KeepAspectRatio, Qt::SmoothTransformation)); CardPictureLoader::getCardBackLoadingFailedPixmap(pixmap, QSize(400, 400));
} else {
picture->setText("Invalid image");
} }
picture->setPixmap(pixmap.scaled(400, 400, Qt::KeepAspectRatio, Qt::SmoothTransformation));
previewWidget->update();
previewWidget->updateGeometry();
reply->deleteLater(); reply->deleteLater();
} }
@ -132,4 +169,4 @@ void ArchidektApiResponseDeckEntryDisplayWidget::resizeEvent(QResizeEvent *event
void ArchidektApiResponseDeckEntryDisplayWidget::actRequestNavigationToDeck() void ArchidektApiResponseDeckEntryDisplayWidget::actRequestNavigationToDeck()
{ {
emit requestNavigation(QString("https://archidekt.com/api/decks/%1/").arg(response.getId())); emit requestNavigation(QString("https://archidekt.com/api/decks/%1/").arg(response.getId()));
} }

View file

@ -3,6 +3,7 @@
#include "../../../../cards/card_info_picture_with_text_overlay_widget.h" #include "../../../../cards/card_info_picture_with_text_overlay_widget.h"
#include "../api_response/deck_listings/archidekt_api_response_deck_listing_container.h" #include "../api_response/deck_listings/archidekt_api_response_deck_listing_container.h"
#include "archidekt_deck_preview_image_display_widget.h"
#include <QLabel> #include <QLabel>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
@ -34,8 +35,8 @@ private:
QVBoxLayout *layout; QVBoxLayout *layout;
ArchidektApiResponseDeckListingContainer response; ArchidektApiResponseDeckListingContainer response;
QNetworkAccessManager *imageNetworkManager; QNetworkAccessManager *imageNetworkManager;
ArchidektDeckPreviewImageDisplayWidget *previewWidget;
QLabel *picture; QLabel *picture;
CardInfoPictureWithTextOverlayWidget *deckPreviewDisplayWidget;
}; };
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_ENTRY_DISPLAY_WIDGET_H #endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_ENTRY_DISPLAY_WIDGET_H