diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 608f4cd388..f06b9cdbee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -20,6 +20,8 @@ #include #include +#include +#include #include #include #include @@ -184,6 +186,7 @@ static const QString JS_EXTENSION = ".js"; static const QString FST_EXTENSION = ".fst"; static const QString FBX_EXTENSION = ".fbx"; static const QString OBJ_EXTENSION = ".obj"; +static const QString AVA_JSON_EXTENSION = ".ava.json"; static const int MIRROR_VIEW_TOP_PADDING = 5; static const int MIRROR_VIEW_LEFT_PADDING = 10; @@ -219,7 +222,8 @@ const QHash Application::_acceptedExtensi { SVO_EXTENSION, &Application::importSVOFromURL }, { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, { JS_EXTENSION, &Application::askToLoadScript }, - { FST_EXTENSION, &Application::askToSetAvatarUrl } + { FST_EXTENSION, &Application::askToSetAvatarUrl }, + { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl } }; #ifdef Q_OS_WIN @@ -4457,6 +4461,99 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) } } +bool Application::askToWearAvatarAttachmentUrl(const QString& url) { + + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkRequest networkRequest = QNetworkRequest(url); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + QNetworkReply* reply = networkAccessManager.get(networkRequest); + int requestNumber = ++_avatarAttachmentRequest; + connect(reply, &QNetworkReply::finished, [this, reply, url, requestNumber]() { + + if (requestNumber != _avatarAttachmentRequest) { + // this request has been superseded by another more recent request + reply->deleteLater(); + return; + } + + QNetworkReply::NetworkError networkError = reply->error(); + if (networkError == QNetworkReply::NoError) { + // download success + QByteArray contents = reply->readAll(); + + QJsonParseError jsonError; + auto doc = QJsonDocument::fromJson(contents, &jsonError); + if (jsonError.error == QJsonParseError::NoError) { + + auto jsonObject = doc.object(); + + // retrieve optional name field from JSON + QString name = tr("Unnamed Attachment"); + auto nameValue = jsonObject.value("name"); + if (nameValue.isString()) { + name = nameValue.toString(); + } + + // display confirmation dialog + if (displayAvatarAttachmentConfirmationDialog(name)) { + + // add attachment to avatar + auto myAvatar = getMyAvatar(); + assert(myAvatar); + auto attachmentDataVec = myAvatar->getAttachmentData(); + AttachmentData attachmentData; + attachmentData.fromJson(jsonObject); + attachmentDataVec.push_back(attachmentData); + myAvatar->setAttachmentData(attachmentDataVec); + + } else { + qCDebug(interfaceapp) << "User declined to wear the avatar attachment: " << url; + } + + } else { + // json parse error + auto avatarAttachmentParseErrorString = tr("Error parsing attachment JSON from url: \"%1\""); + displayAvatarAttachmentWarning(avatarAttachmentParseErrorString.arg(url)); + } + } else { + // download failure + auto avatarAttachmentDownloadErrorString = tr("Error downloading attachment JSON from url: \"%1\""); + displayAvatarAttachmentWarning(avatarAttachmentDownloadErrorString.arg(url)); + } + reply->deleteLater(); + }); + return true; +} + +void Application::displayAvatarAttachmentWarning(const QString& message) const { + auto avatarAttachmentWarningTitle = tr("Avatar Attachment Failure"); + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Warning); + msgBox.setWindowTitle(avatarAttachmentWarningTitle); + msgBox.setText(message); + msgBox.exec(); + msgBox.addButton(QMessageBox::Ok); + msgBox.exec(); +} + +bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name) const { + auto avatarAttachmentConfirmationTitle = tr("Avatar Attachment Confirmation"); + auto avatarAttachmentConfirmationMessage = tr("Would you like to wear '%1' on your avatar?"); + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Question); + msgBox.setWindowTitle(avatarAttachmentConfirmationTitle); + QPushButton* button = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole); + QString message = avatarAttachmentConfirmationMessage.arg(name); + msgBox.setText(message); + msgBox.addButton(QMessageBox::Cancel); + msgBox.exec(); + if (msgBox.clickedButton() == button) { + return true; + } else { + return false; + } +} + ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor, bool activateMainWindow, bool reload) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 0953aedd8c..78b753880d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -340,7 +340,11 @@ private slots: bool askToLoadScript(const QString& scriptFilenameOrURL); bool askToUploadAsset(const QString& asset); void modelUploadFinished(AssetUpload* upload, const QString& hash); - + + bool askToWearAvatarAttachmentUrl(const QString& url); + void displayAvatarAttachmentWarning(const QString& message) const; + bool displayAvatarAttachmentConfirmationDialog(const QString& name) const; + void setSessionUUID(const QUuid& sessionUUID); void domainChanged(const QString& domainHostname); void updateWindowTitle(); @@ -550,6 +554,8 @@ private: bool _physicsEnabled { false }; bool _reticleClickPressed { false }; + + int _avatarAttachmentRequest = 0; }; #endif // hifi_Application_h