TabArchidekt and Archidekt API integration.

Took 37 seconds

Took 4 minutes

Took 40 seconds

Took 4 minutes
This commit is contained in:
Brübach, Lukas 2025-11-24 17:54:46 +01:00
parent de13c22552
commit 81046cd135
27 changed files with 1516 additions and 2 deletions

View file

@ -220,6 +220,18 @@ set(cockatrice_SOURCES
src/interface/window_main.cpp src/interface/window_main.cpp
src/main.cpp src/main.cpp
src/interface/widgets/tabs/abstract_tab_deck_editor.cpp src/interface/widgets/tabs/abstract_tab_deck_editor.cpp
src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp
src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp
@ -303,7 +315,32 @@ if(APPLE)
set_source_files_properties( set_source_files_properties(
${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources
) )
set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns) set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns
src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp
src/interface/widgets/tabs/api/archidekt/tab_archidekt.h
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.h
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.h
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.h
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.h
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.h
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.h
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.h
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.h
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.h
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp
src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.h
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.h
)
endif(APPLE) endif(APPLE)
if(Qt6_FOUND) if(Qt6_FOUND)

View file

@ -0,0 +1,29 @@
#include "archidekt_deck_listing_api_response.h"
#include <QDebug>
#include <QJsonArray>
void ArchidektDeckListingApiResponse::fromJson(const QJsonObject &json)
{
count = json.value("count").toInt();
next = QUrl(json.value("next").toString());
QJsonArray containerJson = json.value("results").toArray();
for (const QJsonValue &deckListingValue : containerJson) {
ArchidektApiResponseDeckListingContainer listingResult;
listingResult.fromJson(deckListingValue.toObject());
results.append(listingResult);
}
}
void ArchidektDeckListingApiResponse::debugPrint() const
{
qDebug() << "Count:" << count;
qDebug() << "Next:" << next;
qDebug() << "Results:";
for (const auto &deckListing : results) {
deckListing.debugPrint();
}
}

View file

@ -0,0 +1,22 @@
#ifndef COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_H
#define COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_H
#include "deck_listings/archidekt_api_response_deck_listing_container.h"
#include <QJsonObject>
#include <QString>
#include <QUrl>
class ArchidektDeckListingApiResponse
{
public:
int count;
QUrl next;
QVector<ArchidektApiResponseDeckListingContainer> results;
void fromJson(const QJsonObject &json);
void debugPrint() const;
};
#endif // COCKATRICE_DECK_LISTING_API_RESPONSE_H

View file

@ -0,0 +1,61 @@
#include "archidekt_api_response_card.h"
void ArchidektApiResponseCard::fromJson(const QJsonObject &json)
{
id = json.value("id").toInt();
artist = json.value("artist").toString();
tcgProductId = json.value("tcgProductId").toInt();
ckFoilId = json.value("ckFoilId").toInt();
ckNormalId = json.value("ckNormalId").toInt();
cmEd = json.value("cmEd").toString();
scgSku = json.value("scgSku").toString();
scgFoilSku = json.value("scgFoilSku").toString();
collectorNumber = json.value("collectorNumber").toString();
multiverseId = json.value("multiverseId").toInt();
mtgoFoilId = json.value("mtgoFoilId").toInt();
mtgoNormalId = json.value("mtgoNormalId").toInt();
uid = json.value("uid").toString();
displayName = json.value("displayName").toString();
releasedAt = json.value("releasedAt").toString();
edition.fromJson(json.value("edition").toObject());
flavor = json.value("flavor").toString();
// TODO but not really important
games = {};
options = {};
scryfallImageHash = json.value("scryfallImageHash").toString();
oracleCard = json.value("oracleCard").toObject();
owned = json.value("owned").toInt();
pinnedStatus = json.value("pinnedStatus").toInt();
rarity = json.value("rarity").toString();
// TODO but not really important
globalCategories = {};
}
void ArchidektApiResponseCard::debugPrint() const
{
qDebug() << "Id:" << id;
qDebug() << "id:" << artist;
qDebug() << "artist:" << tcgProductId;
qDebug() << "tcgProductId:" << ckFoilId;
qDebug() << "ckFoilId:" << ckNormalId;
qDebug() << "ckNormalId:" << cmEd;
qDebug() << "cmEd:" << scgSku;
qDebug() << "scgSku:" << scgFoilSku;
qDebug() << "scgFoilSku:" << collectorNumber;
qDebug() << "collectorNumber:" << multiverseId;
qDebug() << "multiverseId:" << mtgoFoilId;
qDebug() << "mtgoFoilId:" << mtgoNormalId;
qDebug() << "mtgoNormalId:" << uid;
qDebug() << "uid:" << displayName;
qDebug() << "displayName:" << releasedAt;
qDebug() << "releasedAt:" << flavor;
qDebug() << "flavor:" << games;
qDebug() << "games:" << options;
qDebug() << "options:" << scryfallImageHash;
qDebug() << "scryfallImageHash:" << owned;
qDebug() << "owned:" << pinnedStatus;
qDebug() << "pinnedStatus:" << rarity;
qDebug() << "rarity:" << globalCategories;
}

View file

@ -0,0 +1,68 @@
#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_H
#define COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_H
#include "archidekt_api_response_edition.h"
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QVector>
class ArchidektApiResponseCard
{
public:
// Constructor
ArchidektApiResponseCard() = default;
// Parse deck-related data from JSON
void fromJson(const QJsonObject &json);
// Debug method for logging
void debugPrint() const;
QJsonObject getOracleCard() const
{
return oracleCard;
};
QString getCollectorNumber() const
{
return collectorNumber;
}
ArchidektApiResponseEdition getEdition() const
{
return edition;
}
private:
int id;
QString artist;
int tcgProductId;
int ckFoilId;
int ckNormalId;
QString cmEd;
QString scgSku;
QString scgFoilSku;
QString collectorNumber;
int multiverseId;
int mtgoFoilId;
int mtgoNormalId;
QString uid;
QString displayName;
QString releasedAt;
ArchidektApiResponseEdition edition;
QString flavor;
QStringList games;
QStringList options;
QString scryfallImageHash;
QJsonObject oracleCard;
int owned;
int pinnedStatus;
//ArchidektApiResponsePrices prices;
QString rarity;
QStringList globalCategories;
};
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_H

View file

@ -0,0 +1,43 @@
#include "archidekt_api_response_card_entry.h"
void ArchidektApiResponseCardEntry::fromJson(const QJsonObject &json)
{
id = json.value("id").toInt();
auto categoriesJson = json.value("categories").toArray();
for (auto category : categoriesJson) {
categories.append(category.toString());
}
companion = json.value("companion").toBool();
flippedDefault = json.value("flippedDefault").toBool();
label = json.value("label").toString();
modifier = json.value("modifier").toString();
quantity = json.value("quantity").toInt();
customCmc = json.value("customCmc").toInt();
removedCategories = {};
createdAt = json.value("createdAt").toString();
updatedAt = json.value("updatedAt").toString();
deletedAt = json.value("deletedAt").toString();
notes = json.value("notes").toString();
card.fromJson(json.value("card").toObject());
}
void ArchidektApiResponseCardEntry::debugPrint() const
{
qDebug() << "Id:" << id;
qDebug() << "Categories:" << categories;
qDebug() << "Companion:" << companion;
qDebug() << "FlippedDefault:" << flippedDefault;
qDebug() << "Label:" << label;
qDebug() << "Modifier:" << modifier;
qDebug() << "Quantity:" << quantity;
qDebug() << "CustomCmc:" << customCmc;
qDebug() << "RemovedCategories:" << removedCategories;
qDebug() << "CreatedAt:" << createdAt;
qDebug() << "UpdatedAt:" << updatedAt;
qDebug() << "DeletedAt:" << deletedAt;
qDebug() << "Notes:" << notes;
card.debugPrint();
}

View file

@ -0,0 +1,56 @@
#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_ENTRY_H
#define COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_ENTRY_H
#include "archidekt_api_response_card.h"
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QVector>
class ArchidektApiResponseCardEntry
{
public:
// Constructor
ArchidektApiResponseCardEntry() = default;
// Parse deck-related data from JSON
void fromJson(const QJsonObject &json);
// Debug method for logging
void debugPrint() const;
ArchidektApiResponseCard getCard() const
{
return card;
};
QStringList getCategories() const
{
return categories;
}
int getQuantity() const
{
return quantity;
}
private:
int id;
QStringList categories;
bool companion;
bool flippedDefault;
QString label;
QString modifier;
int quantity;
int customCmc;
QStringList removedCategories;
QString createdAt;
QString updatedAt;
QString deletedAt;
QString notes;
ArchidektApiResponseCard card;
};
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_ENTRY_H

View file

@ -0,0 +1,19 @@
#include "archidekt_api_response_edition.h"
void ArchidektApiResponseEdition::fromJson(const QJsonObject &json)
{
editionCode = json.value("editioncode").toString();
editionName = json.value("editionname").toString();
editionDate = json.value("editiondate").toString();
editionType = json.value("editiontype").toString();
mtgoCode = json.value("mtgocode").toString();
}
void ArchidektApiResponseEdition::debugPrint() const
{
qDebug() << "Edition Code: " << editionCode;
qDebug() << "Edition Name: " << editionName;
qDebug() << "Edition Date: " << editionDate;
qDebug() << "Edition Type: " << editionType;
qDebug() << "Mtgo Code: " << mtgoCode;
}

View file

@ -0,0 +1,52 @@
#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_EDITION_H
#define COCKATRICE_ARCHIDEKT_API_RESPONSE_EDITION_H
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QVector>
class ArchidektApiResponseEdition
{
public:
// Constructor
ArchidektApiResponseEdition() = default;
// Parse deck-related data from JSON
void fromJson(const QJsonObject &json);
// Debug method for logging
void debugPrint() const;
[[nodiscard]] QString getEditionCode() const
{
return editionCode;
}
[[nodiscard]] QString getEditionName() const
{
return editionName;
}
[[nodiscard]] QString getEditionDate() const
{
return editionDate;
}
[[nodiscard]] QString getEditionType() const
{
return editionType;
}
[[nodiscard]] QString getMtgoCode() const
{
return mtgoCode;
}
private:
QString editionCode;
QString editionName;
QString editionDate;
QString editionType;
QString mtgoCode;
};
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_EDITION_H

View file

@ -0,0 +1,79 @@
#include "archidekt_api_response_deck.h"
#include "../card/archidekt_api_response_card_entry.h"
void ArchidektApiResponseDeck::fromJson(const QJsonObject &json)
{
id = json.value("id").toInt();
name = json.value("name").toString();
size = json.value("size").toInt();
updatedAt = json.value("updatedAt").toString();
createdAt = json.value("createdAt").toString();
deckFormat = json.value("deckFormat").toInt();
edhBracket = json.value("edhBracket").toInt();
featured = json.value("featured").toString();
customFeatured = json.value("customFeatured").toString();
viewCount = json.value("viewCount").toInt();
privateDeck = json.value("private").toBool();
unlisted = json.value("unlisted").toBool();
theoryCrafted = json.value("theoryCrafted").toBool();
points = json.value("points").toInt();
userInput = json.value("userInput").toInt();
owner.fromJson(json.value("owner").toObject());
commentRoot = json.value("commentRoot").toInt();
editors = json.value("editors").toString();
parentFolderId = json.value("parentFolderId").toInt();
bookmarked = json.value("bookmarked").toBool();
auto categoriesJson = json.value("categories").toArray();
for (auto category : categoriesJson) {
ArchidektApiResponseDeckCategory categoryEntry;
categoryEntry.fromJson(category.toObject());
categories.append(categoryEntry);
}
deckTags = {};
playgroupDeckUrl = json.value("playgroupDeckUrl").toString();
cardPackage = json.value("cardPackage").toString();
auto cardsObject = json.value("cards").toArray();
for (auto card : cardsObject) {
ArchidektApiResponseCardEntry entry;
entry.fromJson(card.toObject());
cards.append(entry);
}
// TODO but not really important
customCards = {};
}
void ArchidektApiResponseDeck::debugPrint() const
{
qDebug() << "Id:" << id;
qDebug() << "Name:" << name;
qDebug() << "Size:" << size;
qDebug() << "UpdatedAt:" << updatedAt;
qDebug() << "CreatedAt:" << createdAt;
qDebug() << "DeckFormat:" << deckFormat;
qDebug() << "EdhBracket:" << edhBracket;
qDebug() << "Featured:" << featured;
qDebug() << "CustomFeatured:" << customFeatured;
qDebug() << "ViewCount:" << viewCount;
qDebug() << "Private:" << privateDeck;
qDebug() << "Unlisted:" << unlisted;
qDebug() << "TheoryCrafted:" << theoryCrafted;
qDebug() << "Points:" << points;
qDebug() << "UserInput:" << userInput;
owner.debugPrint();
qDebug() << "CommentRoot:" << commentRoot;
qDebug() << "Editors:" << editors;
qDebug() << "ParentFolderId:" << parentFolderId;
qDebug() << "Bookmarked:" << bookmarked;
qDebug() << "DeckTags:" << deckTags;
qDebug() << "PlaygroupDeckUrl:" << playgroupDeckUrl;
qDebug() << "CardPackage:" << cardPackage;
for (auto card : cards) {
card.debugPrint();
}
}

View file

@ -0,0 +1,72 @@
#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_H
#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_H
#include "../card/archidekt_api_response_card.h"
#include "../card/archidekt_api_response_card_entry.h"
#include "../deck_listings/archidekt_api_response_deck_owner.h"
#include "archidekt_api_response_deck_category.h"
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QVector>
class ArchidektApiResponseDeck
{
public:
// Constructor
ArchidektApiResponseDeck() = default;
// Parse deck-related data from JSON
void fromJson(const QJsonObject &json);
// Debug method for logging
void debugPrint() const;
QVector<ArchidektApiResponseCardEntry> getCards() const
{
return cards;
};
QVector<ArchidektApiResponseDeckCategory> getCategories() const
{
return categories;
}
QString getDeckName() const
{
return name;
};
private:
int id;
QString name;
int size;
QString updatedAt;
QString createdAt;
int deckFormat;
int edhBracket;
QString featured;
QString customFeatured;
int viewCount;
bool privateDeck;
bool unlisted;
bool theoryCrafted;
int points;
int userInput;
ArchidektApiResponseDeckOwner owner;
int commentRoot;
QString editors;
int parentFolderId;
bool bookmarked;
QVector<ArchidektApiResponseDeckCategory> categories;
QStringList deckTags;
QString playgroupDeckUrl;
QString cardPackage;
QVector<ArchidektApiResponseCardEntry> cards;
QStringList customCards;
};
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_H

View file

@ -0,0 +1,19 @@
#include "archidekt_api_response_deck_category.h"
void ArchidektApiResponseDeckCategory::fromJson(const QJsonObject &json)
{
id = json.value("id").toInt();
name = json.value("name").toString();
isPremier = json.value("isPremier").toBool();
includedInDeck = json.value("includedInDeck").toBool();
includedInPrice = json.value("includedInPrice").toBool();
}
void ArchidektApiResponseDeckCategory::debugPrint() const
{
qDebug() << "Id:" << id;
qDebug() << "Name:" << name;
qDebug() << "isPremier:" << isPremier;
qDebug() << "IncludedInDeck:" << includedInDeck;
qDebug() << "IncludedInPrice:" << includedInPrice;
}

View file

@ -0,0 +1,55 @@
#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_CATEGORY_H
#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_CATEGORY_H
#include "../card/archidekt_api_response_card.h"
#include "../card/archidekt_api_response_card_entry.h"
#include "../deck_listings/archidekt_api_response_deck_owner.h"
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QVector>
class ArchidektApiResponseDeckCategory
{
public:
// Constructor
ArchidektApiResponseDeckCategory() = default;
// Parse deck-related data from JSON
void fromJson(const QJsonObject &json);
// Debug method for logging
void debugPrint() const;
[[nodiscard]] int getId() const
{
return id;
}
[[nodiscard]] QString getName() const
{
return name;
}
[[nodiscard]] bool getIsPremier() const
{
return isPremier;
}
[[nodiscard]] bool getIncludedInDeck() const
{
return includedInDeck;
}
[[nodiscard]] bool getIncludedInPrice() const
{
return includedInPrice;
}
private:
int id;
QString name;
bool isPremier;
bool includedInDeck;
bool includedInPrice;
};
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_CATEGORY_H

View file

@ -0,0 +1,57 @@
#include "archidekt_api_response_deck_listing_container.h"
#include "archidekt_api_response_deck_owner.h"
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
void ArchidektApiResponseDeckListingContainer::fromJson(const QJsonObject &json)
{
id = json.value("id").toInt();
name = json.value("name").toString();
size = json.value("size").toInt();
updatedAt = json.value("updatedAt").toString();
createdAt = json.value("createdAt").toString();
deckFormat = json.value("deckFormat").toInt();
edhBracket = json.value("edhBracket").toInt();
featured = json.value("featured").toString();
customFeatured = json.value("customFeatured").toString();
viewCount = json.value("viewCount").toInt();
privateDeck = json.value("private").toBool();
unlisted = json.value("unlisted").toBool();
theoryCrafted = json.value("theoryCrafted").toBool();
game = json.value("game").toString();
hasDescription = json.value("hasDescription").toBool();
//TODO
tags = {};
parentFolderId = json.value("parentFolderId").toInt();
owner.fromJson(json.value("owner").toObject());
cardPackage = json.value("cardPackage").toString();
contest = json.value("contest").toString();
}
void ArchidektApiResponseDeckListingContainer::debugPrint() const
{
qDebug() << "Id:" << id;
qDebug() << "Name:" << name;
qDebug() << "Size:" << size;
qDebug() << "UpdatedAt:" << updatedAt;
qDebug() << "CreatedAt:" << createdAt;
qDebug() << "DeckFormat:" << deckFormat;
qDebug() << "EdhBracket:" << edhBracket;
qDebug() << "Featured:" << featured;
qDebug() << "CustomFeatured:" << customFeatured;
qDebug() << "ViewCount:" << viewCount;
qDebug() << "Private:" << privateDeck;
qDebug() << "Unlisted:" << unlisted;
qDebug() << "TheoryCrafted:" << theoryCrafted;
qDebug() << "Game:" << game;
qDebug() << "HasDescription:" << hasDescription;
qDebug() << "Tags:" << tags;
qDebug() << "ParentFolderId:" << parentFolderId;
owner.debugPrint();
qDebug() << "Colors:" << colors;
qDebug() << "CardPackage" << cardPackage;
qDebug() << "Contest:" << contest;
}

View file

@ -0,0 +1,133 @@
#ifndef COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_CONTAINER_H
#define COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_CONTAINER_H
#include "archidekt_api_response_deck_owner.h"
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QVector>
class ArchidektApiResponseDeckListingContainer
{
public:
// Constructor
ArchidektApiResponseDeckListingContainer() = default;
// Parse deck-related data from JSON
void fromJson(const QJsonObject &json);
// Debug method for logging
void debugPrint() const;
[[nodiscard]] int getId() const
{
return id;
}
[[nodiscard]] QString getName() const
{
return name;
}
[[nodiscard]] int getSize() const
{
return size;
}
[[nodiscard]] QString getUpdatedAt() const
{
return updatedAt;
}
[[nodiscard]] QString getCreatedAt() const
{
return createdAt;
}
[[nodiscard]] int getDeckFormat() const
{
return deckFormat;
}
[[nodiscard]] int getEDHBracket() const
{
return edhBracket;
}
[[nodiscard]] QString getFeatured() const
{
return featured;
}
[[nodiscard]] QString getCustomFeatured() const
{
return customFeatured;
}
[[nodiscard]] int getViewCount() const
{
return viewCount;
}
[[nodiscard]] bool getPrivateDeck() const
{
return privateDeck;
}
[[nodiscard]] bool getUnlisted() const
{
return unlisted;
}
[[nodiscard]] bool getTheoryCrafted() const
{
return theoryCrafted;
}
[[nodiscard]] QString getGame() const
{
return game;
}
[[nodiscard]] bool getHasDescription() const
{
return hasDescription;
}
[[nodiscard]] QStringList getTags() const
{
return tags;
}
[[nodiscard]] int getParentFolderId() const
{
return parentFolderId;
}
[[nodiscard]] ArchidektApiResponseDeckOwner getOwner() const
{
return owner;
}
[[nodiscard]] QMap<QString, int> getColors() const
{
return colors;
}
[[nodiscard]] QString getCardPackage() const
{
return cardPackage;
}
[[nodiscard]] QString getContest() const
{
return contest;
}
private:
int id;
QString name;
int size;
QString updatedAt;
QString createdAt;
int deckFormat;
int edhBracket;
QString featured;
QString customFeatured;
int viewCount;
bool privateDeck;
bool unlisted;
bool theoryCrafted;
QString game;
bool hasDescription;
QStringList tags;
int parentFolderId;
ArchidektApiResponseDeckOwner owner;
QMap<QString, int> colors;
QString cardPackage;
QString contest;
};
#endif // COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_CONTAINER_H

View file

@ -0,0 +1,22 @@
#include "archidekt_api_response_deck_owner.h"
void ArchidektApiResponseDeckOwner::fromJson(const QJsonObject &json)
{
id = json.value("id").toInt();
userName = json.value("userName").toString();
avatar = QUrl(json.value("avatar").toString());
moderator = json.value("moderator").toBool();
pledgeLevel = json.value("pledgeLevel").toInt();
// TODO but not really important
roles = {};
}
void ArchidektApiResponseDeckOwner::debugPrint() const
{
qDebug() << "Id:" << id;
qDebug() << "UserName:" << userName;
qDebug() << "Avatar:" << avatar;
qDebug() << "Moderator:" << moderator;
qDebug() << "PledgeLevel:" << pledgeLevel;
qDebug() << "Roles:" << roles;
}

View file

@ -0,0 +1,31 @@
#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_OWNER_H
#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_OWNER_H
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QVector>
class ArchidektApiResponseDeckOwner
{
public:
// Constructor
ArchidektApiResponseDeckOwner() = default;
// Parse deck-related data from JSON
void fromJson(const QJsonObject &json);
// Debug method for logging
void debugPrint() const;
private:
int id;
QString userName;
QUrl avatar;
bool moderator;
int pledgeLevel;
QStringList roles;
};
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_OWNER_H

View file

@ -0,0 +1,142 @@
#include "archidekt_api_response_deck_display_widget.h"
#include "../../../../../deck_loader/deck_loader.h"
#include "../../../../cards/card_info_picture_with_text_overlay_widget.h"
#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 <QSortFilterProxyModel>
ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWidget *parent,
ArchidektApiResponseDeck _response,
CardSizeWidget *_cardSizeSlider)
: QWidget(parent), response(_response), cardSizeSlider(_cardSizeSlider)
{
layout = new QVBoxLayout(this);
setLayout(layout);
openInEditorButton = new QPushButton(this);
layout->addWidget(openInEditorButton);
connect(openInEditorButton, &QPushButton::clicked, this, &ArchidektApiResponseDeckDisplayWidget::actOpenInDeckEditor);
scrollArea = new QScrollArea(this);
scrollArea->setWidgetResizable(true);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
layout->addWidget(scrollArea);
container = new QWidget(scrollArea);
scrollArea->setWidget(container);
containerLayout = new QVBoxLayout(container);
container->setLayout(containerLayout);
zoneContainer = new QWidget(container);
containerLayout->addWidget(zoneContainer);
zoneContainerLayout = new QVBoxLayout(zoneContainer);
zoneContainer->setLayout(zoneContainerLayout);
QString tempDeck;
QTextStream deckStream(&tempDeck);
for (auto card : response.getCards()) {
tempDeck += QString("%1 %2 (%3) %4\n")
.arg(card.getQuantity())
.arg(card.getCard().getOracleCard().value("name").toString())
.arg(card.getCard().getEdition().getEditionCode())
.arg(card.getCard().getCollectorNumber());
}
model = new DeckListModel(this);
connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset);
model->getDeckList()->loadFromStream_Plain(deckStream, false);
model->rebuildTree();
retranslateUi();
}
void ArchidektApiResponseDeckDisplayWidget::retranslateUi()
{
openInEditorButton->setText(tr("Open Deck in Deck Editor"));
}
void ArchidektApiResponseDeckDisplayWidget::actOpenInDeckEditor()
{
auto loader = new DeckLoader(this);
loader->getDeckList()->loadFromString_Native(model->getDeckList()->writeToString_Native());
loader->getDeckList()->setName(response.getDeckName());
emit openInDeckEditor(loader);
}
void ArchidektApiResponseDeckDisplayWidget::clearAllDisplayWidgets()
{
for (auto idx : indexToWidgetMap.keys()) {
auto displayWidget = indexToWidgetMap.value(idx);
zoneContainerLayout->removeWidget(displayWidget);
indexToWidgetMap.remove(idx);
delete displayWidget;
}
}
void ArchidektApiResponseDeckDisplayWidget::decklistModelReset()
{
clearAllDisplayWidgets();
constructZoneWidgetsFromDeckListModel();
}
void ArchidektApiResponseDeckDisplayWidget::constructZoneWidgetsFromDeckListModel()
{
qDebug() << model->rowCount(model->getRoot());
QSortFilterProxyModel proxy;
proxy.setSourceModel(model);
proxy.setSortRole(Qt::EditRole);
proxy.sort(1, Qt::AscendingOrder);
for (int i = 0; i < proxy.rowCount(); ++i) {
QModelIndex proxyIndex = proxy.index(i, 0);
QModelIndex sourceIndex = proxy.mapToSource(proxyIndex);
// Make a persistent index from the *source* model
QPersistentModelIndex persistent(sourceIndex);
if (indexToWidgetMap.contains(persistent)) {
continue;
}
DeckCardZoneDisplayWidget *zoneDisplayWidget = new DeckCardZoneDisplayWidget(
zoneContainer, model, persistent,
model->data(persistent.sibling(persistent.row(), 1), Qt::EditRole).toString(), "maintype",
{"name"}, DisplayType::Overlap, 20, 10, cardSizeSlider);
/*connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardHovered, this, &VisualDeckEditorWidget::onHover);
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardClicked, this, &VisualDeckEditorWidget::onCardClick);
connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::requestCleanup, this,
&VisualDeckEditorWidget::cleanupInvalidZones);
connect(this, &VisualDeckEditorWidget::activeSortCriteriaChanged, zoneDisplayWidget,
&DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged);
connect(this, &VisualDeckEditorWidget::activeGroupCriteriaChanged, zoneDisplayWidget,
&DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged);
connect(this, &VisualDeckEditorWidget::displayTypeChanged, zoneDisplayWidget,
&DeckCardZoneDisplayWidget::refreshDisplayType);*/
zoneContainerLayout->addWidget(zoneDisplayWidget);
indexToWidgetMap.insert(persistent, zoneDisplayWidget);
}
}
void ArchidektApiResponseDeckDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
layout->invalidate();
layout->activate();
layout->update();
}

View file

@ -0,0 +1,49 @@
#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_DISPLAY_WIDGET_H
#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_DISPLAY_WIDGET_H
#include "../../../../../deck_loader/deck_loader.h"
#include "../../../../cards/card_size_widget.h"
#include "../../../../general/layout_containers/flow_widget.h"
#include "../api_response/deck/archidekt_api_response_deck.h"
#include "deck_list_model.h"
#include <QPushButton>
#include <QResizeEvent>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QWidget>
class ArchidektApiResponseDeckDisplayWidget : public QWidget
{
Q_OBJECT
signals:
void requestNavigation(QString url);
void openInDeckEditor(DeckLoader *loader);
public:
explicit ArchidektApiResponseDeckDisplayWidget(QWidget *parent,
ArchidektApiResponseDeck response,
CardSizeWidget *cardSizeSlider);
void retranslateUi();
void actOpenInDeckEditor();
void clearAllDisplayWidgets();
void decklistModelReset();
void constructZoneWidgetsFromDeckListModel();
void resizeEvent(QResizeEvent *event) override;
private:
ArchidektApiResponseDeck response;
CardSizeWidget *cardSizeSlider;
QVBoxLayout *layout;
QPushButton *openInEditorButton;
QScrollArea *scrollArea;
QWidget *zoneContainer;
QVBoxLayout *zoneContainerLayout;
QWidget *container;
QHash<QPersistentModelIndex, QWidget *> indexToWidgetMap;
QVBoxLayout *containerLayout;
DeckListModel *model;
};
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_DISPLAY_WIDGET_H

View file

@ -0,0 +1,34 @@
#include "archidekt_api_response_deck_entry_display_widget.h"
#include "../../../../cards/card_info_picture_with_text_overlay_widget.h"
ArchidektApiResponseDeckEntryDisplayWidget::ArchidektApiResponseDeckEntryDisplayWidget(
QWidget *parent,
ArchidektApiResponseDeckListingContainer _response)
: QWidget(parent), response(_response)
{
layout = new QHBoxLayout(this);
setLayout(layout);
// Add widgets for deck listings
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);
}
void ArchidektApiResponseDeckEntryDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
layout->invalidate();
layout->activate();
layout->update();
}
void ArchidektApiResponseDeckEntryDisplayWidget::actRequestNavigationToDeck()
{
emit requestNavigation(QString("https://archidekt.com/api/decks/%1/").arg(response.getId()));
}

View file

@ -0,0 +1,34 @@
#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_ENTRY_DISPLAY_WIDGET_H
#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 <QResizeEvent>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QWidget>
class ArchidektApiResponseDeckEntryDisplayWidget : public QWidget
{
Q_OBJECT
signals:
void requestNavigation(QString url);
public:
explicit ArchidektApiResponseDeckEntryDisplayWidget(QWidget *parent,
ArchidektApiResponseDeckListingContainer response);
void resizeEvent(QResizeEvent *event) override;
public slots:
void actRequestNavigationToDeck();
private:
QHBoxLayout *layout;
ArchidektApiResponseDeckListingContainer response;
CardInfoPictureWithTextOverlayWidget *deckPreviewDisplayWidget;
};
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_ENTRY_DISPLAY_WIDGET_H

View file

@ -0,0 +1,34 @@
#include "archidekt_api_response_deck_listings_display_widget.h"
#include "../../../../cards/card_info_picture_with_text_overlay_widget.h"
#include "archidekt_api_response_deck_entry_display_widget.h"
ArchidektApiResponseDeckListingsDisplayWidget::ArchidektApiResponseDeckListingsDisplayWidget(
QWidget *parent,
ArchidektDeckListingApiResponse response)
: QWidget(parent)
{
layout = new QHBoxLayout(this);
setLayout(layout);
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
// Add widgets for deck listings
auto deckListings = response.results;
for (const auto &deckListing : deckListings) {
auto cardListDisplayWidget = new ArchidektApiResponseDeckEntryDisplayWidget(this, deckListing);
connect(cardListDisplayWidget, &ArchidektApiResponseDeckEntryDisplayWidget::requestNavigation, this,
&ArchidektApiResponseDeckListingsDisplayWidget::requestNavigation);
flowWidget->addWidget(cardListDisplayWidget);
}
layout->addWidget(flowWidget);
}
void ArchidektApiResponseDeckListingsDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
layout->invalidate();
layout->activate();
layout->update();
}

View file

@ -0,0 +1,28 @@
#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_LISTINGS_DISPLAY_WIDGET_H
#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_LISTINGS_DISPLAY_WIDGET_H
#include "../../../../general/layout_containers/flow_widget.h"
#include "../api_response/archidekt_deck_listing_api_response.h"
#include <QResizeEvent>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QWidget>
class ArchidektApiResponseDeckListingsDisplayWidget : public QWidget
{
Q_OBJECT
signals:
void requestNavigation(QString url);
public:
explicit ArchidektApiResponseDeckListingsDisplayWidget(QWidget *parent, ArchidektDeckListingApiResponse response);
void resizeEvent(QResizeEvent *event) override;
private:
QHBoxLayout *layout;
FlowWidget *flowWidget;
};
#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_LISTINGS_DISPLAY_WIDGET_H

View file

@ -0,0 +1,258 @@
#include "tab_archidekt.h"
#include "../../tab_supervisor.h"
#include "api_response/archidekt_deck_listing_api_response.h"
#include "display/archidekt_api_response_deck_display_widget.h"
#include "display/archidekt_api_response_deck_listings_display_widget.h"
#include <QCompleter>
#include <QDebug>
#include <QHBoxLayout>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QPushButton>
#include <QRegularExpression>
#include <QResizeEvent>
#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>
TabArchidekt::TabArchidekt(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
{
networkManager = new QNetworkAccessManager(this);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
networkManager->setTransferTimeout(); // Use Qt's default timeout
#endif
networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(processApiJson(QNetworkReply *)));
container = new QWidget(this);
mainLayout = new QVBoxLayout(container);
container->setLayout(mainLayout);
navigationContainer = new QWidget(container);
navigationContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
navigationLayout = new QHBoxLayout(navigationContainer);
navigationLayout->setSpacing(5);
navigationContainer->setLayout(navigationLayout);
decksPushButton = new QPushButton(navigationContainer);
connect(decksPushButton, &QPushButton::clicked, this, &TabArchidekt::getTopDecks);
searchBar = new QLineEdit(this);
auto cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
auto displayModel = new CardDatabaseDisplayModel(this);
displayModel->setSourceModel(cardDatabaseModel);
auto *searchModel = new CardSearchModel(displayModel, this);
auto *proxyModel = new CardCompleterProxyModel(this);
proxyModel->setSourceModel(searchModel);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
proxyModel->setFilterRole(Qt::DisplayRole);
auto *completer = new QCompleter(proxyModel, this);
completer->setCompletionRole(Qt::DisplayRole);
completer->setCompletionMode(QCompleter::PopupCompletion);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setFilterMode(Qt::MatchContains);
completer->setMaxVisibleItems(10);
searchBar->setCompleter(completer);
// Update suggestions dynamically
connect(searchBar, &QLineEdit::textChanged, searchModel, &CardSearchModel::updateSearchResults);
connect(searchBar, &QLineEdit::textChanged, this, [=](const QString &text) {
// Ensure substring matching
QString pattern = ".*" + QRegularExpression::escape(text) + ".*";
proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption));
if (!text.isEmpty()) {
completer->complete(); // Force the dropdown to appear
}
});
searchPushButton = new QPushButton(navigationContainer);
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() { doSearch(); });
settingsButton = new SettingsButtonWidget(this);
cardSizeSlider = new CardSizeWidget(this);
settingsButton->addSettingsWidget(cardSizeSlider);
navigationLayout->addWidget(decksPushButton);
navigationLayout->addWidget(searchBar);
navigationLayout->addWidget(searchPushButton);
navigationLayout->addWidget(settingsButton);
currentPageDisplay = new QWidget(container);
currentPageLayout = new QVBoxLayout(currentPageDisplay);
currentPageDisplay->setLayout(currentPageLayout);
mainLayout->addWidget(navigationContainer);
mainLayout->addWidget(currentPageDisplay);
// 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
setCentralWidget(container);
TabArchidekt::retranslateUi();
getTopDecks();
}
void TabArchidekt::retranslateUi()
{
decksPushButton->setText(tr("&Decks"));
searchBar->setPlaceholderText(tr("Search for a card ..."));
searchPushButton->setText(tr("Search"));
}
void TabArchidekt::doSearch()
{
CardInfoPtr searchedCard = CardDatabaseManager::query()->getCardInfo(searchBar->text());
if (!searchedCard) {
return;
}
// setCard(searchedCard, canBeCommander(searchedCard));
}
void TabArchidekt::actNavigatePage(QString url)
{
QNetworkRequest request{QUrl(url)};
networkManager->get(request);
}
void TabArchidekt::getTopDecks()
{
QNetworkRequest request{QUrl(archidektApiLink)};
networkManager->get(request);
}
void TabArchidekt::processApiJson(QNetworkReply *reply)
{
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Network error occurred:" << reply->errorString();
reply->deleteLater();
return;
}
QByteArray responseData = reply->readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData);
if (!jsonDoc.isObject()) {
qDebug() << "Invalid JSON response received.";
reply->deleteLater();
return;
}
QJsonObject jsonObj = jsonDoc.object();
// Get the actual URL from the reply
QString responseUrl = reply->url().toString();
// Check if the response URL matches a commander request
if (responseUrl == "https://archidekt.com/api/decks/v3/?name=") {
processTopDecksResponse(jsonObj);
} else if (responseUrl.startsWith("https://archidekt.com/api/decks/")) {
processDeckResponse(jsonObj);
} else {
prettyPrintJson(jsonObj, 4);
}
reply->deleteLater();
}
void TabArchidekt::processTopDecksResponse(QJsonObject reply)
{
ArchidektDeckListingApiResponse deckData;
deckData.fromJson(reply);
// **Remove previous page display to prevent stacking**
if (currentPageDisplay) {
mainLayout->removeWidget(currentPageDisplay);
delete currentPageDisplay;
currentPageDisplay = nullptr;
}
// **Create new currentPageDisplay**
currentPageDisplay = new QWidget(container);
currentPageLayout = new QVBoxLayout(currentPageDisplay);
currentPageDisplay->setLayout(currentPageLayout);
auto display = new ArchidektApiResponseDeckListingsDisplayWidget(currentPageDisplay, deckData);
connect(display, &ArchidektApiResponseDeckListingsDisplayWidget::requestNavigation, this,
&TabArchidekt::actNavigatePage);
currentPageLayout->addWidget(display);
mainLayout->addWidget(currentPageDisplay);
// **Ensure layout stays correct**
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
}
void TabArchidekt::processDeckResponse(QJsonObject reply)
{
ArchidektApiResponseDeck deckData;
deckData.fromJson(reply);
// **Remove previous page display to prevent stacking**
if (currentPageDisplay) {
mainLayout->removeWidget(currentPageDisplay);
delete currentPageDisplay;
currentPageDisplay = nullptr;
}
// **Create new currentPageDisplay**
currentPageDisplay = new QWidget(container);
currentPageLayout = new QVBoxLayout(currentPageDisplay);
currentPageDisplay->setLayout(currentPageLayout);
auto display = new ArchidektApiResponseDeckDisplayWidget(currentPageDisplay, deckData, cardSizeSlider);
connect(display, &ArchidektApiResponseDeckDisplayWidget::requestNavigation, this,
&TabArchidekt::actNavigatePage);
connect(display, &ArchidektApiResponseDeckDisplayWidget::openInDeckEditor, tabSupervisor, &TabSupervisor::openDeckInNewTab);
currentPageLayout->addWidget(display);
mainLayout->addWidget(currentPageDisplay);
// **Ensure layout stays correct**
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
}
void TabArchidekt::prettyPrintJson(const QJsonValue &value, int indentLevel)
{
const QString indent(indentLevel * 2, ' '); // Adjust spacing as needed for pretty printing
if (value.isObject()) {
QJsonObject obj = value.toObject();
for (auto it = obj.begin(); it != obj.end(); ++it) {
qDebug().noquote() << indent + it.key() + ":";
prettyPrintJson(it.value(), indentLevel + 1);
}
} else if (value.isArray()) {
QJsonArray array = value.toArray();
for (int i = 0; i < array.size(); ++i) {
qDebug().noquote() << indent + QString("[%1]:").arg(i);
prettyPrintJson(array[i], indentLevel + 1);
}
} else if (value.isString()) {
qDebug().noquote() << indent + "\"" + value.toString() + "\"";
} else if (value.isDouble()) {
qDebug().noquote() << indent + QString::number(value.toDouble());
} else if (value.isBool()) {
qDebug().noquote() << indent + (value.toBool() ? "true" : "false");
} else if (value.isNull()) {
qDebug().noquote() << indent + "null";
}
}

View file

@ -0,0 +1,63 @@
#ifndef COCKATRICE_TAB_ARCHIDEKT_H
#define COCKATRICE_TAB_ARCHIDEKT_H
#include "../../interface/widgets/cards/card_size_widget.h"
#include "../../interface/widgets/quick_settings/settings_button_widget.h"
#include "../../tab.h"
#include <QHBoxLayout>
#include <QLineEdit>
#include <QNetworkAccessManager>
#include <QPushButton>
#include <libcockatrice/card/database/card_database.h>
#include <QString>
inline QString archidektApiLink = "https://archidekt.com/api/decks/v3/?name=";
class TabArchidekt : public Tab
{
Q_OBJECT
public:
explicit TabArchidekt(TabSupervisor *_tabSupervisor);
void retranslateUi() override;
void doSearch();
QString getTabText() const override
{
auto cardName = cardToQuery.isNull() ? QString() : cardToQuery->getName();
return tr("Archidekt: ") + cardName;
}
CardSizeWidget *getCardSizeSlider()
{
return cardSizeSlider;
}
QNetworkAccessManager *networkManager;
public slots:
void processApiJson(QNetworkReply *reply);
void processTopDecksResponse(QJsonObject reply);
void processDeckResponse(QJsonObject reply);
void prettyPrintJson(const QJsonValue &value, int indentLevel);
void actNavigatePage(QString url);
void getTopDecks();
private:
QWidget *container;
QWidget *navigationContainer;
QWidget *currentPageDisplay;
QVBoxLayout *mainLayout;
QHBoxLayout *navigationLayout;
QVBoxLayout *currentPageLayout;
QPushButton *decksPushButton;
QLineEdit *searchBar;
QPushButton *searchPushButton;
SettingsButtonWidget *settingsButton;
CardSizeWidget *cardSizeSlider;
CardInfoPtr cardToQuery;
};
#endif // COCKATRICE_TAB_ARCHIDEKT_H

View file

@ -5,6 +5,7 @@
#include "../interface/widgets/server/user/user_list_manager.h" #include "../interface/widgets/server/user/user_list_manager.h"
#include "../interface/widgets/server/user/user_list_widget.h" #include "../interface/widgets/server/user/user_list_widget.h"
#include "../main.h" #include "../main.h"
#include "api/archidekt/tab_archidekt.h"
#include "api/edhrec/tab_edhrec_main.h" #include "api/edhrec/tab_edhrec_main.h"
#include "tab_account.h" #include "tab_account.h"
#include "tab_admin.h" #include "tab_admin.h"
@ -140,6 +141,9 @@ TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *
aTabEdhRec = new QAction(this); aTabEdhRec = new QAction(this);
connect(aTabEdhRec, &QAction::triggered, this, [this] { addEdhrecMainTab(); }); connect(aTabEdhRec, &QAction::triggered, this, [this] { addEdhrecMainTab(); });
aTabArchidekt = new QAction(this);
connect(aTabArchidekt, &QAction::triggered, this, [this] { addArchidektTab(); });
aTabHome = new QAction(this); aTabHome = new QAction(this);
aTabHome->setCheckable(true); aTabHome->setCheckable(true);
connect(aTabHome, &QAction::triggered, this, &TabSupervisor::actTabHome); connect(aTabHome, &QAction::triggered, this, &TabSupervisor::actTabHome);
@ -204,6 +208,7 @@ void TabSupervisor::retranslateUi()
aTabDeckEditor->setText(tr("Deck Editor")); aTabDeckEditor->setText(tr("Deck Editor"));
aTabVisualDeckEditor->setText(tr("Visual Deck Editor")); aTabVisualDeckEditor->setText(tr("Visual Deck Editor"));
aTabEdhRec->setText(tr("EDHRec")); aTabEdhRec->setText(tr("EDHRec"));
aTabArchidekt->setText(tr("Archidekt"));
aTabHome->setText(tr("Home")); aTabHome->setText(tr("Home"));
aTabVisualDeckStorage->setText(tr("&Visual Deck Storage")); aTabVisualDeckStorage->setText(tr("&Visual Deck Storage"));
aTabVisualDatabaseDisplay->setText(tr("Visual Database Display")); aTabVisualDatabaseDisplay->setText(tr("Visual Database Display"));
@ -386,6 +391,7 @@ void TabSupervisor::resetTabsMenu()
tabsMenu->addAction(aTabDeckEditor); tabsMenu->addAction(aTabDeckEditor);
tabsMenu->addAction(aTabVisualDeckEditor); tabsMenu->addAction(aTabVisualDeckEditor);
tabsMenu->addAction(aTabEdhRec); tabsMenu->addAction(aTabEdhRec);
tabsMenu->addAction(aTabArchidekt);
tabsMenu->addSeparator(); tabsMenu->addSeparator();
tabsMenu->addAction(aTabHome); tabsMenu->addAction(aTabHome);
tabsMenu->addAction(aTabVisualDeckStorage); tabsMenu->addAction(aTabVisualDeckStorage);
@ -899,6 +905,15 @@ TabEdhRecMain *TabSupervisor::addEdhrecMainTab()
return tab; return tab;
} }
TabArchidekt *TabSupervisor::addArchidektTab()
{
auto *tab = new TabArchidekt(this);
myAddTab(tab);
setCurrentWidget(tab);
return tab;
}
TabVisualDatabaseDisplay *TabSupervisor::addVisualDatabaseDisplayTab() TabVisualDatabaseDisplay *TabSupervisor::addVisualDatabaseDisplayTab()
{ {
auto *tab = new TabVisualDatabaseDisplay(this); auto *tab = new TabVisualDatabaseDisplay(this);

View file

@ -11,6 +11,7 @@
#include "../../deck_loader/deck_loader.h" #include "../../deck_loader/deck_loader.h"
#include "../interface/widgets/server/user/user_list_proxy.h" #include "../interface/widgets/server/user/user_list_proxy.h"
#include "abstract_tab_deck_editor.h" #include "abstract_tab_deck_editor.h"
#include "api/archidekt/tab_archidekt.h"
#include "api/edhrec/tab_edhrec.h" #include "api/edhrec/tab_edhrec.h"
#include "api/edhrec/tab_edhrec_main.h" #include "api/edhrec/tab_edhrec_main.h"
#include "tab_visual_database_display.h" #include "tab_visual_database_display.h"
@ -110,7 +111,7 @@ private:
QList<AbstractTabDeckEditor *> deckEditorTabs; QList<AbstractTabDeckEditor *> deckEditorTabs;
bool isLocalGame; bool isLocalGame;
QAction *aTabHome, *aTabDeckEditor, *aTabVisualDeckEditor, *aTabEdhRec, *aTabVisualDeckStorage, QAction *aTabHome, *aTabDeckEditor, *aTabVisualDeckEditor, *aTabEdhRec, *aTabArchidekt, *aTabVisualDeckStorage,
*aTabVisualDatabaseDisplay, *aTabServer, *aTabAccount, *aTabDeckStorage, *aTabReplays, *aTabAdmin, *aTabLog; *aTabVisualDatabaseDisplay, *aTabServer, *aTabAccount, *aTabDeckStorage, *aTabReplays, *aTabAdmin, *aTabLog;
int myAddTab(Tab *tab, QAction *manager = nullptr); int myAddTab(Tab *tab, QAction *manager = nullptr);
@ -172,6 +173,7 @@ public slots:
TabDeckEditorVisual *addVisualDeckEditorTab(DeckLoader *deckToOpen); TabDeckEditorVisual *addVisualDeckEditorTab(DeckLoader *deckToOpen);
TabVisualDatabaseDisplay *addVisualDatabaseDisplayTab(); TabVisualDatabaseDisplay *addVisualDatabaseDisplayTab();
TabEdhRecMain *addEdhrecMainTab(); TabEdhRecMain *addEdhrecMainTab();
TabArchidekt *addArchidektTab();
TabEdhRec *addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander = false); TabEdhRec *addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander = false);
void openReplay(GameReplay *replay); void openReplay(GameReplay *replay);
void switchToFirstAvailableNetworkTab(); void switchToFirstAvailableNetworkTab();