diff --git a/src/core/managers/ModManager.cpp b/src/core/managers/ModManager.cpp index fba3fdc..3f25794 100644 --- a/src/core/managers/ModManager.cpp +++ b/src/core/managers/ModManager.cpp @@ -37,8 +37,10 @@ QString ModManager::getPaksPath() const { bool ModManager::addMod(const QString &pakFilePath, const QString &modName, const QString &nexusModId, const QString &nexusFileId, + const QString &nexusUrl, const QString &author, const QString &description, const QString &version, const QString &itchGameId, + const QString &itchUrl, const QDateTime &uploadDate) { QFileInfo fileInfo(pakFilePath); if (!fileInfo.exists() || !fileInfo.isFile()) { @@ -68,7 +70,9 @@ bool ModManager::addMod(const QString &pakFilePath, const QString &modName, mod.nexusModId = nexusModId; mod.nexusFileId = nexusFileId; + mod.nexusUrl = nexusUrl; mod.itchGameId = itchGameId; + mod.itchUrl = itchUrl; mod.author = author; mod.description = description; mod.version = version; @@ -489,7 +493,9 @@ bool ModManager::updateModMetadata(const ModInfo &updatedMod) { it->description = updatedMod.description; it->nexusModId = updatedMod.nexusModId; it->nexusFileId = updatedMod.nexusFileId; + it->nexusUrl = updatedMod.nexusUrl; it->itchGameId = updatedMod.itchGameId; + it->itchUrl = updatedMod.itchUrl; it->version = updatedMod.version; it->author = updatedMod.author; it->installDate = updatedMod.installDate; diff --git a/src/core/managers/ModManager.h b/src/core/managers/ModManager.h index ec5d1ba..8e08197 100644 --- a/src/core/managers/ModManager.h +++ b/src/core/managers/ModManager.h @@ -23,8 +23,10 @@ class ModManager : public QObject { // Mod management bool addMod(const QString &pakFilePath, const QString &modName = QString(), const QString &nexusModId = QString(), const QString &nexusFileId = QString(), + const QString &nexusUrl = QString(), const QString &author = QString(), const QString &description = QString(), const QString &version = QString(), const QString &itchGameId = QString(), + const QString &itchUrl = QString(), const QDateTime &uploadDate = QDateTime()); bool removeMod(const QString &modId); bool replaceMod(const QString &modId, const QString &newPakPath, diff --git a/src/core/managers/ProfileManager.cpp b/src/core/managers/ProfileManager.cpp index 8751251..0767ca9 100644 --- a/src/core/managers/ProfileManager.cpp +++ b/src/core/managers/ProfileManager.cpp @@ -813,7 +813,9 @@ bool ProfileManager::importProfile(const QString &filePath, QString &importedPro updated.description = meta.description; updated.nexusModId = meta.nexusModId; updated.nexusFileId = meta.nexusFileId; + updated.nexusUrl = meta.nexusUrl; updated.itchGameId = meta.itchGameId; + updated.itchUrl = meta.itchUrl; updated.version = meta.version; updated.author = meta.author; updated.uploadDate = meta.uploadDate; @@ -828,8 +830,10 @@ bool ProfileManager::importProfile(const QString &filePath, QString &importedPro const QList beforeMods = m_modManager->getMods(); if (!m_modManager->addMod(pakPath, QString(), meta.nexusModId, meta.nexusFileId, + meta.nexusUrl, meta.author, meta.description, meta.version, - meta.itchGameId, meta.uploadDate)) { + meta.itchGameId, meta.itchUrl, + meta.uploadDate)) { return false; } @@ -859,7 +863,9 @@ bool ProfileManager::importProfile(const QString &filePath, QString &importedPro updated.description = meta.description; updated.nexusModId = meta.nexusModId; updated.nexusFileId = meta.nexusFileId; + updated.nexusUrl = meta.nexusUrl; updated.itchGameId = meta.itchGameId; + updated.itchUrl = meta.itchUrl; updated.version = meta.version; updated.author = meta.author; updated.uploadDate = meta.uploadDate; @@ -886,8 +892,10 @@ bool ProfileManager::importProfile(const QString &filePath, QString &importedPro const QList beforeMods = m_modManager->getMods(); if (!m_modManager->addMod(pakPath, candidateName, meta.nexusModId, meta.nexusFileId, + meta.nexusUrl, meta.author, meta.description, meta.version, - meta.itchGameId, meta.uploadDate)) { + meta.itchGameId, meta.itchUrl, + meta.uploadDate)) { return false; } @@ -915,7 +923,9 @@ bool ProfileManager::importProfile(const QString &filePath, QString &importedPro updated.description = meta.description; updated.nexusModId = meta.nexusModId; updated.nexusFileId = meta.nexusFileId; + updated.nexusUrl = meta.nexusUrl; updated.itchGameId = meta.itchGameId; + updated.itchUrl = meta.itchUrl; updated.version = meta.version; updated.author = meta.author; updated.uploadDate = meta.uploadDate; diff --git a/src/core/models/ModInfo.cpp b/src/core/models/ModInfo.cpp index 41aaf0a..f4dd8a7 100644 --- a/src/core/models/ModInfo.cpp +++ b/src/core/models/ModInfo.cpp @@ -21,9 +21,15 @@ QJsonObject ModInfo::toJson() const { if (!nexusFileId.isEmpty()) { json["nexusFileId"] = nexusFileId; } + if (!nexusUrl.isEmpty()) { + json["nexusUrl"] = nexusUrl; + } if (!itchGameId.isEmpty()) { json["itchGameId"] = itchGameId; } + if (!itchUrl.isEmpty()) { + json["itchUrl"] = itchUrl; + } if (!version.isEmpty()) { json["version"] = version; } @@ -64,9 +70,15 @@ ModInfo ModInfo::fromJson(const QJsonObject &json) { if (json.contains("nexusFileId")) { mod.nexusFileId = json["nexusFileId"].toString(); } + if (json.contains("nexusUrl")) { + mod.nexusUrl = json["nexusUrl"].toString(); + } if (json.contains("itchGameId")) { mod.itchGameId = json["itchGameId"].toString(); } + if (json.contains("itchUrl")) { + mod.itchUrl = json["itchUrl"].toString(); + } if (json.contains("version")) { mod.version = json["version"].toString(); } diff --git a/src/core/models/ModInfo.h b/src/core/models/ModInfo.h index 250571d..74d12ea 100644 --- a/src/core/models/ModInfo.h +++ b/src/core/models/ModInfo.h @@ -17,7 +17,9 @@ struct ModInfo { int priority; // Load order (lower = loads first) QString nexusModId; // Optional Nexus Mod ID QString nexusFileId; // Optional Nexus File ID + QString nexusUrl; // Optional Nexus Mods URL QString itchGameId; // Optional itch.io Game ID + QString itchUrl; // Optional itch.io URL QString version; // Optional mod version QString author; // Optional mod author QString description; // Optional mod description diff --git a/src/modals/mod_manager/AddModModalContent.cpp b/src/modals/mod_manager/AddModModalContent.cpp index 076148b..b2ad5e5 100644 --- a/src/modals/mod_manager/AddModModalContent.cpp +++ b/src/modals/mod_manager/AddModModalContent.cpp @@ -130,7 +130,10 @@ bool AddModModalContent::isArchiveFile(const QString &filePath) const { } void AddModModalContent::handleArchiveFile(const QString &archivePath, const QString &nexusModId, const QString &nexusFileId, - const QString &author, const QString &description, const QString &version, const QString &itchGameId, const QDateTime &uploadDate, bool isBatchProcessing) { + const QString &nexusUrl, + const QString &author, const QString &description, const QString &version, + const QString &itchGameId, const QString &itchUrl, + const QDateTime &uploadDate, bool isBatchProcessing) { ArchiveExtractor extractor; auto result = extractor.extractPakFiles(archivePath); @@ -151,7 +154,8 @@ void AddModModalContent::handleArchiveFile(const QString &archivePath, const QSt selectedPaks.append(result.pakFiles.first()); for (const QString &pakPath : selectedPaks) { - handlePakFile(pakPath, nexusModId, nexusFileId, author, description, version, itchGameId, QString(), uploadDate); + handlePakFile(pakPath, nexusModId, nexusFileId, nexusUrl, author, description, version, itchGameId, + itchUrl, QString(), uploadDate); } ArchiveExtractor::cleanupTempDir(result.tempDir); @@ -166,7 +170,7 @@ void AddModModalContent::handleArchiveFile(const QString &archivePath, const QSt } auto *fileModal = new FileSelectionModalContent(fileNames, QFileInfo(archivePath).fileName(), true); - connect(fileModal, &FileSelectionModalContent::accepted, this, [this, result, fileModal, nexusModId, nexusFileId, author, description, version, itchGameId, uploadDate, isBatchProcessing]() { + connect(fileModal, &FileSelectionModalContent::accepted, this, [this, result, fileModal, nexusModId, nexusFileId, nexusUrl, author, description, version, itchGameId, itchUrl, uploadDate, isBatchProcessing]() { QStringList selectedFileNames = fileModal->getSelectedFiles(); QStringList selectedPaks; @@ -180,7 +184,8 @@ void AddModModalContent::handleArchiveFile(const QString &archivePath, const QSt } for (const QString &pakPath : selectedPaks) { - handlePakFile(pakPath, nexusModId, nexusFileId, author, description, version, itchGameId, QString(), uploadDate); + handlePakFile(pakPath, nexusModId, nexusFileId, nexusUrl, author, description, version, itchGameId, + itchUrl, QString(), uploadDate); } ArchiveExtractor::cleanupTempDir(result.tempDir); @@ -212,7 +217,10 @@ void AddModModalContent::handleArchiveFile(const QString &archivePath, const QSt } void AddModModalContent::handlePakFile(const QString &pakPath, const QString &nexusModId, const QString &nexusFileId, - const QString &author, const QString &description, const QString &version, const QString &itchGameId, const QString &customModName, const QDateTime &uploadDate) { + const QString &nexusUrl, + const QString &author, const QString &description, const QString &version, + const QString &itchGameId, const QString &itchUrl, + const QString &customModName, const QDateTime &uploadDate) { QString modName; if (!customModName.isEmpty()) { modName = customModName; @@ -221,7 +229,8 @@ void AddModModalContent::handlePakFile(const QString &pakPath, const QString &ne modName = fileInfo.baseName(); } - if (!m_modManager->addMod(pakPath, modName, nexusModId, nexusFileId, author, description, version, itchGameId, uploadDate)) { + if (!m_modManager->addMod(pakPath, modName, nexusModId, nexusFileId, nexusUrl, author, description, version, + itchGameId, itchUrl, uploadDate)) { MessageModal::warning(m_modalManager, tr("Error"), tr("Failed to add mod: %1").arg(modName)); } else { emit modAdded(modName); @@ -246,6 +255,7 @@ void AddModModalContent::onFromNexusClicked() { fileData.filePath = result.filePath; fileData.nexusModId = result.modId; fileData.nexusFileId = result.fileInfo.id; + fileData.nexusUrl = result.url; fileData.author = result.author; fileData.description = result.description; fileData.version = result.fileInfo.version; @@ -274,6 +284,7 @@ void AddModModalContent::onFromItchClicked() { FileToProcess fileData; fileData.filePath = result.filePath; fileData.itchGameId = result.gameId; + fileData.itchUrl = result.url; fileData.author = result.author; fileData.description = result.gameTitle; @@ -355,8 +366,9 @@ void AddModModalContent::processNextFile() { if (isArchiveFile(filePath)) { handleArchiveFile(filePath, fileData.nexusModId, fileData.nexusFileId, - fileData.author, fileData.description, fileData.version, - fileData.itchGameId, fileData.uploadDate, true); + fileData.nexusUrl, fileData.author, fileData.description, fileData.version, + fileData.itchGameId, fileData.itchUrl, + fileData.uploadDate, true); if (filePath.contains("nexus_mod_") || filePath.contains("itch_game_")) { QFile::remove(filePath); @@ -367,8 +379,9 @@ void AddModModalContent::processNextFile() { } } else { handlePakFile(filePath, fileData.nexusModId, fileData.nexusFileId, - fileData.author, fileData.description, fileData.version, - fileData.itchGameId, fileData.customModName, fileData.uploadDate); + fileData.nexusUrl, fileData.author, fileData.description, fileData.version, + fileData.itchGameId, fileData.itchUrl, + fileData.customModName, fileData.uploadDate); if (filePath.contains("nexus_mod_") || filePath.contains("itch_game_")) { QFile::remove(filePath); diff --git a/src/modals/mod_manager/AddModModalContent.h b/src/modals/mod_manager/AddModModalContent.h index 023775f..ee56d7a 100644 --- a/src/modals/mod_manager/AddModModalContent.h +++ b/src/modals/mod_manager/AddModModalContent.h @@ -47,10 +47,12 @@ private slots: QString filePath; QString nexusModId; QString nexusFileId; + QString nexusUrl; QString author; QString description; QString version; QString itchGameId; + QString itchUrl; QString customModName; QDateTime uploadDate; }; @@ -58,11 +60,15 @@ private slots: void setupUi(); void retranslateUi(); void handleArchiveFile(const QString &archivePath, const QString &nexusModId = QString(), const QString &nexusFileId = QString(), + const QString &nexusUrl = QString(), const QString &author = QString(), const QString &description = QString(), const QString &version = QString(), - const QString &itchGameId = QString(), const QDateTime &uploadDate = QDateTime(), bool isBatchProcessing = false); + const QString &itchGameId = QString(), const QString &itchUrl = QString(), + const QDateTime &uploadDate = QDateTime(), bool isBatchProcessing = false); void handlePakFile(const QString &pakPath, const QString &nexusModId = QString(), const QString &nexusFileId = QString(), + const QString &nexusUrl = QString(), const QString &author = QString(), const QString &description = QString(), const QString &version = QString(), - const QString &itchGameId = QString(), const QString &customModName = QString(), const QDateTime &uploadDate = QDateTime()); + const QString &itchGameId = QString(), const QString &itchUrl = QString(), + const QString &customModName = QString(), const QDateTime &uploadDate = QDateTime()); bool isArchiveFile(const QString &filePath) const; void startProcessingFiles(const QList &files); diff --git a/src/modals/mod_manager/ItchDownloadModalContent.cpp b/src/modals/mod_manager/ItchDownloadModalContent.cpp index 9f6408e..6af2d9e 100644 --- a/src/modals/mod_manager/ItchDownloadModalContent.cpp +++ b/src/modals/mod_manager/ItchDownloadModalContent.cpp @@ -191,7 +191,8 @@ void ItchDownloadModalContent::onDownloadClicked() { if (!result.isValid) { errors.append(QString("%1: %2").arg(url, result.error)); } else { - m_pendingGames.append({result.creator, result.gameName}); + QString canonicalUrl = QStringLiteral("https://%1.itch.io/%2").arg(result.creator, result.gameName); + m_pendingGames.append({result.creator, result.gameName, canonicalUrl}); } } @@ -489,6 +490,7 @@ void ItchDownloadModalContent::onDownloadFinished(const QString &savePath) { m_results.append({ savePath, m_currentGameId, + m_pendingGames[m_currentGameIndex].url, m_gameTitle, m_author, m_pendingUploads[m_currentDownloadIndex] diff --git a/src/modals/mod_manager/ItchDownloadModalContent.h b/src/modals/mod_manager/ItchDownloadModalContent.h index 34fae7d..fc11fae 100644 --- a/src/modals/mod_manager/ItchDownloadModalContent.h +++ b/src/modals/mod_manager/ItchDownloadModalContent.h @@ -21,6 +21,7 @@ class QStackedWidget; struct ItchDownloadResult { QString filePath; QString gameId; + QString url; QString gameTitle; QString author; ItchUploadInfo uploadInfo; @@ -63,6 +64,7 @@ private slots: struct PendingGame { QString creator; QString gameName; + QString url; }; void setupUi(); diff --git a/src/modals/mod_manager/ItchRegistrationModalContent.cpp b/src/modals/mod_manager/ItchRegistrationModalContent.cpp index fbcf757..6c72bb6 100644 --- a/src/modals/mod_manager/ItchRegistrationModalContent.cpp +++ b/src/modals/mod_manager/ItchRegistrationModalContent.cpp @@ -157,6 +157,7 @@ void ItchRegistrationModalContent::onFetchClicked() { return; } + m_url = QStringLiteral("https://%1.itch.io/%2").arg(result.creator, result.gameName); m_pendingUrl = url; if (!m_client->hasApiKey()) { @@ -179,6 +180,7 @@ void ItchRegistrationModalContent::onAuthenticateClicked() { m_authStatusLabel->setText(tr("API key saved. Fetching game information...")); auto result = ItchUrlParser::parseUrl(m_pendingUrl); + m_url = QStringLiteral("https://%1.itch.io/%2").arg(result.creator, result.gameName); QTimer::singleShot(500, this, [this, result]() { m_client->getGameId(result.creator, result.gameName); diff --git a/src/modals/mod_manager/ItchRegistrationModalContent.h b/src/modals/mod_manager/ItchRegistrationModalContent.h index 1984313..86b3c6b 100644 --- a/src/modals/mod_manager/ItchRegistrationModalContent.h +++ b/src/modals/mod_manager/ItchRegistrationModalContent.h @@ -29,6 +29,7 @@ class ItchRegistrationModalContent : public BaseModalContent { QList getSelectedUploads() const { return m_selectedUploads; } QString getGameId() const { return m_currentGameId; } QString getAuthor() const { return m_author; } + QString getUrl() const { return m_url; } private slots: void onFetchClicked(); @@ -67,6 +68,7 @@ private slots: QString m_currentGameId; QString m_author; + QString m_url; QString m_pendingUrl; enum Page { InputPage, AuthPage }; diff --git a/src/modals/mod_manager/ModMetadataModalContent.cpp b/src/modals/mod_manager/ModMetadataModalContent.cpp index 0920114..a6bf719 100644 --- a/src/modals/mod_manager/ModMetadataModalContent.cpp +++ b/src/modals/mod_manager/ModMetadataModalContent.cpp @@ -15,6 +15,7 @@ ModMetadataModalContent::ModMetadataModalContent(const ModInfo &mod, QWidget *pa , m_priority(mod.priority) , m_enabled(mod.enabled) , m_numberedFileName(mod.numberedFileName) + , m_itchUrl(mod.itchUrl) { setTitle(tr("Edit Mod Metadata")); setupUi(mod); @@ -58,11 +59,21 @@ void ModMetadataModalContent::setupUi(const ModInfo &mod) { m_nexusFileIdEdit->setPlaceholderText(tr("e.g., 12345")); formLayout->addRow(tr("Nexusmods File ID:"), m_nexusFileIdEdit); + m_nexusUrlEdit = new QLineEdit(mod.nexusUrl, scrollContent); + m_nexusUrlEdit->setMinimumHeight(32); + m_nexusUrlEdit->setPlaceholderText(tr("https://www.nexusmods.com/foxhole/mods/12345")); + formLayout->addRow(tr("Nexusmods URL:"), m_nexusUrlEdit); + m_itchGameIdEdit = new QLineEdit(mod.itchGameId, scrollContent); m_itchGameIdEdit->setMinimumHeight(32); m_itchGameIdEdit->setPlaceholderText(tr("e.g., 1276966")); formLayout->addRow(tr("Itch.io Game ID:"), m_itchGameIdEdit); + m_itchUrlEdit = new QLineEdit(mod.itchUrl, scrollContent); + m_itchUrlEdit->setMinimumHeight(32); + m_itchUrlEdit->setPlaceholderText(tr("https://creator.itch.io/game-name")); + formLayout->addRow(tr("Itch.io URL:"), m_itchUrlEdit); + m_versionEdit = new QLineEdit(mod.version, scrollContent); m_versionEdit->setMinimumHeight(32); m_versionEdit->setPlaceholderText(tr("e.g., 1.0.0")); @@ -106,7 +117,9 @@ ModInfo ModMetadataModalContent::getModInfo() const { mod.description = m_descriptionEdit->toPlainText(); mod.nexusModId = m_nexusModIdEdit->text(); mod.nexusFileId = m_nexusFileIdEdit->text(); + mod.nexusUrl = m_nexusUrlEdit ? m_nexusUrlEdit->text().trimmed() : mod.nexusUrl; mod.itchGameId = m_itchGameIdEdit->text(); + mod.itchUrl = m_itchUrlEdit ? m_itchUrlEdit->text().trimmed() : m_itchUrl; mod.version = m_versionEdit->text(); mod.author = m_authorEdit->text(); mod.installDate = m_installDateEdit->dateTime(); diff --git a/src/modals/mod_manager/ModMetadataModalContent.h b/src/modals/mod_manager/ModMetadataModalContent.h index 23473f6..e0fb1a8 100644 --- a/src/modals/mod_manager/ModMetadataModalContent.h +++ b/src/modals/mod_manager/ModMetadataModalContent.h @@ -25,7 +25,9 @@ class ModMetadataModalContent : public BaseModalContent { QTextEdit *m_descriptionEdit; QLineEdit *m_nexusModIdEdit; QLineEdit *m_nexusFileIdEdit; + QLineEdit *m_nexusUrlEdit; QLineEdit *m_itchGameIdEdit; + QLineEdit *m_itchUrlEdit; QLineEdit *m_versionEdit; QLineEdit *m_authorEdit; QDateTimeEdit *m_installDateEdit; @@ -34,6 +36,7 @@ class ModMetadataModalContent : public BaseModalContent { int m_priority; bool m_enabled; QString m_numberedFileName; + QString m_itchUrl; }; #endif // MODMETADATAMODALCONTENT_H diff --git a/src/modals/mod_manager/NexusDownloadModalContent.cpp b/src/modals/mod_manager/NexusDownloadModalContent.cpp index 6e76cd3..8893b42 100644 --- a/src/modals/mod_manager/NexusDownloadModalContent.cpp +++ b/src/modals/mod_manager/NexusDownloadModalContent.cpp @@ -182,7 +182,8 @@ void NexusDownloadModalContent::onDownloadClicked() { if (!result.isValid) { errors.append(QString("%1: %2").arg(url, result.error)); } else { - m_pendingMods.append({result.modId, result.fileId}); + QString canonicalUrl = QStringLiteral("https://www.nexusmods.com/foxhole/mods/%1").arg(result.modId); + m_pendingMods.append({result.modId, result.fileId, canonicalUrl}); } } @@ -425,6 +426,7 @@ void NexusDownloadModalContent::onDownloadFinished(const QString &savePath) { m_results.append({ savePath, m_currentModId, + m_pendingMods[m_currentModIndex].url, m_selectedFiles[m_currentDownloadIndex], m_author, m_description @@ -524,6 +526,7 @@ void NexusDownloadModalContent::startManualDownloadSequence() { m_results.append({ filePath, m_currentModId, + m_pendingMods[m_currentModIndex].url, file, m_author, m_description diff --git a/src/modals/mod_manager/NexusDownloadModalContent.h b/src/modals/mod_manager/NexusDownloadModalContent.h index a59711f..46ab0f5 100644 --- a/src/modals/mod_manager/NexusDownloadModalContent.h +++ b/src/modals/mod_manager/NexusDownloadModalContent.h @@ -19,6 +19,7 @@ class QStackedWidget; struct NexusDownloadResult { QString filePath; QString modId; + QString url; NexusFileInfo fileInfo; QString author; QString description; @@ -60,6 +61,7 @@ private slots: struct PendingMod { QString modId; QString fileId; + QString url; }; void setupUi(); diff --git a/src/modals/mod_manager/NexusRegistrationModalContent.cpp b/src/modals/mod_manager/NexusRegistrationModalContent.cpp index 7a5c450..2ab6334 100644 --- a/src/modals/mod_manager/NexusRegistrationModalContent.cpp +++ b/src/modals/mod_manager/NexusRegistrationModalContent.cpp @@ -149,6 +149,7 @@ void NexusRegistrationModalContent::onFetchClicked() { } m_currentModId = result.modId; + m_url = QStringLiteral("https://www.nexusmods.com/foxhole/mods/%1").arg(result.modId); if (!m_client->hasApiKey()) { showAuthPage(); diff --git a/src/modals/mod_manager/NexusRegistrationModalContent.h b/src/modals/mod_manager/NexusRegistrationModalContent.h index 36e9a70..43e529c 100644 --- a/src/modals/mod_manager/NexusRegistrationModalContent.h +++ b/src/modals/mod_manager/NexusRegistrationModalContent.h @@ -30,6 +30,7 @@ class NexusRegistrationModalContent : public BaseModalContent { QString getModId() const { return m_currentModId; } QString getAuthor() const { return m_author; } QString getDescription() const { return m_description; } + QString getUrl() const { return m_url; } private slots: void onFetchClicked(); @@ -68,6 +69,7 @@ private slots: QString m_currentModId; QString m_author; QString m_description; + QString m_url; enum Page { InputPage, AuthPage }; }; diff --git a/src/views/mod_manager/ModListWidget.cpp b/src/views/mod_manager/ModListWidget.cpp index 8f6c9a5..a9c4d0e 100644 --- a/src/views/mod_manager/ModListWidget.cpp +++ b/src/views/mod_manager/ModListWidget.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -723,6 +725,23 @@ bool ModListWidget::isFilterActive() const { return !m_filterText.isEmpty(); } +QUrl ModListWidget::buildNexusUrl(const ModInfo &mod) const { + if (!mod.nexusUrl.isEmpty()) { + return QUrl(mod.nexusUrl); + } + if (!mod.nexusModId.isEmpty()) { + return QUrl(QStringLiteral("https://www.nexusmods.com/foxhole/mods/%1").arg(mod.nexusModId)); + } + return {}; +} + +QUrl ModListWidget::buildItchUrl(const ModInfo &mod) const { + if (mod.itchUrl.isEmpty()) { + return {}; + } + return QUrl(mod.itchUrl); +} + void ModListWidget::showSelectionContextMenu(const QPoint &globalPos) { if (!m_modManager) { return; @@ -747,6 +766,19 @@ void ModListWidget::showSelectionContextMenu(const QPoint &globalPos) { QAction *removeSelected = nullptr; if (selectedCount == 1) { + ModInfo mod = m_modManager->getMod(singleModId); + QUrl nexusUrl = buildNexusUrl(mod); + QUrl itchUrl = buildItchUrl(mod); + + QAction *openNexus = nullptr; + QAction *openItch = nullptr; + + if (!nexusUrl.isEmpty()) { + openNexus = menu.addAction(tr("Open Nexus Mods Page")); + } + if (!itchUrl.isEmpty()) { + openItch = menu.addAction(tr("Open itch.io Page")); + } menu.addSeparator(); QAction *renameAction = menu.addAction(tr("Rename")); QAction *editMetaAction = menu.addAction(tr("Edit Metadata")); @@ -766,6 +798,10 @@ void ModListWidget::showSelectionContextMenu(const QPoint &globalPos) { startNexusRegistrationQueue(modIds); } else if (selectedAction == registerItch) { startItchRegistrationQueue(modIds); + } else if (selectedAction == openNexus && !nexusUrl.isEmpty()) { + QDesktopServices::openUrl(nexusUrl); + } else if (selectedAction == openItch && !itchUrl.isEmpty()) { + QDesktopServices::openUrl(itchUrl); } else if (selectedAction == renameAction) { onRenameRequested(singleModId); } else if (selectedAction == editMetaAction) { @@ -1273,7 +1309,7 @@ void ModListWidget::startNexusRegistrationQueue(const QStringList &modIds) { connect(modal, &NexusRegistrationModalContent::accepted, this, [this, modal, modId]() { applyNexusRegistration(modId, modal->getSelectedFiles(), modal->getModId(), modal->getAuthor(), - modal->getDescription()); + modal->getDescription(), modal->getUrl()); }); connect(modal, &BaseModalContent::finished, this, [index, showNext](int result) { @@ -1313,7 +1349,8 @@ void ModListWidget::startItchRegistrationQueue(const QStringList &modIds) { connect(modal, &ItchRegistrationModalContent::accepted, this, [this, modal, modId]() { applyItchRegistration(modId, modal->getSelectedUploads(), - modal->getGameId(), modal->getAuthor()); + modal->getGameId(), modal->getAuthor(), + modal->getUrl()); }); connect(modal, &BaseModalContent::finished, this, [index, showNext](int result) { @@ -1334,7 +1371,7 @@ void ModListWidget::startItchRegistrationQueue(const QStringList &modIds) { void ModListWidget::applyNexusRegistration(const QString &modId, const QList &files, const QString &nexusModId, const QString &author, - const QString &description) { + const QString &description, const QString &nexusUrl) { if (!m_modManager) { return; } @@ -1347,6 +1384,7 @@ void ModListWidget::applyNexusRegistration(const QString &modId, const QList &uploads, - const QString &itchGameId, const QString &author) { + const QString &itchGameId, const QString &author, + const QString &itchUrl) { if (!m_modManager) { return; } @@ -1371,6 +1410,7 @@ void ModListWidget::applyItchRegistration(const QString &modId, const QListgetSelectedFiles(), modal->getModId(), modal->getAuthor(), - modal->getDescription()); + modal->getDescription(), modal->getUrl()); }); m_modalManager->showModal(modal); @@ -1421,7 +1461,8 @@ void ModListWidget::onRegisterWithItchRequested(const QString &modId) { connect(modal, &ItchRegistrationModalContent::accepted, this, [this, modal, modId]() { applyItchRegistration(modId, modal->getSelectedUploads(), - modal->getGameId(), modal->getAuthor()); + modal->getGameId(), modal->getAuthor(), + modal->getUrl()); }); m_modalManager->showModal(modal); diff --git a/src/views/mod_manager/ModListWidget.h b/src/views/mod_manager/ModListWidget.h index 76c4737..98e5cf7 100644 --- a/src/views/mod_manager/ModListWidget.h +++ b/src/views/mod_manager/ModListWidget.h @@ -11,6 +11,7 @@ #include #include #include +#include class NexusModsClient; class NexusModsAuth; @@ -93,13 +94,16 @@ private slots: int getSelectedRow() const; int getSelectedCount() const; void showSelectionContextMenu(const QPoint &globalPos); + QUrl buildNexusUrl(const ModInfo &mod) const; + QUrl buildItchUrl(const ModInfo &mod) const; void startNexusRegistrationQueue(const QStringList &modIds); void startItchRegistrationQueue(const QStringList &modIds); void applyNexusRegistration(const QString &modId, const QList &files, const QString &nexusModId, const QString &author, - const QString &description); + const QString &description, const QString &nexusUrl); void applyItchRegistration(const QString &modId, const QList &uploads, - const QString &itchGameId, const QString &author); + const QString &itchGameId, const QString &author, + const QString &itchUrl); QString extractVersionFromFilename(const QString &filename) const; void handlePakFile(const QString &pakPath); void handleArchiveFile(const QString &archivePath);