Add support for configuring featured art

This commit is contained in:
Joshua Goins 2023-09-02 09:47:58 -04:00
parent 914bf53cf1
commit 94aa711634
8 changed files with 145 additions and 10 deletions

View file

@ -42,6 +42,8 @@ target_sources(Redai PRIVATE
src/artdetailwindow.h src/artdetailwindow.h
src/artmodel.cpp src/artmodel.cpp
src/artmodel.h src/artmodel.h
src/featuredartmodel.cpp
src/featuredartmodel.h
src/imagelabel.cpp src/imagelabel.cpp
src/imagelabel.h src/imagelabel.h
src/main.cpp src/main.cpp

View file

@ -15,7 +15,7 @@
#include <QPushButton> #include <QPushButton>
#include <QScrollArea> #include <QScrollArea>
ArtConfigWindow::ArtConfigWindow(const QString &filename, QWidget *parent) ArtConfigWindow::ArtConfigWindow(const QString &filename, const QString &definitionDirectory, const QString &assetDirectory, QWidget *parent)
: QDialog(parent) : QDialog(parent)
{ {
setWindowModality(Qt::WindowModality::WindowModal); setWindowModality(Qt::WindowModality::WindowModal);
@ -30,8 +30,11 @@ ArtConfigWindow::ArtConfigWindow(const QString &filename, QWidget *parent)
formLayoutWidget->setLayout(formLayout); formLayoutWidget->setLayout(formLayout);
mainLayout->addWidget(formLayoutWidget); mainLayout->addWidget(formLayoutWidget);
auto galleryScrollArea = new QScrollArea(); model = new FeaturedArtModel(definitionDirectory, assetDirectory);
formLayout->addWidget(galleryScrollArea);
auto galleryListView = new QListView();
galleryListView->setModel(model);
formLayout->addWidget(galleryListView);
m_newBannerEdit = new QLineEdit(); m_newBannerEdit = new QLineEdit();
formLayout->addRow(i18nc("@label:textbox", "New Banner"), m_newBannerEdit); formLayout->addRow(i18nc("@label:textbox", "New Banner"), m_newBannerEdit);
@ -47,10 +50,11 @@ ArtConfigWindow::ArtConfigWindow(const QString &filename, QWidget *parent)
bottomButtonLayout->addWidget(cancelButton); bottomButtonLayout->addWidget(cancelButton);
bottomButtonLayout->addStretch(1); bottomButtonLayout->addStretch(1);
auto saveButton = new QPushButton(QIcon::fromTheme(QStringLiteral("dialog-ok")), i18nc("@action:button", "Save")); saveButton = new QPushButton(QIcon::fromTheme(QStringLiteral("dialog-ok")), i18nc("@action:button", "Save"));
connect(saveButton, &QPushButton::clicked, this, [this, filename] { connect(saveButton, &QPushButton::clicked, this, [this, filename] {
saveData(filename); saveData(filename);
}); });
saveButton->setEnabled(false);
bottomButtonLayout->addWidget(saveButton); bottomButtonLayout->addWidget(saveButton);
if (QFile::exists(filename)) { if (QFile::exists(filename)) {
@ -69,6 +73,16 @@ void ArtConfigWindow::loadData(const QString &filename)
m_newBannerEdit->setText(artJson[QStringLiteral("new-banner")].toString()); m_newBannerEdit->setText(artJson[QStringLiteral("new-banner")].toString());
m_commissionsOpen->setChecked(artJson[QStringLiteral("commissions")].toBool()); m_commissionsOpen->setChecked(artJson[QStringLiteral("commissions")].toBool());
connect(model, &ArtModel::loadingFinished, this, [=] {
saveButton->setEnabled(true);
QStringList featuredList;
for (auto featuredId : artJson["featured"].toArray()) {
featuredList.push_back(featuredId.toString());
}
model->setFeaturedItems(featuredList);
});
} }
void ArtConfigWindow::saveData(const QString &filename) void ArtConfigWindow::saveData(const QString &filename)
@ -79,6 +93,17 @@ void ArtConfigWindow::saveData(const QString &filename)
object[QStringLiteral("new-banner")] = m_newBannerEdit->text(); object[QStringLiteral("new-banner")] = m_newBannerEdit->text();
object[QStringLiteral("commissions")] = m_commissionsOpen->isChecked(); object[QStringLiteral("commissions")] = m_commissionsOpen->isChecked();
QJsonArray featuredArray;
for (int i = 0; i < model->rowCount({}); i++) {
const auto checkState = model->data(model->index(i, 0), Qt::CheckStateRole).value<Qt::CheckState>();
if (checkState == Qt::Checked) {
QFileInfo fileInfo(model->data(model->index(i, 1), Qt::DisplayRole).toString());
featuredArray.push_back(fileInfo.baseName());
}
}
object["featured"] = featuredArray;
const QJsonDocument jsonDoc(object); const QJsonDocument jsonDoc(object);
QFile file(filename); QFile file(filename);

View file

@ -13,11 +13,13 @@
#include <QStringListModel> #include <QStringListModel>
#include <QTextEdit> #include <QTextEdit>
#include "featuredartmodel.h"
class ArtConfigWindow : public QDialog class ArtConfigWindow : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ArtConfigWindow(const QString &filename, QWidget *parent = nullptr); explicit ArtConfigWindow(const QString &filename, const QString &definitionDirectory, const QString &assetDirectory, QWidget *parent = nullptr);
private: private:
void loadData(const QString &filename); void loadData(const QString &filename);
@ -25,4 +27,8 @@ private:
QLineEdit *m_newBannerEdit = nullptr; QLineEdit *m_newBannerEdit = nullptr;
QCheckBox *m_commissionsOpen = nullptr; QCheckBox *m_commissionsOpen = nullptr;
FeaturedArtModel *model = nullptr;
QPushButton *saveButton = nullptr;
}; };

View file

@ -43,7 +43,7 @@ ArtModel::ArtModel(const QDir &definitionDirectory, const QDir &assetDirectory,
endInsertRows(); endInsertRows();
} }
const std::function<ArtPiece(const PieceInformation &info)> loadPiece = [this](const PieceInformation &info) -> ArtPiece { const std::function<ArtPiece(const PieceInformation &info)> loadPiece = [](const PieceInformation &info) -> ArtPiece {
ArtPiece p(info.definition, info.asset); ArtPiece p(info.definition, info.asset);
p.image.load(p.filename); p.image.load(p.filename);
@ -134,6 +134,8 @@ void ArtModel::finished()
}); });
Q_EMIT dataChanged(index(0, 0), index(m_artPieces.size(), 0)); Q_EMIT dataChanged(index(0, 0), index(m_artPieces.size(), 0));
Q_EMIT loadingFinished();
} }
ArtPiece::ArtPiece(const QString &filename, const QString &assetFilename) ArtPiece::ArtPiece(const QString &filename, const QString &assetFilename)

View file

@ -38,11 +38,15 @@ public:
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override; [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Q_SIGNALS:
void loadingFinished();
protected:
QVector<ArtPiece> m_artPieces;
private: private:
void pieceFinished(int index); void pieceFinished(int index);
void finished(); void finished();
QFutureWatcher<ArtPiece> *piecesFuture; QFutureWatcher<ArtPiece> *piecesFuture;
QVector<ArtPiece> m_artPieces;
}; };

71
src/featuredartmodel.cpp Normal file
View file

@ -0,0 +1,71 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include "featuredartmodel.h"
#include <QFileInfo>
FeaturedArtModel::FeaturedArtModel(const QString &definitionDirectory, const QString &assetDirectory)
: ArtModel(definitionDirectory, assetDirectory)
{
}
QVariant FeaturedArtModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role == Qt::DisplayRole) {
if (index.column() == 0) {
return ArtModel::data(FeaturedArtModel::index(index.row(), 2), role);
} else {
return ArtModel::data(FeaturedArtModel::index(index.row(), 0), role);
}
} else if (role == Qt::DecorationRole && index.column() == 0) {
return ArtModel::data(FeaturedArtModel::index(index.row(), 1), role);
} else if (role == Qt::CheckStateRole) {
return checkedItems.contains(index) ? Qt::Checked : Qt::Unchecked;
}
return ArtModel::data(index, role);
}
Qt::ItemFlags FeaturedArtModel::flags(const QModelIndex &index) const
{
const Qt::ItemFlags defaultFlags = ArtModel::flags(index);
if (index.isValid()) {
return defaultFlags | Qt::ItemIsUserCheckable;
}
return defaultFlags;
}
bool FeaturedArtModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || role != Qt::CheckStateRole) {
return false;
}
if (value == Qt::Checked) {
checkedItems.insert(index);
} else {
checkedItems.remove(index);
}
emit dataChanged(index, index);
return true;
}
void FeaturedArtModel::setFeaturedItems(QStringList featured)
{
for (const auto &id : featured) {
for (int i = 0; i < m_artPieces.size(); i++) {
ArtPiece &piece = m_artPieces[i];
QFileInfo fileInfo(piece.jsonFilename);
if (fileInfo.baseName() == id) {
setData(index(i, 0), Qt::Checked, Qt::CheckStateRole);
}
}
}
}

24
src/featuredartmodel.h Normal file
View file

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "artmodel.h"
class FeaturedArtModel : public ArtModel
{
public:
FeaturedArtModel(const QString &definitionDirectory, const QString &assetDirectory);
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
[[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
void setFeaturedItems(QStringList featured);
private:
QSet<QPersistentModelIndex> checkedItems;
};

View file

@ -25,8 +25,9 @@ MainWindow::MainWindow(const QDir &definitionDirectory, const QDir &assetDirecto
auto manageMenu = menuBar->addMenu(i18nc("@title:menu Manage site", "Manage")); auto manageMenu = menuBar->addMenu(i18nc("@title:menu Manage site", "Manage"));
auto editConfigAction = manageMenu->addAction(i18nc("@action:inmenu", "Edit Config...")); auto editConfigAction = manageMenu->addAction(i18nc("@action:inmenu", "Edit Config..."));
connect(editConfigAction, &QAction::triggered, this, [this, dataDirectory] { connect(editConfigAction, &QAction::triggered, this, [this, dataDirectory, definitionDirectory, assetDirectory] {
auto window = new ArtConfigWindow(dataDirectory.absoluteFilePath("art-config.json"), this); auto window =
new ArtConfigWindow(dataDirectory.absoluteFilePath("art-config.json"), definitionDirectory.absolutePath(), assetDirectory.absolutePath(), this);
window->show(); window->show();
}); });