mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 01:24:03 +02:00
Merge branch 'feat/avatarTools/avatarPackager' of github.com:thoys/hifi into feat/avatarTools/avatarPackager
This commit is contained in:
commit
dab4a621a3
8 changed files with 339 additions and 203 deletions
|
@ -8,6 +8,7 @@ import "../stylesUit" 1.0
|
|||
import "../windows" as Windows
|
||||
import "../dialogs"
|
||||
import "avatarPackager"
|
||||
import "avatarapp" 1.0 as AvatarApp
|
||||
|
||||
Windows.ScrollingWindow {
|
||||
id: root
|
||||
|
@ -27,18 +28,14 @@ Windows.ScrollingWindow {
|
|||
id: windowContent
|
||||
height: pane.height
|
||||
width: pane.width
|
||||
anchors.fill: parent
|
||||
|
||||
// FIXME: modal overlay does not show
|
||||
Rectangle {
|
||||
id: modalOverlay
|
||||
AvatarApp.MessageBox {
|
||||
id: popup
|
||||
anchors.fill: parent
|
||||
z: 20000
|
||||
color: "#aa031b33"
|
||||
clip: true
|
||||
visible: true
|
||||
visible: false
|
||||
}
|
||||
|
||||
// FIXME: modal overlay does not show
|
||||
Column {
|
||||
id: avatarPackager
|
||||
anchors.fill: parent
|
||||
|
@ -61,6 +58,12 @@ Windows.ScrollingWindow {
|
|||
PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name }
|
||||
PropertyChanges { target: avatarProject; visible: true }
|
||||
PropertyChanges { target: avatarPackagerFooter; content: avatarProject.footer }
|
||||
},
|
||||
State {
|
||||
name: "project-upload"
|
||||
PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name }
|
||||
PropertyChanges { target: avatarUploader; visible: true }
|
||||
PropertyChanges { target: avatarPackagerFooter; color: "blue"; visible: false }
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -86,6 +89,12 @@ Windows.ScrollingWindow {
|
|||
anchors.fill: parent
|
||||
}
|
||||
|
||||
AvatarProjectUpload {
|
||||
id: avatarUploader
|
||||
anchors.fill: parent
|
||||
root: avatarProject
|
||||
}
|
||||
|
||||
CreateAvatarProject {
|
||||
id: createAvatarProject
|
||||
colorScheme: root.colorScheme
|
||||
|
|
|
@ -7,10 +7,10 @@ Rectangle {
|
|||
id: avatarPackagerFooter
|
||||
|
||||
color: "#404040"
|
||||
height: 74
|
||||
height: content === defaultContent ? 0 : 74
|
||||
width: parent.width
|
||||
|
||||
property var content: Item { }
|
||||
property var content: Item { id: defaultContent }
|
||||
|
||||
children: [background, content]
|
||||
|
||||
|
@ -21,4 +21,4 @@ Rectangle {
|
|||
border.width: 2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ Item {
|
|||
anchors.rightMargin: 17
|
||||
HifiControls.Button {
|
||||
id: uploadButton
|
||||
enabled: Account.loggedIn
|
||||
//width: parent.width
|
||||
//anchors.bottom: parent.bottom
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
@ -35,26 +36,82 @@ Item {
|
|||
width: 133
|
||||
height: 40
|
||||
onClicked: function() {
|
||||
console.log("Uploading");
|
||||
root.uploader = AvatarPackagerCore.currentAvatarProject.upload();
|
||||
console.log("uploader: "+ root.uploader);
|
||||
root.uploader.uploadProgress.connect(function(uploaded, total) {
|
||||
console.log("Uploader progress: " + uploaded + " / " + total);
|
||||
});
|
||||
root.uploader.completed.connect(function() {
|
||||
try {
|
||||
var response = JSON.parse(root.uploader.responseData);
|
||||
console.log("Uploader complete! " + response);
|
||||
uploadStatus.text = response.status;
|
||||
} catch (e) {
|
||||
console.log("Error parsing JSON: " + root.uploader.reponseData);
|
||||
}
|
||||
});
|
||||
root.uploader.send();
|
||||
if (AvatarPackagerCore.currentAvatarProject.fst.hasMarketplaceID()) {
|
||||
showConfirmUploadPopup(uploadNew, uploadUpdate);
|
||||
} else {
|
||||
uploadNew();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function uploadNew() {
|
||||
console.log("Uploading new");
|
||||
upload(false);
|
||||
}
|
||||
function uploadUpdate() {
|
||||
console.log("Uploading update");
|
||||
upload(true);
|
||||
}
|
||||
|
||||
function upload(updateExisting) {
|
||||
root.uploader = AvatarPackagerCore.currentAvatarProject.upload(updateExisting);
|
||||
console.log("uploader: "+ root.uploader);
|
||||
root.uploader.uploadProgress.connect(function(uploaded, total) {
|
||||
console.log("Uploader progress: " + uploaded + " / " + total);
|
||||
});
|
||||
root.uploader.completed.connect(function() {
|
||||
try {
|
||||
var response = JSON.parse(root.uploader.responseData);
|
||||
console.log("Uploader complete! " + response);
|
||||
uploadStatus.text = response.status;
|
||||
} catch (e) {
|
||||
console.log("Error parsing JSON: " + root.uploader.reponseData);
|
||||
}
|
||||
});
|
||||
root.uploader.send();
|
||||
avatarPackager.state = "project-upload";
|
||||
}
|
||||
|
||||
function showConfirmUploadPopup() {
|
||||
popup.titleText = 'Overwrite Avatar'
|
||||
popup.bodyText = 'You have previously uploaded the avatar file from this project.' +
|
||||
' This will overwrite that avatar and you won’t be able to access the older version.'
|
||||
|
||||
popup.button1text = 'CREATE NEW';
|
||||
popup.button2text = 'OVERWRITE';
|
||||
|
||||
popup.onButton2Clicked = function() {
|
||||
popup.close();
|
||||
uploadUpdate();
|
||||
}
|
||||
popup.onButton1Clicked = function() {
|
||||
popup.close();
|
||||
showConfirmCreateNewPopup();
|
||||
};
|
||||
|
||||
popup.open();
|
||||
//popup.forceActiveFocus();
|
||||
}
|
||||
|
||||
function showConfirmCreateNewPopup(confirmCallback) {
|
||||
popup.titleText = 'Create New'
|
||||
popup.bodyText = 'This will upload your current files with the same avatar name.' +
|
||||
' You will lose the ability to update the previously uploaded avatar. Are you sure you want to continue?'
|
||||
|
||||
popup.button1text = 'CANCEL';
|
||||
popup.button2text = 'CONFIRM';
|
||||
|
||||
popup.onButton1Clicked = function() { popup.close() };
|
||||
popup.onButton2Clicked = function() {
|
||||
popup.close();
|
||||
uploadNew();
|
||||
};
|
||||
|
||||
popup.open();
|
||||
//popup.forceActiveFocus();
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: avatarFBXNameLabel
|
||||
size: 14
|
||||
|
@ -79,11 +136,15 @@ Item {
|
|||
}
|
||||
|
||||
Rectangle {
|
||||
id: fileList
|
||||
|
||||
visible: false
|
||||
|
||||
color: "white"
|
||||
visible: AvatarPackagerCore.currentAvatarProject !== null
|
||||
anchors.top: openFolderButton.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: showFilesText.top
|
||||
//anchors.bottom: uploadButton.top
|
||||
anchors.topMargin: 10
|
||||
anchors.bottomMargin: 10
|
||||
|
@ -92,96 +153,82 @@ Item {
|
|||
ListView {
|
||||
anchors.fill: parent
|
||||
model: AvatarPackagerCore.currentAvatarProject === null ? [] : AvatarPackagerCore.currentAvatarProject.projectFiles
|
||||
delegate: Text { text: '<b>File:</b> ' + modelData }
|
||||
delegate: Rectangle {
|
||||
width: parent.width
|
||||
height: fileText.implicitHeight + 10
|
||||
color: (index % 2 == 0) ? "white" : "grey"
|
||||
Text {
|
||||
id: fileText
|
||||
anchors.top: parent.top + 5
|
||||
anchors.left: parent.left + 5
|
||||
text: modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: showFilesText
|
||||
|
||||
visible: AvatarPackagerCore.currentAvatarProject !== null
|
||||
|
||||
anchors.bottom: loginRequiredMessage.top
|
||||
anchors.bottomMargin: 10
|
||||
|
||||
font.pointSize: 12
|
||||
text: AvatarPackagerCore.currentAvatarProject.projectFiles.length + " files in the project. <a href='toggle'>" + (fileList.visible ? "Hide" : "Show") + " list</a>"
|
||||
|
||||
onLinkActivated: fileList.visible = !fileList.visible
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: uploadingScreen
|
||||
id: loginRequiredMessage
|
||||
|
||||
visible: !!root.uploader
|
||||
anchors.fill: parent
|
||||
visible: !Account.loggedIn
|
||||
height: loginRequiredTextRow.height + 20
|
||||
|
||||
color: "black"
|
||||
|
||||
Item {
|
||||
visible: !!root.uploader && !root.uploader.complete
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
AnimatedImage {
|
||||
id: uploadSpinner
|
||||
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
source: "../../../icons/loader-snake-64-w.gif"
|
||||
playing: true
|
||||
z: 10000
|
||||
}
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: !!root.uploader && root.uploader.complete
|
||||
color: "#FFD6AD"
|
||||
|
||||
border.color: "#F39622"
|
||||
border.width: 2
|
||||
radius: 2
|
||||
|
||||
Item {
|
||||
id: loginRequiredTextRow
|
||||
|
||||
height: Math.max(loginWarningGlyph.implicitHeight, loginWarningText.implicitHeight)
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
|
||||
HiFiGlyphs {
|
||||
id: successIcon
|
||||
id: loginWarningGlyph
|
||||
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
|
||||
size: 128
|
||||
text: "\ue01a"
|
||||
color: "#1FC6A6"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Congratulations!"
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: successIcon.bottom
|
||||
|
||||
color: "white"
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
font.pointSize: 20
|
||||
text: "+"
|
||||
color: "black"
|
||||
}
|
||||
Text {
|
||||
id: loginWarningText
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: loginWarningGlyph.right
|
||||
anchors.right: parent.right
|
||||
|
||||
text: "View in Inventory"
|
||||
|
||||
color: hifi.buttons.blue
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: function() {
|
||||
console.log("Opening in inventory");
|
||||
|
||||
AvatarPackagerCore.currentAvatarProject.openInInventory();
|
||||
}
|
||||
text: "Please login to upload your avatar to High Fidelity hosting."
|
||||
font.pointSize: 12
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
Text {
|
||||
id: uploadStatus
|
||||
|
||||
text: "Uploading"
|
||||
color: "white"
|
||||
|
||||
}
|
||||
Text {
|
||||
text: "State: " + (!!root.uploader ? root.uploader.state : " NONE")
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QQmlEngine>
|
||||
#include "FBXSerializer.h"
|
||||
#include <QTimer>
|
||||
|
||||
#include "FBXSerializer.h"
|
||||
#include <ui/TabletScriptingInterface.h>
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
|
||||
|
@ -57,20 +58,16 @@ AvatarProject* AvatarProject::createAvatarProject(const QString& avatarProjectNa
|
|||
|
||||
std::shared_ptr<hfm::Model> hfmModel;
|
||||
|
||||
|
||||
try {
|
||||
qDebug() << "Reading FBX file : " << fbxInfo.filePath();
|
||||
const QByteArray fbxContents = fbx.readAll();
|
||||
hfmModel = FBXSerializer().read(fbxContents, QVariantHash(), fbxInfo.filePath());
|
||||
}
|
||||
catch (const QString& error) {
|
||||
} catch (const QString& error) {
|
||||
qDebug() << "Error reading: " << error;
|
||||
return nullptr;
|
||||
}
|
||||
//TODO: copy/fix textures here:
|
||||
|
||||
|
||||
|
||||
FST* fst = FST::createFSTFromModel(newFSTPath, newModelPath, *hfmModel);
|
||||
|
||||
fst->setName(avatarProjectName);
|
||||
|
@ -89,7 +86,6 @@ bool AvatarProject::isValidNewProjectName(const QString& projectName) {
|
|||
|
||||
AvatarProject::AvatarProject(const QString& fstPath, const QByteArray& data) :
|
||||
AvatarProject::AvatarProject(new FST(fstPath, FSTReader::readMapping(data))) {
|
||||
|
||||
}
|
||||
AvatarProject::AvatarProject(FST* fst) {
|
||||
_fst = fst;
|
||||
|
@ -119,8 +115,22 @@ void AvatarProject::refreshProjectFiles() {
|
|||
appendDirectory("", _directory);
|
||||
}
|
||||
|
||||
MarketplaceItemUploader* AvatarProject::upload() {
|
||||
return new MarketplaceItemUploader("test_avatar", "blank description", QFileInfo(getFSTPath()).fileName(), QUuid(), _projectFiles);
|
||||
MarketplaceItemUploader* AvatarProject::upload(bool updateExisting) {
|
||||
QUuid itemID;
|
||||
if (updateExisting) {
|
||||
itemID = _fst->getMarketplaceID();
|
||||
}
|
||||
auto uploader = new MarketplaceItemUploader(getProjectName(), "Empty description", QFileInfo(getFSTPath()).fileName(), itemID,
|
||||
_projectFiles);
|
||||
connect(uploader, &MarketplaceItemUploader::completed, this, [this, uploader]() {
|
||||
if (uploader->getError() == MarketplaceItemUploader::Error::None) {
|
||||
_fst->setMarketplaceID(uploader->getMarketplaceID());
|
||||
// TODO(thoys) uncomment this
|
||||
//_fst->write();
|
||||
}
|
||||
});
|
||||
|
||||
return uploader;
|
||||
}
|
||||
|
||||
void AvatarProject::openInInventory() {
|
||||
|
@ -128,7 +138,12 @@ void AvatarProject::openInInventory() {
|
|||
DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system"));
|
||||
tablet->loadQMLSource("hifi/commerce/wallet/Wallet.qml");
|
||||
DependencyManager::get<HMDScriptingInterface>()->openTablet();
|
||||
tablet->sendToQml(QVariantMap({
|
||||
{ "method", "updatePurchases" },
|
||||
{ "filterText", "filtertext" } }));
|
||||
auto name = getProjectName();
|
||||
|
||||
// I'm not a fan of this, but it's the only current option.
|
||||
QTimer::singleShot(1000, [name]() {
|
||||
auto tablet = dynamic_cast<TabletProxy*>(
|
||||
DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system"));
|
||||
tablet->sendToQml(QVariantMap({ { "method", "updatePurchases" }, { "filterText", name } }));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
Q_INVOKABLE MarketplaceItemUploader* upload();
|
||||
Q_INVOKABLE MarketplaceItemUploader* upload(bool updateExisting);
|
||||
Q_INVOKABLE void openInInventory();
|
||||
|
||||
/**
|
||||
|
|
|
@ -67,10 +67,9 @@ void MarketplaceItemUploader::doGetCategories() {
|
|||
QNetworkReply* reply = networkAccessManager.get(request);
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
auto doc = QJsonDocument::fromJson(reply->readAll());
|
||||
|
||||
auto error = reply->error();
|
||||
if (error == QNetworkReply::NoError) {
|
||||
auto doc = QJsonDocument::fromJson(reply->readAll());
|
||||
auto extractCategoryID = [&doc]() -> std::pair<bool, int> {
|
||||
auto items = doc.object()["data"].toObject()["items"];
|
||||
if (!items.isArray()) {
|
||||
|
@ -119,116 +118,175 @@ void MarketplaceItemUploader::doGetCategories() {
|
|||
}
|
||||
|
||||
void MarketplaceItemUploader::doUploadAvatar() {
|
||||
QBuffer buffer{ &_fileData };
|
||||
//buffer.open(QIODevice::WriteOnly);
|
||||
QuaZip zip{ &buffer };
|
||||
if (!zip.open(QuaZip::Mode::mdAdd)) {
|
||||
qWarning() << "Failed to open zip!!";
|
||||
QBuffer buffer{ &_fileData };
|
||||
//buffer.open(QIODevice::WriteOnly);
|
||||
QuaZip zip{ &buffer };
|
||||
if (!zip.open(QuaZip::Mode::mdAdd)) {
|
||||
qWarning() << "Failed to open zip!!";
|
||||
}
|
||||
|
||||
for (auto& filePath : _filePaths) {
|
||||
qWarning() << "Zipping: " << filePath;
|
||||
QFileInfo fileInfo{ filePath };
|
||||
|
||||
QuaZipFile zipFile{ &zip };
|
||||
if (!zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileInfo.fileName()))) {
|
||||
qWarning() << "Could not open zip file:" << zipFile.getZipError();
|
||||
_error = Error::Unknown;
|
||||
setState(State::Complete);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& filePath : _filePaths) {
|
||||
qWarning() << "Zipping: " << filePath;
|
||||
QFileInfo fileInfo{ filePath };
|
||||
|
||||
QuaZipFile zipFile{ &zip };
|
||||
if (!zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileInfo.fileName()))) {
|
||||
qWarning() << "Could not open zip file:" << zipFile.getZipError();
|
||||
_error = Error::Unknown;
|
||||
setState(State::Complete);
|
||||
return;
|
||||
}
|
||||
QFile file{ filePath };
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
zipFile.write(file.readAll());
|
||||
} else {
|
||||
qWarning() << "Failed to open: " << filePath;
|
||||
}
|
||||
file.close();
|
||||
zipFile.close();
|
||||
if (zipFile.getZipError() != UNZ_OK) {
|
||||
qWarning() << "Could not close zip file: " << zipFile.getZipError();
|
||||
setState(State::Complete);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
zip.close();
|
||||
|
||||
qDebug() << "Finished zipping, size: " << (buffer.size() / (1000.0f)) << "KB";
|
||||
|
||||
QString path = "/api/v1/marketplace/items";
|
||||
bool creating = true;
|
||||
if (!_marketplaceID.isNull()) {
|
||||
creating = false;
|
||||
auto idWithBraces = _marketplaceID.toString();
|
||||
auto idWithoutBraces = idWithBraces.mid(1, idWithBraces.length() - 2);
|
||||
path += "/" + idWithoutBraces;
|
||||
}
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
auto request = accountManager->createRequest(path, AccountManagerAuth::Required);
|
||||
qWarning() << "Request url is: " << request.url();
|
||||
|
||||
QJsonObject root{ { "marketplace_item",
|
||||
QJsonObject{ { "title", _title },
|
||||
{ "description", _description },
|
||||
{ "root_file_key", _rootFilename },
|
||||
{ "category_ids", QJsonArray({ 5 }) },
|
||||
//{ "attributions", QJsonArray({ QJsonObject{ { "name", "" }, { "link", "" } } }) },
|
||||
{ "license", 0 },
|
||||
{ "files", QString::fromLatin1(_fileData.toBase64()) } } } };
|
||||
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||
QJsonDocument doc{ root };
|
||||
|
||||
qWarning() << "data: " << doc.toJson();
|
||||
|
||||
_fileData.toBase64();
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QNetworkReply* reply{ nullptr };
|
||||
if (creating) {
|
||||
reply = networkAccessManager.post(request, doc.toJson());
|
||||
QFile file{ filePath };
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
zipFile.write(file.readAll());
|
||||
} else {
|
||||
reply = networkAccessManager.put(request, doc.toJson());
|
||||
qWarning() << "Failed to open: " << filePath;
|
||||
}
|
||||
file.close();
|
||||
zipFile.close();
|
||||
if (zipFile.getZipError() != UNZ_OK) {
|
||||
qWarning() << "Could not close zip file: " << zipFile.getZipError();
|
||||
setState(State::Complete);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
connect(reply, &QNetworkReply::uploadProgress, this, &MarketplaceItemUploader::uploadProgress);
|
||||
zip.close();
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
qDebug() << "Finished zipping, size: " << (buffer.size() / (1000.0f)) << "KB";
|
||||
|
||||
QString path = "/api/v1/marketplace/items";
|
||||
bool creating = true;
|
||||
if (!_marketplaceID.isNull()) {
|
||||
creating = false;
|
||||
auto idWithBraces = _marketplaceID.toString();
|
||||
auto idWithoutBraces = idWithBraces.mid(1, idWithBraces.length() - 2);
|
||||
path += "/" + idWithoutBraces;
|
||||
}
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
auto request = accountManager->createRequest(path, AccountManagerAuth::Required);
|
||||
qWarning() << "Request url is: " << request.url();
|
||||
|
||||
QJsonObject root{ { "marketplace_item",
|
||||
QJsonObject{ { "title", _title },
|
||||
{ "description", _description },
|
||||
{ "root_file_key", _rootFilename },
|
||||
{ "category_ids", QJsonArray({ 5 }) },
|
||||
//{ "attributions", QJsonArray({ QJsonObject{ { "name", "" }, { "link", "" } } }) },
|
||||
{ "license", 0 },
|
||||
{ "files", QString::fromLatin1(_fileData.toBase64()) } } } };
|
||||
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||
QJsonDocument doc{ root };
|
||||
|
||||
qWarning() << "data: " << doc.toJson();
|
||||
|
||||
_fileData.toBase64();
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QNetworkReply* reply{ nullptr };
|
||||
if (creating) {
|
||||
reply = networkAccessManager.post(request, doc.toJson());
|
||||
} else {
|
||||
reply = networkAccessManager.put(request, doc.toJson());
|
||||
}
|
||||
|
||||
connect(reply, &QNetworkReply::uploadProgress, this, &MarketplaceItemUploader::uploadProgress);
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
//_responseData = reply->readAll();
|
||||
auto error = reply->error();
|
||||
if (error == QNetworkReply::NoError) {
|
||||
_responseData = reply->readAll();
|
||||
qWarning() << "Finished request " << _responseData;
|
||||
auto error = reply->error();
|
||||
if (error == QNetworkReply::NoError) {
|
||||
|
||||
auto doc = QJsonDocument::fromJson(_responseData.toLatin1());
|
||||
auto status = doc.object()["status"].toString();
|
||||
if (status == "success") {
|
||||
_marketplaceID = QUuid::fromString(doc["data"].toObject()["marketplace_id"].toString());
|
||||
_itemVersion = doc["data"].toObject()["version"].toDouble();
|
||||
doWaitForInventory();
|
||||
} else {
|
||||
_error = Error::Unknown;
|
||||
setState(State::Complete);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
_error = Error::Unknown;
|
||||
setState(State::Complete);
|
||||
}
|
||||
});
|
||||
|
||||
setState(State::UploadingAvatar);
|
||||
setState(State::UploadingAvatar);
|
||||
}
|
||||
|
||||
void MarketplaceItemUploader::doWaitForInventory() {
|
||||
static const QString path = "/api/v1/commerce/inventory";
|
||||
static const QString path = "/api/v1/commerce/inventory";
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
auto request = accountManager->createRequest(path, AccountManagerAuth::Required);
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
auto request = accountManager->createRequest(path, AccountManagerAuth::Required);
|
||||
|
||||
qWarning() << "Request url is: " << request.url();
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply* reply = networkAccessManager.post(request, "");
|
||||
|
||||
QNetworkReply* reply = networkAccessManager.post(request, "");
|
||||
_numRequestsForInventory++;
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
auto data = reply->readAll();
|
||||
qWarning() << "Finished inventory request " << data;
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
auto data = reply->readAll();
|
||||
|
||||
auto error = reply->error();
|
||||
if (error == QNetworkReply::NoError) {
|
||||
} else {
|
||||
_error = Error::Unknown;
|
||||
}
|
||||
bool success = false;
|
||||
|
||||
auto error = reply->error();
|
||||
if (error == QNetworkReply::NoError) {
|
||||
// Parse response data
|
||||
auto doc = QJsonDocument::fromJson(data);
|
||||
auto isAssetAvailable = [this, &doc]() -> bool {
|
||||
if (!doc.isObject()) {
|
||||
return false;
|
||||
}
|
||||
auto root = doc.object();
|
||||
auto status = root["status"].toString();
|
||||
if (status != "success") {
|
||||
return false;
|
||||
}
|
||||
auto data = root["data"];
|
||||
if (!data.isObject()) {
|
||||
return false;
|
||||
}
|
||||
auto assets = data.toObject()["assets"];
|
||||
if (!assets.isArray()) {
|
||||
return false;
|
||||
}
|
||||
for (auto asset : assets.toArray()) {
|
||||
auto assetObject = asset.toObject();
|
||||
auto id = QUuid::fromString(assetObject["id"].toString());
|
||||
if (id.isNull()) {
|
||||
continue;
|
||||
}
|
||||
if (id == _marketplaceID) {
|
||||
auto version = assetObject["version"];
|
||||
if (version.isDouble()) {
|
||||
int versionInt = version.toDouble();
|
||||
if (versionInt >= _itemVersion) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
success = isAssetAvailable();
|
||||
}
|
||||
if (success) {
|
||||
setState(State::Complete);
|
||||
});
|
||||
} else {
|
||||
qDebug() << "Failed to find item in inventory";
|
||||
if (_numRequestsForInventory > 8) {
|
||||
_error = Error::Unknown;
|
||||
setState(State::Complete);
|
||||
} else {
|
||||
QTimer::singleShot(5000, [this]() { doWaitForInventory(); });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -56,6 +56,8 @@ public:
|
|||
State getState() const { return _state; }
|
||||
bool getComplete() const { return _state == State::Complete; }
|
||||
|
||||
QUuid getMarketplaceID() const { return _marketplaceID; }
|
||||
|
||||
Error getError() const { return _error; }
|
||||
|
||||
signals:
|
||||
|
@ -77,9 +79,12 @@ private:
|
|||
QString _description;
|
||||
QString _rootFilename;
|
||||
QUuid _marketplaceID;
|
||||
int _itemVersion;
|
||||
|
||||
QString _responseData;
|
||||
|
||||
int _numRequestsForInventory{ 0 };
|
||||
|
||||
QStringList _filePaths;
|
||||
QByteArray _fileData;
|
||||
};
|
||||
|
|
|
@ -37,7 +37,9 @@ public:
|
|||
QString getModelPath() const { return _modelPath; }
|
||||
void setModelPath(const QString& modelPath);
|
||||
|
||||
Q_INVOKABLE bool hasMarketplaceID() const { return !_marketplaceID.isNull(); }
|
||||
QUuid getMarketplaceID() const { return _marketplaceID; }
|
||||
void setMarketplaceID(QUuid marketplaceID) { _marketplaceID = marketplaceID; }
|
||||
|
||||
QString getPath() { return _fstPath; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue