Skip to content

Commit

Permalink
curseforge| indexed files & loader type filter
Browse files Browse the repository at this point in the history
Signed-off-by: kaniol-lck <[email protected]>
  • Loading branch information
kaniol-lck committed Jun 6, 2024
1 parent 98139ed commit 67d6cfe
Show file tree
Hide file tree
Showing 12 changed files with 271 additions and 43 deletions.
45 changes: 40 additions & 5 deletions src/curseforge/curseforgeapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,17 @@ Reply<CurseforgeFileInfo> CurseforgeAPI::getFileInfo(int id, int FileID)
} };
}

Reply<QList<CurseforgeFileInfo>, int> CurseforgeAPI::getFiles(int id, int index, GameVersion version)
Reply<QList<CurseforgeFileInfo>, int> CurseforgeAPI::getModFiles(int id, int index, GameVersion version, ModLoaderType::Type loaderType)
{
//TODO: page
QUrl url = PREFIX + "/v1/mods/" + QString::number(id) + "/files";
//url query
QUrlQuery urlQuery;
//version
if(version != GameVersion::Any)
urlQuery.addQueryItem("gameVersion", version.toString());
//loader tye
if(loaderType != ModLoaderType::Any)
urlQuery.addQueryItem("modLoaderType", QString::number(ModLoaderType::curseforge.indexOf(loaderType)));
//index
urlQuery.addQueryItem("index", QString::number(index));
//page size
Expand All @@ -181,7 +183,7 @@ Reply<QList<CurseforgeFileInfo>, int> CurseforgeAPI::getFiles(int id, int index,
QJsonDocument jsonDocument = QJsonDocument::fromJson(reply->readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qDebug("%s", error.errorString().toUtf8().constData());
return std::make_pair(QList<CurseforgeFileInfo>{}, 0);
return std::make_tuple(QList<CurseforgeFileInfo>{}, 0);
}
auto resultList = value(jsonDocument.toVariant(), "data").toList();
auto totalCount = value(jsonDocument.toVariant(), "pagination", "totalCount").toInt();
Expand All @@ -190,8 +192,41 @@ Reply<QList<CurseforgeFileInfo>, int> CurseforgeAPI::getFiles(int id, int index,
for(const auto &result : qAsConst(resultList))
fileInfoList << CurseforgeFileInfo::fromVariant(result);

return std::make_pair(fileInfoList, totalCount);
} };
return std::make_tuple(fileInfoList, totalCount);
} };
}

Reply<QList<CurseforgeFileInfo> > CurseforgeAPI::getFiles(QList<int> fileIds)
{
QUrl url = PREFIX + "/v1/mods/files";

QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("x-api-key",XAPIKEY);
MMLogger::network(this) << url;
QJsonArray list;
for(auto &&fileId : fileIds)
list << fileId;
QJsonObject data{
{ "fileIds", list }
};
auto reply = accessManager_.post(request, QJsonDocument(data).toJson(QJsonDocument::Compact));
return { reply, [=]{
//parse json
QJsonParseError error;
QJsonDocument jsonDocument = QJsonDocument::fromJson(reply->readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qDebug("%s", error.errorString().toUtf8().constData());
return std::make_tuple(QList<CurseforgeFileInfo>{});
}
auto resultList = value(jsonDocument.toVariant(), "data").toList();

QList<CurseforgeFileInfo> fileInfoList;
for(const auto &result : qAsConst(resultList))
fileInfoList << CurseforgeFileInfo::fromVariant(result);

return std::make_tuple(fileInfoList);
} };
}

Reply<CurseforgeModInfo> CurseforgeAPI::getInfo(int id)
Expand Down
3 changes: 2 additions & 1 deletion src/curseforge/curseforgeapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class CurseforgeAPI : public QObject
Reply<QString> getChangelog(int id, int FileID);
Reply<QString> getDownloadUrl(int id, int FileID);
Reply<CurseforgeFileInfo> getFileInfo(int id, int FileID);
Reply<QList<CurseforgeFileInfo>, int> getFiles(int id, int index, GameVersion version = GameVersion::Any);
Reply<QList<CurseforgeFileInfo>, int> getModFiles(int id, int index, GameVersion version = GameVersion::Any, ModLoaderType::Type modLoader = ModLoaderType::Any);
Reply<QList<CurseforgeFileInfo> > getFiles(QList<int> fileIds);
Reply<CurseforgeModInfo> getInfo(int id);
Reply<QString> getTimestamp();
Reply<QList<GameVersion> > getMinecraftVersionList();
Expand Down
3 changes: 2 additions & 1 deletion src/curseforge/curseforgemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ CurseforgeManager::CurseforgeManager(QObject *parent, CurseforgeAPI::Section sec
sectionId_(sectionId)
{}

void CurseforgeManager::search(const QString &name, int categoryId, GameVersion gameVersion, int sort, bool sortOrderAsc)
void CurseforgeManager::search(const QString &name, int categoryId, GameVersion gameVersion, ModLoaderType::Type modLoader, int sort, bool sortOrderAsc)
{
currentIndex_ = 0;
currentName_ = name;
currentCategoryId_ = categoryId;
currentGameVersion_ = gameVersion;
currentLoaderType_ = modLoader;
currentSort_ = sort;
currentSortOrderAsc_ = sortOrderAsc;
getModList();
Expand Down
2 changes: 1 addition & 1 deletion src/curseforge/curseforgemanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class CurseforgeManager : public ExploreManager
public:
CurseforgeManager(QObject *parent = nullptr, CurseforgeAPI::Section sectionId = CurseforgeAPI::Mod);

void search(const QString &name, int categoryId, GameVersion version, int sort, bool sortOrderAsc);
void search(const QString &name, int categoryId, GameVersion version, ModLoaderType::Type modLoader, int sort, bool sortOrderAsc);
void searchMore();
void refresh();

Expand Down
17 changes: 15 additions & 2 deletions src/curseforge/curseforgemod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,23 @@ void CurseforgeMod::acquireDescription()
});
}

std::shared_ptr<Reply<QList<CurseforgeFileInfo>, int>> CurseforgeMod::acquireMoreFileList(GameVersion version, bool clear)
std::shared_ptr<Reply<QList<CurseforgeFileInfo> > > CurseforgeMod::acquireLatestIndexedFileList()
{
if(latestIndexedFileListGetter_ && latestIndexedFileListGetter_->isRunning()) return latestIndexedFileListGetter_;
latestIndexedFileListGetter_ = api_->getFiles(modInfo_.latestFileIndexList()).asShared();
latestIndexedFileListGetter_->setOnFinished(this, [=](const QList<CurseforgeFileInfo> &fileList){
modInfo_.latestIndexedFileList_ = fileList;
emit latestIndexedFileListReady(fileList);
}, [=](auto){
emit latestIndexedFileListReady({});
});
return latestIndexedFileListGetter_;
}

std::shared_ptr<Reply<QList<CurseforgeFileInfo>, int>> CurseforgeMod::acquireMoreFileList(GameVersion version, ModLoaderType::Type loaderType, bool clear)
{
if(allFileListGetter_ && allFileListGetter_->isRunning()) return allFileListGetter_;
allFileListGetter_ = api_->getFiles(modInfo_.id(), clear? 0: modInfo().allFileList().size(), version).asUnique();
allFileListGetter_ = api_->getModFiles(modInfo_.id(), clear? 0: modInfo().allFileList().size(), version, loaderType).asShared();
allFileListGetter_->setOnFinished(this, [=](const QList<CurseforgeFileInfo> &fileList, int count){
if(clear)
modInfo_.allFileList_ = fileList;
Expand Down
9 changes: 6 additions & 3 deletions src/curseforge/curseforgemod.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class CurseforgeMod : public QObject, public Tagable
void acquireBasicInfo();
void acquireIcon();
void acquireDescription();
std::shared_ptr<Reply<QList<CurseforgeFileInfo>, int>> acquireMoreFileList(GameVersion version = GameVersion::Any, bool clear = false);
std::shared_ptr<Reply<QList<CurseforgeFileInfo>>> acquireLatestIndexedFileList();
std::shared_ptr<Reply<QList<CurseforgeFileInfo>, int>> acquireMoreFileList(GameVersion version = GameVersion::Any, ModLoaderType::Type loaderType = ModLoaderType::Any, bool clear = false);

const CurseforgeModInfo &modInfo() const;
void download(const CurseforgeFileInfo &fileInfo, LocalModPath *downloadPath = nullptr);
Expand All @@ -38,6 +39,7 @@ class CurseforgeMod : public QObject, public Tagable
void basicInfoReady();
void iconReady();
void descriptionReady();
void latestIndexedFileListReady(QList<CurseforgeFileInfo> fileInfos);
void moreFileListReady(QList<CurseforgeFileInfo> fileInfos);

void downloadStarted();
Expand All @@ -47,9 +49,10 @@ class CurseforgeMod : public QObject, public Tagable
CurseforgeModInfo modInfo_;
QAria2Downloader *downloader_;

std::shared_ptr<Reply<CurseforgeModInfo>> basicInfoGetter_;
std::unique_ptr<Reply<CurseforgeModInfo>> basicInfoGetter_;
bool gettingIcon_ = false;
std::shared_ptr<Reply<QString>> descriptionGetter_;
std::unique_ptr<Reply<QString>> descriptionGetter_;
std::shared_ptr<Reply<QList<CurseforgeFileInfo>>> latestIndexedFileListGetter_;
std::shared_ptr<Reply<QList<CurseforgeFileInfo>, int>> allFileListGetter_;
};

Expand Down
17 changes: 16 additions & 1 deletion src/curseforge/curseforgemodinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,15 @@ CurseforgeModInfo CurseforgeModInfo::fromVariant(const QVariant &variant)
modInfo.iconUrl_ = value(value(variant,"logo"),"thumbnailUrl").toUrl();


//latest file url
//latest files
for(auto &&variant : value(variant, "latestFiles").toList())
modInfo.latestFileList_ << CurseforgeFileInfo::fromVariant(variant);

//latest file indexes
for(auto &&variant : value(variant, "latestFilesIndexes").toList())
if(auto id = value(variant, "fileId").toInt(); !modInfo.latestFileIndexList_.contains(id))
modInfo.latestFileIndexList_ << value(variant, "fileId").toInt();

//categories
for(auto &&variant : value(variant, "categories").toList()){
auto category = CurseforgeCategoryInfo::fromVariant(variant);
Expand Down Expand Up @@ -136,6 +141,16 @@ void CurseforgeModInfo::setTotalFileCount(int newTotalFileCount)
totalFileCount_ = newTotalFileCount;
}

const QList<int> &CurseforgeModInfo::latestFileIndexList() const
{
return latestFileIndexList_;
}

const QList<CurseforgeFileInfo> &CurseforgeModInfo::latestIndexedFileList() const
{
return latestIndexedFileList_;
}

const QList<CurseforgeCategoryInfo> &CurseforgeModInfo::categories() const
{
return categories_;
Expand Down
6 changes: 6 additions & 0 deletions src/curseforge/curseforgemodinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,19 @@ class CurseforgeModInfo : public CurseforgeModCacheInfo, Tagable
int totalFileCount() const;
void setTotalFileCount(int newTotalFileCount);

const QList<int> &latestFileIndexList() const;

const QList<CurseforgeFileInfo> &latestIndexedFileList() const;

private:
QUrl websiteUrl_;
QList<Attachment> images_;
QStringList authors_;
QString description_;
int downloadCount_;
QList<CurseforgeFileInfo> latestFileList_;
QList<CurseforgeFileInfo> latestIndexedFileList_;
QList<int> latestFileIndexList_;
QList<CurseforgeFileInfo> allFileList_;
int totalFileCount_ = 0;
QList<CurseforgeCategoryInfo> categories_;
Expand Down
100 changes: 90 additions & 10 deletions src/ui/curseforge/curseforgefilelistwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,27 @@ CurseforgeFileListWidget::CurseforgeFileListWidget(CurseforgeModBrowser *parent)
ui->setupUi(this);
ui->versionSelect->setDefaultAction(versionMenu_->menuAction());
ui->versionSelect->setPopupMode(QToolButton::InstantPopup);

ui->loaderTypeSelecct->blockSignals(true);
for(const auto &type : ModLoaderType::curseforge)
ui->loaderTypeSelecct->addItem(ModLoaderType::icon(type), ModLoaderType::toString(type));
ui->loaderTypeSelecct->blockSignals(false);

ui->fileListView->setModel(&model_);
ui->allFileListView->setModel(&model2_);
ui->fileListView->setVerticalScrollBar(new SmoothScrollBar(this));
ui->fileListView->setProperty("class", "ModList");
ui->allFileListView->setVerticalScrollBar(new SmoothScrollBar(this));
ui->allFileListView->setProperty("class", "ModList");
connect(ui->fileListView->verticalScrollBar(), &QAbstractSlider::valueChanged, this , &CurseforgeFileListWidget::updateIndexWidget);
connect(ui->fileListView->verticalScrollBar(), &QSlider::valueChanged, this, &CurseforgeFileListWidget::onListSliderChanged);
connect(ui->allFileListView->verticalScrollBar(), &QAbstractSlider::valueChanged, this , &CurseforgeFileListWidget::updateIndexWidget2);
connect(ui->allFileListView->verticalScrollBar(), &QSlider::valueChanged, this, &CurseforgeFileListWidget::onListSliderChanged);
updateVersionList();
connect(VersionManager::manager(), &VersionManager::curseforgeVersionListUpdated, this, &CurseforgeFileListWidget::updateVersionList);
ui->downloadPathSelect->hide();
downloadPathSelectMenu_ = parent->downloadPathSelectMenu();
ui->versionSelect->setVisible(false);
ui->loaderTypeSelecct->setVisible(false);
}

CurseforgeFileListWidget::CurseforgeFileListWidget(QWidget *parent, LocalMod *localMod) :
Expand All @@ -39,18 +51,30 @@ CurseforgeFileListWidget::CurseforgeFileListWidget(QWidget *parent, LocalMod *lo
ui->setupUi(this);
ui->versionSelect->setDefaultAction(versionMenu_->menuAction());
ui->versionSelect->setPopupMode(QToolButton::InstantPopup);

ui->loaderTypeSelecct->blockSignals(true);
for(const auto &type : ModLoaderType::curseforge)
ui->loaderTypeSelecct->addItem(ModLoaderType::icon(type), ModLoaderType::toString(type));
ui->loaderTypeSelecct->blockSignals(false);

ui->fileListView->setModel(&model_);
ui->allFileListView->setModel(&model2_);
ui->fileListView->setVerticalScrollBar(new SmoothScrollBar(this));
ui->fileListView->setProperty("class", "ModList");
ui->allFileListView->setVerticalScrollBar(new SmoothScrollBar(this));
ui->allFileListView->setProperty("class", "ModList");
connect(ui->fileListView->verticalScrollBar(), &QAbstractSlider::valueChanged, this, &CurseforgeFileListWidget::updateIndexWidget);
connect(ui->fileListView->verticalScrollBar(), &QSlider::valueChanged, this, &CurseforgeFileListWidget::onListSliderChanged);
connect(ui->allFileListView->verticalScrollBar(), &QAbstractSlider::valueChanged, this, &CurseforgeFileListWidget::updateIndexWidget2);
connect(ui->allFileListView->verticalScrollBar(), &QSlider::valueChanged, this, &CurseforgeFileListWidget::onListSliderChanged);
updateVersionList();
connect(VersionManager::manager(), &VersionManager::curseforgeVersionListUpdated, this, &CurseforgeFileListWidget::updateVersionList);
ui->downloadPathSelect->hide();
downloadPathSelectMenu_ = new DownloadPathSelectMenu(this);
ui->downloadPathSelect->setDefaultAction(downloadPathSelectMenu_->menuAction());
ui->downloadPathSelect->setPopupMode(QToolButton::InstantPopup);
setLocalMod(localMod);
ui->versionSelect->setVisible(false);
ui->loaderTypeSelecct->setVisible(false);
}

CurseforgeFileListWidget::~CurseforgeFileListWidget()
Expand All @@ -65,10 +89,12 @@ void CurseforgeFileListWidget::setMod(CurseforgeMod *mod)
ui->fileListView->setVisible(mod_);
if(!mod_) return;
connect(this, &CurseforgeFileListWidget::modChanged, disconnecter(
connect(mod_, &CurseforgeMod::moreFileListReady, this, &CurseforgeFileListWidget::updateFileList),
connect(mod_, &CurseforgeMod::latestIndexedFileListReady, this, &CurseforgeFileListWidget::updateFileList),
connect(mod_, &CurseforgeMod::moreFileListReady, this, &CurseforgeFileListWidget::updateFileList2),
connect(mod_, &QObject::destroyed, this, [=]{ setMod(nullptr); })));

mod_->acquireLatestIndexedFileList();
updateFileList();
updateFileList2();
search();
}

Expand All @@ -81,17 +107,35 @@ void CurseforgeFileListWidget::updateUi()
void CurseforgeFileListWidget::updateFileList()
{
model_.clear();
for(int i = 0; i < mod_->modInfo().allFileList().size(); i++){
for(int i = 0; i < mod_->modInfo().latestIndexedFileList().size(); i++){
auto item = new QStandardItem;
model_.appendRow(item);
auto &&fileInfo = mod_->modInfo().allFileList().at(i);
auto &&fileInfo = mod_->modInfo().latestIndexedFileList().at(i);
item->setData(fileInfo.fileDate(), Qt::UserRole);
item->setData(i, Qt::UserRole + 1);
item->setSizeHint(QSize(0, 100));
}
model_.setSortRole(Qt::UserRole);
model_.sort(0, Qt::DescendingOrder);
ui->fileListView->setCursor(Qt::ArrowCursor);
updateIndexWidget();
}

void CurseforgeFileListWidget::updateFileList2()
{
model2_.clear();
for(int i = 0; i < mod_->modInfo().allFileList().size(); i++){
auto item = new QStandardItem;
model2_.appendRow(item);
auto &&fileInfo = mod_->modInfo().allFileList().at(i);
item->setData(fileInfo.fileDate(), Qt::UserRole);
item->setData(i, Qt::UserRole + 1);
item->setSizeHint(QSize(0, 100));
}
model2_.setSortRole(Qt::UserRole);
model2_.sort(0, Qt::DescendingOrder);
ui->allFileListView->setCursor(Qt::ArrowCursor);
updateIndexWidget2();
}

void CurseforgeFileListWidget::paintEvent(QPaintEvent *event)
Expand Down Expand Up @@ -133,16 +177,37 @@ void CurseforgeFileListWidget::updateIndexWidget()
auto index = model_.index(row, 0);
if(ui->fileListView->indexWidget(index)) continue;
auto item = model_.item(row);
auto &&fileInfo = mod_->modInfo().allFileList().at(item->data(Qt::UserRole + 1).toInt());
auto &&fileInfo = mod_->modInfo().latestIndexedFileList().at(item->data(Qt::UserRole + 1).toInt());
auto itemWidget = new CurseforgeFileItemWidget(this, mod_, fileInfo);
ui->fileListView->setIndexWidget(model_.indexFromItem(item), itemWidget);
item->setSizeHint(QSize(0, itemWidget->height()));
}
}

void CurseforgeFileListWidget::updateIndexWidget2()
{
auto beginRow = ui->allFileListView->indexAt(QPoint(0, 0)).row();
if(beginRow < 0) return;
auto endRow = ui->allFileListView->indexAt(QPoint(0, ui->allFileListView->height())).row();
if(endRow < 0)
endRow = model2_.rowCount() - 1;
else
//extra 2
endRow += 2;
for(int row = beginRow; row <= endRow && row < model2_.rowCount(); row++){
auto index = model2_.index(row, 0);
if(ui->allFileListView->indexWidget(index)) continue;
auto item = model2_.item(row);
auto &&fileInfo = mod_->modInfo().allFileList().at(item->data(Qt::UserRole + 1).toInt());
auto itemWidget = new CurseforgeFileItemWidget(this, mod_, fileInfo);
ui->allFileListView->setIndexWidget(model2_.indexFromItem(item), itemWidget);
item->setSizeHint(QSize(0, itemWidget->height()));
}
}

void CurseforgeFileListWidget::onListSliderChanged(int i)
{
if(i >= ui->fileListView->verticalScrollBar()->maximum() - 1000){
if(i >= ui->allFileListView->verticalScrollBar()->maximum() - 1000){
search();
}
}
Expand Down Expand Up @@ -194,7 +259,22 @@ void CurseforgeFileListWidget::updateVersionList()
void CurseforgeFileListWidget::search(bool changed)
{
if(changed || !mod_->modInfo().fileCompleted()){
ui->fileListView->setCursor(Qt::BusyCursor);
mod_->acquireMoreFileList(currentGameVersion_, changed);
ui->allFileListView->setCursor(Qt::BusyCursor);
mod_->acquireMoreFileList(currentGameVersion_, currentLoaderType_, changed);
}
}

void CurseforgeFileListWidget::on_allFile_btn_toggled(bool checked)
{
ui->stackedWidget->setCurrentIndex(checked? 1: 0);
ui->versionSelect->setVisible(checked);
ui->loaderTypeSelecct->setVisible(checked);
}


void CurseforgeFileListWidget::on_loaderTypeSelecct_currentIndexChanged(int index)
{
currentLoaderType_ = ModLoaderType::curseforge.at(index);
search(true);
}

Loading

0 comments on commit 67d6cfe

Please sign in to comment.