mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-09 17:44:01 -07:00
Search bar, fancier display, resolve providerId
This commit is contained in:
parent
6edaa6db25
commit
cbbe9e7da0
8 changed files with 274 additions and 25 deletions
|
|
@ -19,6 +19,11 @@ public:
|
|||
// Debug method for logging
|
||||
void debugPrint() const;
|
||||
|
||||
QString getName() const
|
||||
{
|
||||
return userName;
|
||||
}
|
||||
|
||||
private:
|
||||
int id;
|
||||
QString userName;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
#include "../../../../cards/card_size_widget.h"
|
||||
#include "../../../../cards/deck_card_zone_display_widget.h"
|
||||
#include "../api_response/deck/archidekt_api_response_deck.h"
|
||||
#include "custom_category_grouping_deck_list_proxy_model.h"
|
||||
#include "deck_list_model.h"
|
||||
#include "libcockatrice/card/database/card_database_manager.h"
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
|
|
@ -59,6 +57,8 @@ ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWi
|
|||
connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset);
|
||||
model->getDeckList()->loadFromStream_Plain(deckStream, false);
|
||||
|
||||
DeckLoader::resolveSetNameAndNumberToProviderID(model->getDeckList());
|
||||
|
||||
model->rebuildTree();
|
||||
|
||||
retranslateUi();
|
||||
|
|
|
|||
|
|
@ -1,23 +1,122 @@
|
|||
#include "archidekt_api_response_deck_entry_display_widget.h"
|
||||
|
||||
#include "../../../../cards/card_info_picture_with_text_overlay_widget.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QPixmap>
|
||||
|
||||
ArchidektApiResponseDeckEntryDisplayWidget::ArchidektApiResponseDeckEntryDisplayWidget(
|
||||
QWidget *parent,
|
||||
ArchidektApiResponseDeckListingContainer _response)
|
||||
: QWidget(parent), response(_response)
|
||||
ArchidektApiResponseDeckListingContainer _response,
|
||||
QNetworkAccessManager *_imageNetworkManager)
|
||||
: QWidget(parent), response(_response), imageNetworkManager(_imageNetworkManager)
|
||||
{
|
||||
layout = new QHBoxLayout(this);
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
// Add widgets for deck listings
|
||||
this->setMaximumWidth(200);
|
||||
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
|
||||
deckPreviewDisplayWidget = new CardInfoPictureWithTextOverlayWidget(this);
|
||||
auto headerLayout = new QVBoxLayout();
|
||||
|
||||
QLabel *deckNameLabel = new QLabel(QString("%1 (%2)").arg(response.getName()).arg(response.getSize()));
|
||||
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)
|
||||
picture = new QLabel(this);
|
||||
picture->setText("Loading Image...");
|
||||
picture->setAlignment(Qt::AlignCenter);
|
||||
picture->setMaximumWidth(200);
|
||||
|
||||
QNetworkRequest req(QUrl(response.getFeatured()));
|
||||
imageNetworkManager->get(req);
|
||||
connect(imageNetworkManager, &QNetworkAccessManager::finished,
|
||||
this, &ArchidektApiResponseDeckEntryDisplayWidget::onPreviewImageLoadFinished);
|
||||
|
||||
headerLayout->addWidget(picture);
|
||||
|
||||
QLabel *ownerLabel = new QLabel(QString("Owner: %1").arg(response.getOwner().getName()));
|
||||
ownerLabel->setWordWrap(true);
|
||||
ownerLabel->setMaximumWidth(200);
|
||||
headerLayout->addWidget(ownerLabel);
|
||||
|
||||
QLabel *edhBracketLabel = new QLabel(QString("EDH Bracket: %1").arg(response.getEDHBracket()));
|
||||
edhBracketLabel->setWordWrap(true);
|
||||
edhBracketLabel->setMaximumWidth(200);
|
||||
headerLayout->addWidget(edhBracketLabel);
|
||||
|
||||
QLabel *viewCountLabel = new QLabel(QString("Views: %1").arg(response.getViewCount()));
|
||||
viewCountLabel->setWordWrap(true);
|
||||
viewCountLabel->setMaximumWidth(200);
|
||||
headerLayout->addWidget(viewCountLabel);
|
||||
|
||||
QLabel *createdAtLabel = new QLabel(QString("Created: %1").arg(response.getCreatedAt()));
|
||||
createdAtLabel->setWordWrap(true);
|
||||
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);
|
||||
|
||||
/*deckPreviewDisplayWidget = new CardInfoPictureWithTextOverlayWidget(this);
|
||||
deckPreviewDisplayWidget->setOverlayText(QString("%1 (%2)").arg(response.getName()).arg(response.getSize()));
|
||||
connect(deckPreviewDisplayWidget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this,
|
||||
&ArchidektApiResponseDeckEntryDisplayWidget::actRequestNavigationToDeck);
|
||||
layout->addWidget(deckPreviewDisplayWidget);*/
|
||||
}
|
||||
|
||||
layout->addWidget(deckPreviewDisplayWidget);
|
||||
void ArchidektApiResponseDeckEntryDisplayWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
actRequestNavigationToDeck();
|
||||
}
|
||||
|
||||
void ArchidektApiResponseDeckEntryDisplayWidget::onPreviewImageLoadFinished(QNetworkReply *reply)
|
||||
{
|
||||
if (reply->url() != response.getFeatured()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
picture->setText("Error loading");
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray imageData = reply->readAll();
|
||||
QPixmap pixmap;
|
||||
|
||||
if (pixmap.loadFromData(imageData)) {
|
||||
picture->setPixmap(pixmap.scaled(150, 150, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
} else {
|
||||
picture->setText("Invalid image");
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void ArchidektApiResponseDeckEntryDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_ENTRY_DISPLAY_WIDGET_H
|
||||
|
||||
#include "../../../../cards/card_info_picture_with_text_overlay_widget.h"
|
||||
#include "../../../../general/layout_containers/flow_widget.h"
|
||||
#include "../api_response/deck_listings/archidekt_api_response_deck_listing_container.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QResizeEvent>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
|
|
@ -19,15 +19,22 @@ signals:
|
|||
|
||||
public:
|
||||
explicit ArchidektApiResponseDeckEntryDisplayWidget(QWidget *parent,
|
||||
ArchidektApiResponseDeckListingContainer response);
|
||||
ArchidektApiResponseDeckListingContainer response,
|
||||
QNetworkAccessManager *imageNetworkManager);
|
||||
void onPreviewImageLoadFinished(QNetworkReply *reply);
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
public slots:
|
||||
void actRequestNavigationToDeck();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
QHBoxLayout *layout;
|
||||
QVBoxLayout *layout;
|
||||
ArchidektApiResponseDeckListingContainer response;
|
||||
QNetworkAccessManager *imageNetworkManager;
|
||||
QLabel *picture;
|
||||
CardInfoPictureWithTextOverlayWidget *deckPreviewDisplayWidget;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,10 +13,17 @@ ArchidektApiResponseDeckListingsDisplayWidget::ArchidektApiResponseDeckListingsD
|
|||
|
||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||
|
||||
imageNetworkManager = new QNetworkAccessManager(this);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
imageNetworkManager->setTransferTimeout(); // Use Qt's default timeout
|
||||
#endif
|
||||
|
||||
imageNetworkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
|
||||
|
||||
// Add widgets for deck listings
|
||||
auto deckListings = response.results;
|
||||
for (const auto &deckListing : deckListings) {
|
||||
auto cardListDisplayWidget = new ArchidektApiResponseDeckEntryDisplayWidget(this, deckListing);
|
||||
auto cardListDisplayWidget = new ArchidektApiResponseDeckEntryDisplayWidget(this, deckListing, imageNetworkManager);
|
||||
connect(cardListDisplayWidget, &ArchidektApiResponseDeckEntryDisplayWidget::requestNavigation, this,
|
||||
&ArchidektApiResponseDeckListingsDisplayWidget::requestNavigation);
|
||||
flowWidget->addWidget(cardListDisplayWidget);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "../../../../general/layout_containers/flow_widget.h"
|
||||
#include "../api_response/archidekt_deck_listing_api_response.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QResizeEvent>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
|
|
@ -23,6 +24,7 @@ public:
|
|||
private:
|
||||
QHBoxLayout *layout;
|
||||
FlowWidget *flowWidget;
|
||||
QNetworkAccessManager *imageNetworkManager;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_LISTINGS_DISPLAY_WIDGET_H
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <QPushButton>
|
||||
#include <QRegularExpression>
|
||||
#include <QResizeEvent>
|
||||
#include <QUrlQuery>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/models/database/card/card_completer_proxy_model.h>
|
||||
#include <libcockatrice/models/database/card/card_search_model.h>
|
||||
|
|
@ -77,6 +78,58 @@ TabArchidekt::TabArchidekt(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
|
|||
searchPushButton = new QPushButton(navigationContainer);
|
||||
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() { doSearch(); });
|
||||
|
||||
searchOptionsContainer = new QWidget(container);
|
||||
searchOptionsLayout = new QHBoxLayout(searchOptionsContainer);
|
||||
mainLayout->addWidget(searchOptionsContainer);
|
||||
|
||||
nameField = new QLineEdit(searchOptionsContainer);
|
||||
nameField->setPlaceholderText(tr("Deck name contains..."));
|
||||
searchOptionsLayout->addWidget(nameField);
|
||||
|
||||
ownerField = new QLineEdit(searchOptionsContainer);
|
||||
ownerField->setPlaceholderText(tr("Owner name contains..."));
|
||||
searchOptionsLayout->addWidget(ownerField);
|
||||
|
||||
QHBoxLayout *colorLayout = new QHBoxLayout();
|
||||
QStringList colors = {"White", "Blue", "Black", "Green", "Red", "Colorless"};
|
||||
|
||||
for (const auto &c : colors) {
|
||||
QCheckBox *chk = new QCheckBox(c, searchOptionsContainer);
|
||||
colorChecks << chk;
|
||||
colorLayout->addWidget(chk);
|
||||
}
|
||||
|
||||
searchOptionsLayout->addLayout(colorLayout);
|
||||
|
||||
logicalAndCheck = new QCheckBox("Require ALL colors", searchOptionsContainer);
|
||||
searchOptionsLayout->addWidget(logicalAndCheck);
|
||||
|
||||
QHBoxLayout *formatLayout = new QHBoxLayout();
|
||||
QStringList formatNames = {"Standard", "Modern", "Commander", "Legacy", "Vintage",
|
||||
"Pauper", "Custom", "Frontier", "Future Std", "Penny Dreadful",
|
||||
"1v1 Commander", "Dual Commander", "Brawl"};
|
||||
|
||||
for (int i = 0; i < formatNames.size(); ++i) {
|
||||
QCheckBox *formatCheckBox = new QCheckBox(formatNames[i], searchOptionsContainer);
|
||||
formatChecks << formatCheckBox;
|
||||
formatLayout->addWidget(formatCheckBox);
|
||||
}
|
||||
|
||||
searchOptionsLayout->addLayout(formatLayout);
|
||||
|
||||
pageSizeSpin = new QSpinBox(searchOptionsContainer);
|
||||
pageSizeSpin->setRange(1, 500);
|
||||
pageSizeSpin->setValue(50);
|
||||
searchOptionsLayout->addWidget(pageSizeSpin);
|
||||
|
||||
cardsField = new QLineEdit(searchOptionsContainer);
|
||||
cardsField->setPlaceholderText("Cards (comma separated)");
|
||||
searchOptionsLayout->addWidget(cardsField);
|
||||
|
||||
commandersField = new QLineEdit(searchOptionsContainer);
|
||||
commandersField->setPlaceholderText("Commanders (comma separated)");
|
||||
searchOptionsLayout->addWidget(commandersField);
|
||||
|
||||
settingsButton = new SettingsButtonWidget(this);
|
||||
|
||||
cardSizeSlider = new CardSizeWidget(this);
|
||||
|
|
@ -97,7 +150,8 @@ TabArchidekt::TabArchidekt(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
|
|||
|
||||
// Ensure navigation stays at the top and currentPageDisplay takes remaining space
|
||||
mainLayout->setStretch(0, 0); // navigationContainer gets minimum space
|
||||
mainLayout->setStretch(1, 1); // currentPageDisplay expands as much as possible
|
||||
mainLayout->setStretch(1, 0);
|
||||
mainLayout->setStretch(2, 1); // currentPageDisplay expands as much as possible
|
||||
|
||||
setCentralWidget(container);
|
||||
|
||||
|
|
@ -113,14 +167,61 @@ void TabArchidekt::retranslateUi()
|
|||
searchPushButton->setText(tr("Search"));
|
||||
}
|
||||
|
||||
QString TabArchidekt::buildSearchUrl()
|
||||
{
|
||||
QUrlQuery query;
|
||||
|
||||
// required
|
||||
query.addQueryItem("name", nameField->text());
|
||||
|
||||
// colors
|
||||
QStringList selectedColors;
|
||||
for (auto *chk : colorChecks)
|
||||
if (chk->isChecked())
|
||||
selectedColors << chk->text();
|
||||
if (!selectedColors.isEmpty())
|
||||
query.addQueryItem("colors", selectedColors.join(","));
|
||||
|
||||
// logicalAnd
|
||||
if (logicalAndCheck->isChecked())
|
||||
query.addQueryItem("logicalAnd", "true");
|
||||
|
||||
// owner
|
||||
if (!ownerField->text().isEmpty())
|
||||
query.addQueryItem("owner", ownerField->text());
|
||||
|
||||
// cards
|
||||
if (!cardsField->text().isEmpty())
|
||||
query.addQueryItem("cards", cardsField->text());
|
||||
|
||||
// commanders
|
||||
if (!commandersField->text().isEmpty())
|
||||
query.addQueryItem("commanders", commandersField->text());
|
||||
|
||||
// formats
|
||||
QStringList formatIds;
|
||||
for (int i = 0; i < formatChecks.size(); ++i)
|
||||
if (formatChecks[i]->isChecked())
|
||||
formatIds << QString::number(i + 1);
|
||||
if (!formatIds.isEmpty())
|
||||
query.addQueryItem("formats", formatIds.join(","));
|
||||
|
||||
// page size
|
||||
if (pageSizeSpin->value() != 50)
|
||||
query.addQueryItem("pageSize", QString::number(pageSizeSpin->value()));
|
||||
|
||||
// build final URL
|
||||
QUrl url("https://archidekt.com/api/decks/v3/");
|
||||
url.setQuery(query);
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
void TabArchidekt::doSearch()
|
||||
{
|
||||
CardInfoPtr searchedCard = CardDatabaseManager::query()->getCardInfo(searchBar->text());
|
||||
if (!searchedCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
// setCard(searchedCard, canBeCommander(searchedCard));
|
||||
QString url = buildSearchUrl();
|
||||
QNetworkRequest req{QUrl(url)};
|
||||
networkManager->get(req);
|
||||
}
|
||||
|
||||
void TabArchidekt::actNavigatePage(QString url)
|
||||
|
|
@ -160,7 +261,7 @@ void TabArchidekt::processApiJson(QNetworkReply *reply)
|
|||
QString responseUrl = reply->url().toString();
|
||||
|
||||
// Check if the response URL matches a commander request
|
||||
if (responseUrl == "https://archidekt.com/api/decks/v3/?name=") {
|
||||
if (responseUrl.startsWith("https://archidekt.com/api/decks/v3/")) {
|
||||
processTopDecksResponse(jsonObj);
|
||||
} else if (responseUrl.startsWith("https://archidekt.com/api/decks/")) {
|
||||
processDeckResponse(jsonObj);
|
||||
|
|
@ -197,7 +298,8 @@ void TabArchidekt::processTopDecksResponse(QJsonObject reply)
|
|||
|
||||
// **Ensure layout stays correct**
|
||||
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
|
||||
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
|
||||
mainLayout->setStretch(1, 0); // Keep searchOptionsContainer at the top
|
||||
mainLayout->setStretch(2, 1); // Make sure currentPageDisplay takes remaining space
|
||||
}
|
||||
|
||||
void TabArchidekt::processDeckResponse(QJsonObject reply)
|
||||
|
|
@ -227,7 +329,8 @@ void TabArchidekt::processDeckResponse(QJsonObject reply)
|
|||
|
||||
// **Ensure layout stays correct**
|
||||
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
|
||||
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
|
||||
mainLayout->setStretch(1, 0); // Keep searchOptionsContainer at the top
|
||||
mainLayout->setStretch(2, 1); // Make sure currentPageDisplay takes remaining space
|
||||
}
|
||||
|
||||
void TabArchidekt::prettyPrintJson(const QJsonValue &value, int indentLevel)
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@
|
|||
#include "../../interface/widgets/quick_settings/settings_button_widget.h"
|
||||
#include "../../tab.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QString>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
|
||||
|
|
@ -21,6 +23,7 @@ public:
|
|||
explicit TabArchidekt(TabSupervisor *_tabSupervisor);
|
||||
|
||||
void retranslateUi() override;
|
||||
QString buildSearchUrl();
|
||||
void doSearch();
|
||||
QString getTabText() const override
|
||||
{
|
||||
|
|
@ -53,6 +56,29 @@ private:
|
|||
QPushButton *decksPushButton;
|
||||
QLineEdit *searchBar;
|
||||
QPushButton *searchPushButton;
|
||||
|
||||
// --- Search options UI ---
|
||||
QWidget *searchOptionsContainer;
|
||||
QHBoxLayout *searchOptionsLayout;
|
||||
|
||||
// Required / basic fields
|
||||
QLineEdit *nameField; // Deck name substring
|
||||
QLineEdit *ownerField; // Owner substring
|
||||
|
||||
// Colors
|
||||
QVector<QCheckBox*> colorChecks; // White, Blue, Black, Green, Red, Colorless
|
||||
QCheckBox *logicalAndCheck; // Require ALL colors instead of ANY
|
||||
|
||||
// Formats
|
||||
QVector<QCheckBox*> formatChecks; // Format checkboxes (13 total)
|
||||
|
||||
// Page size
|
||||
QSpinBox *pageSizeSpin;
|
||||
|
||||
// Cards and Commanders
|
||||
QLineEdit *cardsField; // comma-separated quoted card names
|
||||
QLineEdit *commandersField; // comma-separated quoted commander names
|
||||
|
||||
SettingsButtonWidget *settingsButton;
|
||||
CardSizeWidget *cardSizeSlider;
|
||||
CardInfoPtr cardToQuery;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue