diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index ce724d73685..db149073e7c 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -42,7 +42,7 @@ const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client"; const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000; AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, - quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, + quint16 listenPort, QString assignmentServerHostname, quint16 assignmentServerPort, quint16 assignmentMonitorPort) : _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME) { @@ -68,13 +68,6 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri // setup our _requestAssignment member variable from the passed arguments _requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool); - // check for a wallet UUID on the command line or in the config - // this would represent where the user running AC wants funds sent to - if (!walletUUID.isNull()) { - qCDebug(assignment_client) << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID); - _requestAssignment.setWalletUUID(walletUUID); - } - // check for an overriden assignment server hostname if (assignmentServerHostname != "") { // change the hostname for our assignment server diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 28464bc222c..8f7ea6494cb 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -24,7 +24,7 @@ class AssignmentClient : public QObject { public: AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, - QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort, + QString assignmentServerHostname, quint16 assignmentServerPort, quint16 assignmentMonitorPort); ~AssignmentClient(); diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index c5b228bd16f..d8e12c5d215 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -69,10 +69,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : "Minimum UDP listen port", "port"); parser.addOption(minChildListenPort); - const QCommandLineOption walletDestinationOption(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION, - "set wallet destination", "wallet-uuid"); - parser.addOption(walletDestinationOption); - const QCommandLineOption assignmentServerHostnameOption(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION, "set assignment-server hostname", "hostname"); parser.addOption(assignmentServerHostnameOption); @@ -174,16 +170,8 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : assignmentPool = parser.value(poolOption); } - QUuid walletUUID; - if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) { - walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString(); - } - if (parser.isSet(walletDestinationOption)) { - walletUUID = parser.value(walletDestinationOption); - } - QString assignmentServerHostname; - if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) { + if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) { assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString(); } if (parser.isSet(assignmentServerHostnameOption)) { @@ -192,7 +180,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : // check for an overriden assignment server port quint16 assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT; - if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) { + if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) { assignmentServerPort = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toUInt(); } @@ -249,13 +237,13 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : if (numForks || minForks || maxForks) { AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, listenPort, - childMinListenPort, walletUUID, assignmentServerHostname, + childMinListenPort, assignmentServerHostname, assignmentServerPort, httpStatusPort, logDirectory); monitor->setParent(this); connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit); } else { AssignmentClient* client = new AssignmentClient(requestAssignmentType, assignmentPool, listenPort, - walletUUID, assignmentServerHostname, + assignmentServerHostname, assignmentServerPort, monitorPort); client->setParent(this); connect(this, &QCoreApplication::aboutToQuit, client, &AssignmentClient::aboutToQuit); diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index 1b509229800..7689108badf 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -18,7 +18,6 @@ const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t"; const QString ASSIGNMENT_POOL_OPTION = "pool"; const QString ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION = "p"; -const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet"; const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a"; const QString ASSIGNMENT_MONITOR_MIN_CHILDREN_LISTEN_PORT_OPTION = "min-listen-port"; const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "server-port"; diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 4c7f71a7aa3..25705533539 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -40,7 +40,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, - quint16 listenPort, quint16 childMinListenPort, QUuid walletUUID, QString assignmentServerHostname, + quint16 listenPort, quint16 childMinListenPort, QString assignmentServerHostname, quint16 assignmentServerPort, quint16 httpStatusServerPort, QString logDirectory) : _httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this), _numAssignmentClientForks(numAssignmentClientForks), @@ -48,7 +48,6 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen _maxAssignmentClientForks(maxAssignmentClientForks), _requestAssignmentType(requestAssignmentType), _assignmentPool(assignmentPool), - _walletUUID(walletUUID), _assignmentServerHostname(assignmentServerHostname), _assignmentServerPort(assignmentServerPort), _childMinListenPort(childMinListenPort) @@ -181,10 +180,6 @@ void AssignmentClientMonitor::spawnChildClient() { _childArguments.append("--" + ASSIGNMENT_POOL_OPTION); _childArguments.append(_assignmentPool); } - if (!_walletUUID.isNull()) { - _childArguments.append("--" + ASSIGNMENT_WALLET_DESTINATION_ID_OPTION); - _childArguments.append(_walletUUID.toString()); - } if (_assignmentServerHostname != "") { _childArguments.append("--" + CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION); _childArguments.append(_assignmentServerHostname); diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index f5355476b7e..06f1e1e6a48 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -37,7 +37,7 @@ class AssignmentClientMonitor : public QObject, public HTTPRequestHandler { public: AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, - QString assignmentPool, quint16 listenPort, quint16 childMinListenPort, QUuid walletUUID, + QString assignmentPool, quint16 listenPort, quint16 childMinListenPort, QString assignmentServerHostname, quint16 assignmentServerPort, quint16 httpStatusServerPort, QString logDirectory); ~AssignmentClientMonitor(); @@ -70,7 +70,6 @@ public slots: Assignment::Type _requestAssignmentType; QString _assignmentPool; - QUuid _walletUUID; QString _assignmentServerHostname; quint16 _assignmentServerPort; diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 807f54953e0..a2c0dd09809 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -83,7 +83,6 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::BulkAvatarTraitsAck, this, "queueIncomingPacket"); packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); - packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "queueIncomingPacket"); packetReceiver.registerListenerForTypes({ PacketType::ReplicatedAvatarIdentity, @@ -499,8 +498,6 @@ void AvatarMixer::handleAvatarKilled(SharedNodePointer avatarNode) { } else { _sessionDisplayNames.erase(displayNameIter); } - - nodeData->getAvatar().stopChallengeTimer(); } std::unique_ptr killPacket; diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index f86dc7f766d..4aceb89b3f2 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -73,9 +73,6 @@ int AvatarMixerClientData::processPackets(const SlaveSharedData& slaveSharedData case PacketType::BulkAvatarTraitsAck: processBulkAvatarTraitsAckMessage(*packet); break; - case PacketType::ChallengeOwnership: - _avatar->processChallengeResponse(*packet); - break; default: Q_UNREACHABLE(); } @@ -83,10 +80,6 @@ int AvatarMixerClientData::processPackets(const SlaveSharedData& slaveSharedData } assert(_packetQueue.empty()); - if (_avatar) { - _avatar->processCertifyEvents(); - } - return packetsProcessed; } @@ -230,8 +223,6 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message, if (traitType == AvatarTraits::SkeletonModelURL) { // special handling for skeleton model URL, since we need to make sure it is in the whitelist checkSkeletonURLAgainstWhitelist(slaveSharedData, sendingNode, packetTraitVersion); - // Deferred for UX work. With no PoP check, no need to get the .fst. - _avatar->fetchAvatarFST(); } anyTraitsChanged = true; diff --git a/assignment-client/src/avatars/MixerAvatar.cpp b/assignment-client/src/avatars/MixerAvatar.cpp index f3d7bb89959..741e33de389 100644 --- a/assignment-client/src/avatars/MixerAvatar.cpp +++ b/assignment-client/src/avatars/MixerAvatar.cpp @@ -10,409 +10,3 @@ // #include "MixerAvatar.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "ClientTraitsHandler.h" -#include "AvatarLogging.h" - -MixerAvatar::MixerAvatar() { - static constexpr int CHALLENGE_TIMEOUT_MS = 10 * 1000; // 10 s - - _challengeTimer.setSingleShot(true); - _challengeTimer.setInterval(CHALLENGE_TIMEOUT_MS); - _challengeTimer.callOnTimeout(this, &MixerAvatar::challengeTimeout); - // QTimer::start is a set of overloaded functions. - connect(this, &MixerAvatar::startChallengeTimer, &_challengeTimer, static_cast(&QTimer::start)); -} - -const char* MixerAvatar::stateToName(VerifyState state) { - return QMetaEnum::fromType().valueToKey(state); -} - -void MixerAvatar::challengeTimeout() { - switch (_verifyState) { - case challengeClient: - _verifyState = staticValidation; - _pendingEvent = true; - if (++_numberChallenges < NUM_CHALLENGES_BEFORE_FAIL) { - qCDebug(avatars) << "Retrying (" << _numberChallenges << ") timed-out challenge for" << getDisplayName() - << getSessionUUID(); - } else { - _certifyFailed = true; - _needsIdentityUpdate = true; - qCWarning(avatars) << "ALERT: Dynamic verification TIMED-OUT for" << getDisplayName() << getSessionUUID(); - } - break; - - case verificationFailed: - qCDebug(avatars) << "Retrying failed challenge for" << getDisplayName() << getSessionUUID(); - _verifyState = staticValidation; - _pendingEvent = true; - break; - - default: - qCDebug(avatars) << "Ignoring timeout of avatar challenge"; - break; - } -} - -void MixerAvatar::fetchAvatarFST() { - if (_verifyState >= requestingFST && _verifyState <= challengeClient) { - qCDebug(avatars) << "WARNING: Avatar verification restarted; old state:" << stateToName(_verifyState); - } - _verifyState = nonCertified; - - _pendingEvent = false; - - QUrl avatarURL = _skeletonModelURL; - if (avatarURL.isEmpty() || avatarURL.isLocalFile() || avatarURL.scheme() == "qrc") { - // Not network FST. - return; - } - _certificateIdFromURL.clear(); - _certificateIdFromFST.clear(); - _marketplaceIdFromURL.clear(); - _marketplaceIdFromFST.clear(); - auto resourceManager = DependencyManager::get(); - - // Match UUID + (optionally) URL cert - static const QRegularExpression marketIdRegex{ - "^https://.*?highfidelity\\.com/api/.*?/commerce/entity_edition/([-0-9a-z]{36})(.*?certificate_id=([\\w/+%]+)|.*).*$" - }; - auto marketIdMatch = marketIdRegex.match(avatarURL.toDisplayString()); - if (marketIdMatch.hasMatch()) { - QMutexLocker certifyLocker(&_avatarCertifyLock); - _marketplaceIdFromURL = marketIdMatch.captured(1); - if (marketIdMatch.lastCapturedIndex() == 3) { - _certificateIdFromURL = QUrl::fromPercentEncoding(marketIdMatch.captured(3).toUtf8()); - } - } - - ResourceRequest* fstRequest = resourceManager->createResourceRequest(this, avatarURL); - if (fstRequest) { - QMutexLocker certifyLocker(&_avatarCertifyLock); - - _avatarRequest = fstRequest; - _verifyState = requestingFST; - connect(fstRequest, &ResourceRequest::finished, this, &MixerAvatar::fstRequestComplete); - fstRequest->send(); - } else { - qCDebug(avatars) << "Couldn't create FST request for" << avatarURL << getSessionUUID(); - _verifyState = error; - } - _needsIdentityUpdate = true; -} - -void MixerAvatar::fstRequestComplete() { - ResourceRequest* fstRequest = static_cast(QObject::sender()); - QMutexLocker certifyLocker(&_avatarCertifyLock); - if (_verifyState == requestingFST && fstRequest == _avatarRequest) { - auto result = fstRequest->getResult(); - if (result != ResourceRequest::Success) { - _verifyState = error; - qCDebug(avatars) << "FST request for" << fstRequest->getUrl() << "(user " << getSessionUUID() << ") failed:" << result; - } else { - _avatarFSTContents = fstRequest->getData(); - _verifyState = receivedFST; - _pendingEvent = true; - } - _avatarRequest = nullptr; - } else { - qCDebug(avatars) << "Incorrect or outdated FST request for" << getDisplayName(); - } - fstRequest->deleteLater(); -} - -bool MixerAvatar::generateFSTHash() { - if (_avatarFSTContents.length() == 0) { - return false; - } - QByteArray hashJson = canonicalJson(_avatarFSTContents); - QCryptographicHash fstHash(QCryptographicHash::Sha256); - fstHash.addData(hashJson); - _certificateHash = fstHash.result(); - return true; -} - -bool MixerAvatar::validateFSTHash(const QString& publicKey) const { - // Guess we should refactor this stuff into a Authorization namespace ... - return EntityItemProperties::verifySignature(publicKey, _certificateHash, - QByteArray::fromBase64(_certificateIdFromFST.toUtf8())); -} - -QByteArray MixerAvatar::canonicalJson(const QString fstFile) { - QStringList fstLines = fstFile.split("\n", QString::SkipEmptyParts); - static const QString fstKeywordsReg { - "(marketplaceID|itemDescription|itemCategories|itemArtist|itemLicenseUrl|limitedRun|itemName|" - "filename|texdir|script|editionNumber|certificateID)" - }; - QRegularExpression fstLineRegExp { QString("^\\s*") + fstKeywordsReg + "\\s*=\\s*(\\S.*)$" }; - QStringListIterator fstLineIter(fstLines); - - QJsonObject certifiedItems; - QStringList scripts; - while (fstLineIter.hasNext()) { - auto line = fstLineIter.next(); - auto lineMatch = fstLineRegExp.match(line); - if (lineMatch.hasMatch()) { - QString key = lineMatch.captured(1); - if (key == "certificateID") { - _certificateIdFromFST = lineMatch.captured(2); - } else if (key == "itemDescription") { - // Item description can be multiline - intermediate lines end in - QString itemDesc = lineMatch.captured(2); - while (itemDesc.endsWith('\r') && fstLineIter.hasNext()) { - itemDesc += '\n' + fstLineIter.next(); - } - certifiedItems[key] = QJsonValue(itemDesc); - } else if (key == "limitedRun" || key == "editionNumber") { - double value = lineMatch.captured(2).toDouble(); - if (value != 0.0) { - certifiedItems[key] = QJsonValue(value); - } - } else if (key == "script") { - scripts.append(lineMatch.captured(2).trimmed()); - } else { - certifiedItems[key] = QJsonValue(lineMatch.captured(2)); - if (key == "marketplaceID") { - _marketplaceIdFromFST = lineMatch.captured(2); - } - } - } - } - if (!scripts.empty()) { - scripts.sort(); - certifiedItems["script"] = QJsonArray::fromStringList(scripts); - } - - QJsonDocument jsonDocCertifiedItems(certifiedItems); - //Example working form: - //return R"({"editionNumber":34,"filename":"http://mpassets.highfidelity.com/7f142fde-541a-4902-b33a-25fa89dfba21-v1/Bridger/Hifi_Toon_Male_3.fbx","itemArtist":"EgyMax", - //"itemCategories":"Avatars","itemDescription":"This is my first avatar. I hope you like it. More will come","itemName":"Bridger","limitedRun":-1, - //"marketplaceID":"7f142fde-541a-4902-b33a-25fa89dfba21","texdir":"http://mpassets.highfidelity.com/7f142fde-541a-4902-b33a-25fa89dfba21-v1/Bridger/textures"})"; - return jsonDocCertifiedItems.toJson(QJsonDocument::Compact); -} - -void MixerAvatar::ownerRequestComplete() { - QMutexLocker certifyLocker(&_avatarCertifyLock); - QNetworkReply* networkReply = static_cast(QObject::sender()); - - if (_verifyState != requestingOwner) { - qCDebug(avatars) << "WARNING: outdated avatar-owner information received in state" << stateToName(_verifyState); - } else if (networkReply->error() == QNetworkReply::NoError) { - _dynamicMarketResponse = networkReply->readAll(); - _verifyState = ownerResponse; - _pendingEvent = true; - } else { - auto jsonData = QJsonDocument::fromJson(networkReply->readAll())["data"]; - if (!jsonData.isUndefined() && !jsonData.toObject()["message"].isUndefined()) { - qCDebug(avatars) << "Owner lookup failed for" << getDisplayName() << "(" - << getSessionUUID() << ") :" - << jsonData.toObject()["message"].toString(); - _verifyState = error; - _pendingEvent = false; - } - } - networkReply->deleteLater(); -} - -void MixerAvatar::requestCurrentOwnership() { - // Get registered owner's public key from metaverse. - static const QString POP_MARKETPLACE_API { "/api/v1/commerce/proof_of_purchase_status/transfer" }; - auto& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest; - networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - QUrl requestURL = MetaverseAPI::getCurrentMetaverseServerURL(); - requestURL.setPath(POP_MARKETPLACE_API); - networkRequest.setUrl(requestURL); - - QJsonObject request; - request["certificate_id"] = _certificateIdFromFST; - QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); - connect(networkReply, &QNetworkReply::finished, this, &MixerAvatar::ownerRequestComplete); -} - -void MixerAvatar::processCertifyEvents() { - if (!_pendingEvent) { - return; - } - - QMutexLocker certifyLocker(&_avatarCertifyLock); - switch (_verifyState) { - - case receivedFST: - { - generateFSTHash(); - _numberChallenges = 0; - if (_certificateIdFromFST.length() != 0) { - QString& marketplacePublicKey = EntityItem::_marketplacePublicKey; - bool staticVerification = validateFSTHash(marketplacePublicKey); - _verifyState = staticVerification ? staticValidation : verificationFailed; - - if (_verifyState == staticValidation) { - requestCurrentOwnership(); - _verifyState = requestingOwner; - } else { - _needsIdentityUpdate = true; - _pendingEvent = false; - qCDebug(avatars) << "Avatar" << getDisplayName() << "(" << getSessionUUID() << ") FAILED static certification"; - } - } else { // FST doesn't have a certificate, so noncertified rather than failed: - _pendingEvent = false; - _certifyFailed = false; - _needsIdentityUpdate = true; - _verifyState = nonCertified; - qCDebug(avatars) << "Avatar " << getDisplayName() << "(" << getSessionUUID() << ") isn't certified"; - } - break; - } - - case staticValidation: - { - requestCurrentOwnership(); - _verifyState = requestingOwner; - break; - } - - case ownerResponse: - { - QJsonDocument responseJson = QJsonDocument::fromJson(_dynamicMarketResponse.toUtf8()); - QString ownerPublicKey; - bool ownerValid = false; - _pendingEvent = false; - if (responseJson["status"].toString() == "success") { - QJsonValue jsonData = responseJson["data"]; - if (jsonData.isObject()) { - auto ownerJson = jsonData["transfer_recipient_key"]; - if (ownerJson.isString()) { - ownerPublicKey = ownerJson.toString(); - } - auto transferStatusJson = jsonData["transfer_status"]; - if (transferStatusJson.isArray() && transferStatusJson.toArray()[0].toString() == "confirmed") { - ownerValid = true; - } - } - if (ownerValid && !ownerPublicKey.isEmpty()) { - if (ownerPublicKey.startsWith("-----BEGIN ")){ - _ownerPublicKey = ownerPublicKey; - } else { - _ownerPublicKey = "-----BEGIN PUBLIC KEY-----\n" - + ownerPublicKey - + "\n-----END PUBLIC KEY-----\n"; - } - sendOwnerChallenge(); - _verifyState = challengeClient; - } else { - _verifyState = error; - qCDebug(avatars) << "Get owner status - couldn't parse response for" << getSessionUUID() - << ":" << _dynamicMarketResponse; - } - } else { - qCDebug(avatars) << "Get owner status failed for" << getDisplayName() << _marketplaceIdFromURL << - "message:" << responseJson["message"].toString(); - _verifyState = error; - } - break; - } - - case requestingOwner: - { // Qt networking done on this thread: - QCoreApplication::processEvents(); - break; - } - - default: - qCDebug(avatars) << "Unexpected verify state" << stateToName(_verifyState); - break; - - } // close switch -} - -void MixerAvatar::sendOwnerChallenge() { - auto nodeList = DependencyManager::get(); - QByteArray avatarID = ("{" + _marketplaceIdFromFST + "}").toUtf8(); - if (_challengeNonce.isEmpty()) { - _challengeNonce = QUuid::createUuid().toByteArray(); - QCryptographicHash nonceHash(QCryptographicHash::Sha256); - nonceHash.addData(_challengeNonce); - _challengeNonceHash = nonceHash.result(); - - } - - auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnership, - 2 * sizeof(int) + _challengeNonce.length() + avatarID.length(), true); - challengeOwnershipPacket->writePrimitive(avatarID.length()); - challengeOwnershipPacket->writePrimitive(_challengeNonce.length()); - challengeOwnershipPacket->write(avatarID); - challengeOwnershipPacket->write(_challengeNonce); - - nodeList->sendPacket(std::move(challengeOwnershipPacket), *(nodeList->nodeWithUUID(getSessionUUID())) ); - QCryptographicHash nonceHash(QCryptographicHash::Sha256); - nonceHash.addData(_challengeNonce); - _challengeNonceHash = nonceHash.result(); - _pendingEvent = false; - - emit startChallengeTimer(); -} - -void MixerAvatar::processChallengeResponse(ReceivedMessage& response) { - QByteArray avatarID; - QMutexLocker certifyLocker(&_avatarCertifyLock); - stopChallengeTimer(); - if (_verifyState == challengeClient) { - QByteArray responseData = response.readAll(); - if (responseData.length() < 8) { - _verifyState = error; - qCWarning(avatars) << "ALERT: Avatar challenge response packet too small, length:" << responseData.length(); - return; - } - - int avatarIDLength; - int signedNonceLength; - { - QDataStream responseStream(responseData); - responseStream.setByteOrder(QDataStream::LittleEndian); - responseStream >> avatarIDLength >> signedNonceLength; - } - QByteArray avatarID(responseData.data() + 2 * sizeof(int), avatarIDLength); - QByteArray signedNonce(responseData.data() + 2 * sizeof(int) + avatarIDLength, signedNonceLength); - - bool challengeResult = EntityItemProperties::verifySignature(_ownerPublicKey, _challengeNonceHash, - QByteArray::fromBase64(signedNonce)); - _verifyState = challengeResult ? verificationSucceeded : verificationFailed; - _certifyFailed = !challengeResult; - _needsIdentityUpdate = true; - if (_certifyFailed) { - qCDebug(avatars) << "Dynamic verification FAILED for" << getDisplayName() << getSessionUUID(); - emit startChallengeTimer(); - } else { - qCDebug(avatars) << "Dynamic verification SUCCEEDED for" << getDisplayName() << getSessionUUID(); - _challengeNonce.clear(); - } - - } else { - qCDebug(avatars) << "WARNING: Unexpected avatar challenge-response in state" << stateToName(_verifyState); - } -} - -void MixerAvatar::stopChallengeTimer() { - if (QThread::currentThread() == thread()) { - _challengeTimer.stop(); - } else { - QMetaObject::invokeMethod(&_challengeTimer, &QTimer::stop); - } -} diff --git a/assignment-client/src/avatars/MixerAvatar.h b/assignment-client/src/avatars/MixerAvatar.h index 09a35220672..7b19c53132b 100644 --- a/assignment-client/src/avatars/MixerAvatar.h +++ b/assignment-client/src/avatars/MixerAvatar.h @@ -21,28 +21,14 @@ class ResourceRequest; class MixerAvatar : public AvatarData { Q_OBJECT public: - MixerAvatar(); + inline MixerAvatar() {} bool getNeedsHeroCheck() const { return _needsHeroCheck; } void setNeedsHeroCheck(bool needsHeroCheck = true) { _needsHeroCheck = needsHeroCheck; } - void fetchAvatarFST(); - virtual bool isCertifyFailed() const override { return _certifyFailed; } bool needsIdentityUpdate() const { return _needsIdentityUpdate; } void setNeedsIdentityUpdate(bool value = true) { _needsIdentityUpdate = value; } - void processCertifyEvents(); - void processChallengeResponse(ReceivedMessage& response); - - void stopChallengeTimer(); - - // Avatar certification/verification: - enum VerifyState { - nonCertified, requestingFST, receivedFST, staticValidation, requestingOwner, ownerResponse, - challengeClient, verified, verificationFailed, verificationSucceeded, error - }; - Q_ENUM(VerifyState) - bool isInScreenshareZone() const { return _inScreenshareZone; } void setInScreenshareZone(bool value = true) { _inScreenshareZone = value; } const QUuid& getScreenshareZone() const { return _screenshareZone; } @@ -50,44 +36,9 @@ class MixerAvatar : public AvatarData { private: bool _needsHeroCheck { false }; - static const char* stateToName(VerifyState state); - VerifyState _verifyState { nonCertified }; - std::atomic _pendingEvent { false }; - QMutex _avatarCertifyLock; - ResourceRequest* _avatarRequest { nullptr }; - QString _marketplaceIdFromURL; - QString _marketplaceIdFromFST; - QByteArray _avatarFSTContents; - QByteArray _certificateHash; - QString _certificateIdFromURL; - QString _certificateIdFromFST; - QString _dynamicMarketResponse; - QString _ownerPublicKey; - QByteArray _challengeNonce; - QByteArray _challengeNonceHash; - QTimer _challengeTimer; - static constexpr int NUM_CHALLENGES_BEFORE_FAIL = 1; - int _numberChallenges { 0 }; - bool _certifyFailed { false }; bool _needsIdentityUpdate { false }; bool _inScreenshareZone { false }; QUuid _screenshareZone; - - bool generateFSTHash(); - bool validateFSTHash(const QString& publicKey) const; - QByteArray canonicalJson(const QString fstFile); - void requestCurrentOwnership(); - void sendOwnerChallenge(); - - static const QString VERIFY_FAIL_MODEL; - -private slots: - void fstRequestComplete(); - void ownerRequestComplete(); - void challengeTimeout(); - - signals: - void startChallengeTimer(); }; using MixerAvatarSharedPointer = std::shared_ptr; diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 4c4fcbf2dd5..b46bd8d7f39 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -37,8 +37,7 @@ const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo"; EntityServer::EntityServer(ReceivedMessage& message) : OctreeServer(message), - _entitySimulation(nullptr), - _dynamicDomainVerificationTimer(this) + _entitySimulation(nullptr) { DependencyManager::set(); DependencyManager::set(); @@ -55,15 +54,9 @@ EntityServer::EntityServer(ReceivedMessage& message) : PacketType::EntityClone, PacketType::EntityEdit, PacketType::EntityErase, - PacketType::EntityPhysics, - PacketType::ChallengeOwnership, - PacketType::ChallengeOwnershipRequest, - PacketType::ChallengeOwnershipReply }, + PacketType::EntityPhysics }, this, "handleEntityPacket"); - - connect(&_dynamicDomainVerificationTimer, &QTimer::timeout, this, &EntityServer::startDynamicDomainVerification); - _dynamicDomainVerificationTimer.setSingleShot(true); } EntityServer::~EntityServer() { @@ -325,18 +318,6 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio tree->setEntityMaxTmpLifetime(EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME); } - int minTime; - if (readOptionInt("dynamicDomainVerificationTimeMin", settingsSectionObject, minTime)) { - _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = minTime * 1000; - } - - int maxTime; - if (readOptionInt("dynamicDomainVerificationTimeMax", settingsSectionObject, maxTime)) { - _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = maxTime * 1000; - } - - startDynamicDomainVerification(); - tree->setWantEditLogging(wantEditLogging); tree->setWantTerseEditLogging(wantTerseEditLogging); @@ -463,20 +444,5 @@ QString EntityServer::serverSubclassStats() { void EntityServer::domainSettingsRequestFailed() { auto nodeList = DependencyManager::get(); - qCDebug(entities) << "The EntityServer couldn't get the Domain Settings. Starting dynamic domain verification with default values..."; - - _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = DEFAULT_MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS; - _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = DEFAULT_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS; - startDynamicDomainVerification(); -} - -void EntityServer::startDynamicDomainVerification() { - qCDebug(entities) << "Starting Dynamic Domain Verification..."; - - EntityTreePointer tree = std::static_pointer_cast(_tree); - tree->startDynamicDomainVerificationOnServer((float) _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS / MSECS_PER_SECOND); - - int nextInterval = qrand() % ((_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS + 1) - _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS) + _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS; - qCDebug(entities) << "Restarting Dynamic Domain Verification timer for" << nextInterval / 1000 << "seconds"; - _dynamicDomainVerificationTimer.start(nextInterval); + qCDebug(entities) << "The EntityServer couldn't get the Domain Settings."; } diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 9bb3a237e06..7bba04c0338 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -79,13 +79,6 @@ private slots: QReadWriteLock _viewerSendingStatsLock; QMap> _viewerSendingStats; - - static const int DEFAULT_MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = 45 * 60 * 1000; // 45m - static const int DEFAULT_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = 60 * 60 * 1000; // 1h - int _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = DEFAULT_MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS; // 45m - int _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = DEFAULT_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS; // 1h - QTimer _dynamicDomainVerificationTimer; - void startDynamicDomainVerification(); }; #endif // hifi_EntityServer_h diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index ef532bb33fc..197cfa9829f 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -93,19 +93,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer // Ask our tree subclass if it can handle the incoming packet... PacketType packetType = message->getType(); - if (packetType == PacketType::ChallengeOwnership) { - _myServer->getOctree()->withWriteLock([&] { - _myServer->getOctree()->processChallengeOwnershipPacket(*message, sendingNode); - }); - } else if (packetType == PacketType::ChallengeOwnershipRequest) { - _myServer->getOctree()->withWriteLock([&] { - _myServer->getOctree()->processChallengeOwnershipRequestPacket(*message, sendingNode); - }); - } else if (packetType == PacketType::ChallengeOwnershipReply) { - _myServer->getOctree()->withWriteLock([&] { - _myServer->getOctree()->processChallengeOwnershipReplyPacket(*message, sendingNode); - }); - } else if (_myServer->getOctree()->handlesEditPacketType(packetType)) { + if (_myServer->getOctree()->handlesEditPacketType(packetType)) { PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket); _receivedPacketCount++; diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 7c3d4914702..9b6abaef958 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -105,7 +105,7 @@ EntityScriptServer::~EntityScriptServer() { static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server"; void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode) { - if (senderNode->getCanRez() || senderNode->getCanRezTmp() || senderNode->getCanRezCertified() || senderNode->getCanRezTmpCertified()) { + if (senderNode->getCanRez() || senderNode->getCanRezTmp()) { auto entityID = QUuid::fromRfc4122(message->read(NUM_BYTES_RFC4122_UUID)); if (_entityViewer.getTree() && !_shuttingDown) { @@ -116,7 +116,7 @@ void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode) { - if (senderNode->getCanRez() || senderNode->getCanRezTmp() || senderNode->getCanRezCertified() || senderNode->getCanRezTmpCertified()) { + if (senderNode->getCanRez() || senderNode->getCanRezTmp()) { MessageID messageID; message->readPrimitive(&messageID); auto entityID = QUuid::fromRfc4122(message->read(NUM_BYTES_RFC4122_UUID)); @@ -184,7 +184,7 @@ void EntityScriptServer::updateEntityPPS() { } void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { - bool canRezAny = senderNode->getCanRez() || senderNode->getCanRezTmp() || senderNode->getCanRezCertified() || senderNode->getCanRezTmpCertified(); + bool canRezAny = senderNode->getCanRez() || senderNode->getCanRezTmp(); bool enable = false; message->readPrimitive(&enable); diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 7c8783bb828..7ca4040660d 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -338,7 +338,7 @@ "name": "standard_permissions", "type": "table", "label": "Domain-Wide User Permissions", - "help": "Indicate which types of users can have which domain-wide permissions.", + "help": "Indicate which types of users can have which domain-wide permissions.", "caption": "Standard Permissions", "can_add_new_rows": false, "groups": [ @@ -347,7 +347,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -384,20 +384,6 @@ "editable": true, "default": false }, - { - "name": "id_can_rez_certified", - "label": "Rez Certified", - "type": "checkbox", - "editable": true, - "default": false - }, - { - "name": "id_can_rez_tmp_certified", - "label": "Rez Temporary Certified", - "type": "checkbox", - "editable": true, - "default": false - }, { "name": "id_can_write_to_asset_server", "label": "Write Assets", @@ -439,12 +425,10 @@ "default": [ { "id_can_connect": true, - "id_can_rez_tmp_certified": true, "permissions_id": "anonymous" }, { "id_can_connect": true, - "id_can_rez_tmp_certified": true, "permissions_id": "friends" }, { @@ -454,16 +438,13 @@ "id_can_kick": true, "id_can_replace_content": true, "id_can_rez": true, - "id_can_rez_certified": true, "id_can_rez_tmp": true, - "id_can_rez_tmp_certified": true, "id_can_write_to_asset_server": true, "id_can_get_and_set_private_user_data": true, "permissions_id": "localhost" }, { "id_can_connect": true, - "id_can_rez_tmp_certified": true, "permissions_id": "logged-in" } ] @@ -484,7 +465,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -546,20 +527,6 @@ "editable": true, "default": false }, - { - "name": "id_can_rez_certified", - "label": "Rez Certified", - "type": "checkbox", - "editable": true, - "default": false - }, - { - "name": "id_can_rez_tmp_certified", - "label": "Rez Temporary Certified", - "type": "checkbox", - "editable": true, - "default": false - }, { "name": "id_can_write_to_asset_server", "label": "Write Assets", @@ -613,7 +580,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -672,20 +639,6 @@ "editable": true, "default": false }, - { - "name": "id_can_rez_certified", - "label": "Rez Certified", - "type": "checkbox", - "editable": true, - "default": false - }, - { - "name": "id_can_rez_tmp_certified", - "label": "Rez Temporary Certified", - "type": "checkbox", - "editable": true, - "default": false - }, { "name": "id_can_write_to_asset_server", "label": "Write Assets", @@ -734,7 +687,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -771,20 +724,6 @@ "editable": true, "default": false }, - { - "name": "id_can_rez_certified", - "label": "Rez Certified", - "type": "checkbox", - "editable": true, - "default": false - }, - { - "name": "id_can_rez_tmp_certified", - "label": "Rez Temporary Certified", - "type": "checkbox", - "editable": true, - "default": false - }, { "name": "id_can_write_to_asset_server", "label": "Write Assets", @@ -833,7 +772,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -870,20 +809,6 @@ "editable": true, "default": false }, - { - "name": "id_can_rez_certified", - "label": "Rez Certified", - "type": "checkbox", - "editable": true, - "default": false - }, - { - "name": "id_can_rez_tmp_certified", - "label": "Rez Temporary Certified", - "type": "checkbox", - "editable": true, - "default": false - }, { "name": "id_can_write_to_asset_server", "label": "Write Assets", @@ -932,7 +857,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -969,20 +894,6 @@ "editable": true, "default": false }, - { - "name": "id_can_rez_certified", - "label": "Rez Certified", - "type": "checkbox", - "editable": true, - "default": false - }, - { - "name": "id_can_rez_tmp_certified", - "label": "Rez Temporary Certified", - "type": "checkbox", - "editable": true, - "default": false - }, { "name": "id_can_write_to_asset_server", "label": "Write Assets", @@ -1031,7 +942,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -1068,20 +979,6 @@ "editable": true, "default": false }, - { - "name": "id_can_rez_certified", - "label": "Rez Certified", - "type": "checkbox", - "editable": true, - "default": false - }, - { - "name": "id_can_rez_tmp_certified", - "label": "Rez Temporary Certified", - "type": "checkbox", - "editable": true, - "default": false - }, { "name": "id_can_write_to_asset_server", "label": "Write Assets", diff --git a/domain-server/resources/web/wizard/js/wizard.js b/domain-server/resources/web/wizard/js/wizard.js index efd3b281169..83a753a15f6 100644 --- a/domain-server/resources/web/wizard/js/wizard.js +++ b/domain-server/resources/web/wizard/js/wizard.js @@ -416,25 +416,19 @@ function savePermissions() { { "id_can_connect": anonymousCanConnect, "id_can_rez": anonymousCanRez, - "id_can_rez_certified": anonymousCanRez, "id_can_rez_tmp": anonymousCanRez, - "id_can_rez_tmp_certified": anonymousCanRez, "permissions_id": "anonymous" }, { "id_can_connect": friendsCanConnect, "id_can_rez": friendsCanRez, - "id_can_rez_certified": friendsCanRez, "id_can_rez_tmp": friendsCanRez, - "id_can_rez_tmp_certified": friendsCanRez, "permissions_id": "friends" }, { "id_can_connect": loggedInCanConnect, "id_can_rez": loggedInCanRez, - "id_can_rez_certified": loggedInCanRez, "id_can_rez_tmp": loggedInCanRez, - "id_can_rez_tmp_certified": loggedInCanRez, "permissions_id": "logged-in" }, { @@ -444,9 +438,7 @@ function savePermissions() { "id_can_kick": localhostPermissions, "id_can_replace_content": localhostPermissions, "id_can_rez": localhostPermissions, - "id_can_rez_certified": localhostPermissions, "id_can_rez_tmp": localhostPermissions, - "id_can_rez_tmp_certified": localhostPermissions, "id_can_write_to_asset_server": localhostPermissions, "permissions_id": "localhost" } diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index ead4002334a..be1342ecb27 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -33,11 +33,10 @@ DomainGatekeeper::DomainGatekeeper(DomainServer* server) : initLocalIDManagement(); } -void DomainGatekeeper::addPendingAssignedNode(const QUuid& nodeUUID, const QUuid& assignmentUUID, - const QUuid& walletUUID, const QString& nodeVersion) { +void DomainGatekeeper::addPendingAssignedNode(const QUuid& nodeUUID, const QUuid& assignmentUUID, const QString& nodeVersion) { _pendingAssignedNodes.emplace(std::piecewise_construct, std::forward_as_tuple(nodeUUID), - std::forward_as_tuple(assignmentUUID, walletUUID, nodeVersion)); + std::forward_as_tuple(assignmentUUID, nodeVersion)); } QUuid DomainGatekeeper::assignmentUUIDForPendingAssignment(const QUuid& tempUUID) { @@ -347,8 +346,6 @@ void DomainGatekeeper::updateNodePermissions() { userPerms.permissions |= NodePermissions::Permission::canAdjustLocks; userPerms.permissions |= NodePermissions::Permission::canRezPermanentEntities; userPerms.permissions |= NodePermissions::Permission::canRezTemporaryEntities; - userPerms.permissions |= NodePermissions::Permission::canRezPermanentCertifiedEntities; - userPerms.permissions |= NodePermissions::Permission::canRezTemporaryCertifiedEntities; userPerms.permissions |= NodePermissions::Permission::canWriteToAssetServer; userPerms.permissions |= NodePermissions::Permission::canReplaceDomainContent; userPerms.permissions |= NodePermissions::Permission::canGetAndSetPrivateUserData; @@ -424,7 +421,6 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo // set assignment related data on the linked data for this node nodeData->setAssignmentUUID(matchingQueuedAssignment->getUUID()); - nodeData->setWalletUUID(it->second.getWalletUUID()); nodeData->setNodeVersion(it->second.getNodeVersion()); nodeData->setHardwareAddress(nodeConnection.hardwareAddress); nodeData->setMachineFingerprint(nodeConnection.machineFingerprint); @@ -442,8 +438,6 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo userPerms.permissions |= NodePermissions::Permission::canAdjustLocks; userPerms.permissions |= NodePermissions::Permission::canRezPermanentEntities; userPerms.permissions |= NodePermissions::Permission::canRezTemporaryEntities; - userPerms.permissions |= NodePermissions::Permission::canRezPermanentCertifiedEntities; - userPerms.permissions |= NodePermissions::Permission::canRezTemporaryCertifiedEntities; userPerms.permissions |= NodePermissions::Permission::canWriteToAssetServer; userPerms.permissions |= NodePermissions::Permission::canReplaceDomainContent; userPerms.permissions |= NodePermissions::Permission::canGetAndSetPrivateUserData; diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index cb42baa7e39..a83e9ec2881 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -39,8 +39,7 @@ class DomainGatekeeper : public QObject { public: DomainGatekeeper(DomainServer* server); - void addPendingAssignedNode(const QUuid& nodeUUID, const QUuid& assignmentUUID, - const QUuid& walletUUID, const QString& nodeVersion); + void addPendingAssignedNode(const QUuid& nodeUUID, const QUuid& assignmentUUID, const QString& nodeVersion); QUuid assignmentUUIDForPendingAssignment(const QUuid& tempUUID); void cleanupICEPeerForNode(const QUuid& nodeID); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ec0a8ff45d3..8f7f371b0a7 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1368,8 +1368,7 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointergetUUID(), - requestAssignment.getWalletUUID(), requestAssignment.getNodeVersion()); + _gatekeeper.addPendingAssignedNode(uniqueAssignment.getUUID(), assignmentToDeploy->getUUID(), requestAssignment.getNodeVersion()); } else { static bool printedAssignmentRequestMessage = false; if (!printedAssignmentRequestMessage && requestAssignment.getType() != Assignment::AgentType) { @@ -1380,99 +1379,6 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointer()->eachNode([&](const SharedNodePointer& node){ - DomainServerNodeData* nodeData = static_cast(node->getLinkedData()); - - if (!nodeData->getAssignmentUUID().isNull() && !nodeData->getWalletUUID().isNull()) { - // check if we have a non-finalized transaction for this node to add this amount to - TransactionHash::iterator i = _pendingAssignmentCredits.find(nodeData->getWalletUUID()); - WalletTransaction* existingTransaction = NULL; - - while (i != _pendingAssignmentCredits.end() && i.key() == nodeData->getWalletUUID()) { - if (!i.value()->isFinalized()) { - existingTransaction = i.value(); - break; - } else { - ++i; - } - } - - qint64 elapsedMsecsSinceLastPayment = nodeData->getPaymentIntervalTimer().elapsed(); - nodeData->getPaymentIntervalTimer().restart(); - - const float CREDITS_PER_HOUR = 0.10f; - const float CREDITS_PER_MSEC = CREDITS_PER_HOUR / (60 * 60 * 1000); - const int SATOSHIS_PER_MSEC = CREDITS_PER_MSEC * SATOSHIS_PER_CREDIT; - - float pendingCredits = elapsedMsecsSinceLastPayment * SATOSHIS_PER_MSEC; - - if (existingTransaction) { - existingTransaction->incrementAmount(pendingCredits); - } else { - // create a fresh transaction to pay this node, there is no transaction to append to - WalletTransaction* freshTransaction = new WalletTransaction(nodeData->getWalletUUID(), pendingCredits); - _pendingAssignmentCredits.insert(nodeData->getWalletUUID(), freshTransaction); - } - } - }); -} - -void DomainServer::sendPendingTransactionsToServer() { - - auto accountManager = DependencyManager::get(); - - if (accountManager->hasValidAccessToken()) { - - // enumerate the pending transactions and send them to the server to complete payment - TransactionHash::iterator i = _pendingAssignmentCredits.begin(); - - JSONCallbackParameters transactionCallbackParams; - - transactionCallbackParams.callbackReceiver = this; - transactionCallbackParams.jsonCallbackMethod = "transactionJSONCallback"; - - while (i != _pendingAssignmentCredits.end()) { - accountManager->sendRequest("api/v1/transactions", - AccountManagerAuth::Required, - QNetworkAccessManager::PostOperation, - transactionCallbackParams, i.value()->postJson().toJson()); - - // set this transaction to finalized so we don't add additional credits to it - i.value()->setIsFinalized(true); - - ++i; - } - } -} - -void DomainServer::transactionJSONCallback(const QJsonObject& data) { - // check if this was successful - if so we can remove it from our list of pending - if (data.value("status").toString() == "success") { - // create a dummy wallet transaction to unpack the JSON to - WalletTransaction dummyTransaction; - dummyTransaction.loadFromJson(data); - - TransactionHash::iterator i = _pendingAssignmentCredits.find(dummyTransaction.getDestinationUUID()); - - while (i != _pendingAssignmentCredits.end() && i.key() == dummyTransaction.getDestinationUUID()) { - if (i.value()->getUUID() == dummyTransaction.getUUID()) { - // we have a match - we can remove this from the hash of pending credits - // and delete it for clean up - - WalletTransaction* matchingTransaction = i.value(); - _pendingAssignmentCredits.erase(i); - delete matchingTransaction; - - break; - } else { - ++i; - } - } - } -} - QJsonObject jsonForDomainSocketUpdate(const HifiSockAddr& socket) { const QString SOCKET_NETWORK_ADDRESS_KEY = "network_address"; const QString SOCKET_PORT_KEY = "port"; @@ -1929,18 +1835,6 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { SharedAssignmentPointer matchingAssignment = _allAssignments.value(nodeData->getAssignmentUUID()); if (matchingAssignment) { nodeJson[JSON_KEY_POOL] = matchingAssignment->getPool(); - - if (!nodeData->getWalletUUID().isNull()) { - TransactionHash::iterator i = _pendingAssignmentCredits.find(nodeData->getWalletUUID()); - float pendingCreditAmount = 0; - - while (i != _pendingAssignmentCredits.end() && i.key() == nodeData->getWalletUUID()) { - pendingCreditAmount += i.value()->getAmount() / SATOSHIS_PER_CREDIT; - ++i; - } - - nodeJson[JSON_KEY_PENDING_CREDITS] = pendingCreditAmount; - } } return nodeJson; @@ -2144,24 +2038,6 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url connection->respond(HTTPConnection::StatusCode200, assignmentDocument.toJson(), qPrintable(JSON_MIME_TYPE)); // we've processed this request - return true; - } else if (url.path() == "/transactions.json") { - // enumerate our pending transactions and display them in an array - QJsonObject rootObject; - QJsonArray transactionArray; - - TransactionHash::iterator i = _pendingAssignmentCredits.begin(); - while (i != _pendingAssignmentCredits.end()) { - transactionArray.push_back(i.value()->toJson()); - ++i; - } - - rootObject["pending_transactions"] = transactionArray; - - // print out the created JSON - QJsonDocument transactionsDocument(rootObject); - connection->respond(HTTPConnection::StatusCode200, transactionsDocument.toJson(), qPrintable(JSON_MIME_TYPE)); - return true; } else if (url.path() == QString("%1.json").arg(URI_NODES)) { // setup the JSON diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index c27500d5ce0..4c2746828f4 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -32,7 +32,6 @@ #include "DomainMetadata.h" #include "DomainServerSettingsManager.h" #include "DomainServerWebSessionData.h" -#include "WalletTransaction.h" #include "DomainContentBackupManager.h" #include "PendingAssignedNodeData.h" @@ -44,7 +43,6 @@ Q_DECLARE_LOGGING_CATEGORY(domain_server) Q_DECLARE_LOGGING_CATEGORY(domain_server_ice) typedef QSharedPointer SharedAssignmentPointer; -typedef QMultiHash TransactionHash; using Subnet = QPair; using SubnetList = std::vector; @@ -87,8 +85,6 @@ public slots: /// Called by NodeList to inform us a node has been killed void nodeKilled(SharedNodePointer node); - void transactionJSONCallback(const QJsonObject& data); - void restart(); private slots: @@ -108,9 +104,6 @@ private slots: void processOctreeDataRequestMessage(QSharedPointer message); void processOctreeDataPersistMessage(QSharedPointer message); - void setupPendingAssignmentCredits(); - void sendPendingTransactionsToServer(); - void performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr); void sendHeartbeatToMetaverse() { sendHeartbeatToMetaverse(QString()); } void sendHeartbeatToIceServer(); @@ -247,7 +240,6 @@ private slots: QHash _allAssignments; QQueue _unfulfilledAssignments; - TransactionHash _pendingAssignmentCredits; bool _isUsingDTLS { false }; diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index 370886cbce7..30659f655d8 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -33,9 +33,6 @@ class DomainServerNodeData : public NodeData { void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } const QUuid& getAssignmentUUID() const { return _assignmentUUID; } - void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } - const QUuid& getWalletUUID() const { return _walletUUID; } - void setUsername(const QString& username) { _username = username; } const QString& getUsername() const { return _username; } @@ -82,7 +79,6 @@ class DomainServerNodeData : public NodeData { QHash _sessionSecretHash; QUuid _assignmentUUID; - QUuid _walletUUID; QString _username; QElapsedTimer _paymentIntervalTimer; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 95bf4adc652..f86084c85fa 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -398,14 +398,6 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena packPermissions(); } - if (oldVersion < 1.9) { - unpackPermissions(); - // This was prior to addition of canRez(Tmp)Certified; add those to localhost permissions by default - _standardAgentPermissions[NodePermissions::standardNameLocalhost]->set(NodePermissions::Permission::canRezPermanentCertifiedEntities); - _standardAgentPermissions[NodePermissions::standardNameLocalhost]->set(NodePermissions::Permission::canRezTemporaryCertifiedEntities); - packPermissions(); - } - if (oldVersion < 2.0) { const QString WIZARD_COMPLETED_ONCE = "wizard.completed_once"; diff --git a/domain-server/src/PendingAssignedNodeData.cpp b/domain-server/src/PendingAssignedNodeData.cpp index 1376e6aa0ea..51f37a35a7d 100644 --- a/domain-server/src/PendingAssignedNodeData.cpp +++ b/domain-server/src/PendingAssignedNodeData.cpp @@ -11,9 +11,8 @@ #include "PendingAssignedNodeData.h" -PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID, const QString& nodeVersion) : +PendingAssignedNodeData::PendingAssignedNodeData(const QUuid& assignmentUUID, const QString& nodeVersion) : _assignmentUUID(assignmentUUID), - _walletUUID(walletUUID), _nodeVersion(nodeVersion) { diff --git a/domain-server/src/PendingAssignedNodeData.h b/domain-server/src/PendingAssignedNodeData.h index eb384a7a939..9641da755d2 100644 --- a/domain-server/src/PendingAssignedNodeData.h +++ b/domain-server/src/PendingAssignedNodeData.h @@ -18,19 +18,15 @@ class PendingAssignedNodeData : public QObject { Q_OBJECT public: - PendingAssignedNodeData(const QUuid& assignmentUUID, const QUuid& walletUUID, const QString& nodeVersion); + PendingAssignedNodeData(const QUuid& assignmentUUID, const QString& nodeVersion); void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } const QUuid& getAssignmentUUID() const { return _assignmentUUID; } - void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } - const QUuid& getWalletUUID() const { return _walletUUID; } - const QString& getNodeVersion() const { return _nodeVersion; } private: QUuid _assignmentUUID; - QUuid _walletUUID; QString _nodeVersion; }; diff --git a/interface/resources/html/commerce/backup_instructions.html b/interface/resources/html/commerce/backup_instructions.html deleted file mode 100644 index 034844e7056..00000000000 --- a/interface/resources/html/commerce/backup_instructions.html +++ /dev/null @@ -1,609 +0,0 @@ - - - - - -Backing Up Your Private Keys | High Fidelity - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- -

Backing Up Your Private Keys

-
- - -

What are private keys?

-

A private key is a secret piece of text that is used to prove ownership, unlock confidential information and sign transactions.

-

In High Fidelity, your private keys are used to securely access the contents of your Wallet and Purchases.

- -
-

Where are my private keys stored?

-

By default, your private keys are only stored on your hard drive in High Fidelity Interface's AppData directory.

-

Here is the file path of your hifikey - you can browse to it using your file explorer.

-
HIFIKEY_PATH_REPLACEME
- -
-

How should I make a backup of my private keys?

-

You should backup your .hifikey file above by copying it to a USB flash drive, or to a service like Dropbox or Google Drive. Restore your backup by replacing the file in Interface's AppData directory with your backed-up copy.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -

What happens if I lose my passphrase?

-

Your passphrase is used to encrypt your private keys. If you lose your passphrase, you will no longer be able to decrypt your private key file nor have access to the contents of your Wallet or My Purchases.

-

In order to guarantee your privacy, nobody can help you recover your passphrase, including High Fidelity. - -

Please write it down and store it securely.

-

 

-
- -

Want to learn more?

-

You can find out much more about the blockchain and about commerce in High Fidelity by visiting our Docs site:

-

Visit High Fidelity's Docs

-
- -
-
- -
- - diff --git a/interface/resources/meshes/verifyFailed.fst b/interface/resources/meshes/verifyFailed.fst deleted file mode 100644 index 97941bf8364..00000000000 --- a/interface/resources/meshes/verifyFailed.fst +++ /dev/null @@ -1,86 +0,0 @@ -name = mannequin2 -type = body+head -scale = 1 -filename = mannequin/man_stolen.fbx -texdir = textures -joint = jointEyeLeft = LeftEye -joint = jointRightHand = RightHand -joint = jointHead = Head -joint = jointEyeRight = RightEye -joint = jointNeck = Neck -joint = jointLeftHand = LeftHand -joint = jointLean = Spine -joint = jointRoot = Hips -freeJoint = LeftArm -freeJoint = LeftForeArm -freeJoint = RightArm -freeJoint = RightForeArm -jointIndex = RightHandPinky2 = 19 -jointIndex = LeftHandPinky3 = 44 -jointIndex = RightToeBase = 9 -jointIndex = LeftHandRing4 = 49 -jointIndex = LeftHandPinky1 = 42 -jointIndex = LeftHandRing1 = 46 -jointIndex = LeftLeg = 2 -jointIndex = RightHandIndex4 = 29 -jointIndex = LeftHandRing3 = 48 -jointIndex = RightShoulder = 14 -jointIndex = RightArm = 15 -jointIndex = Neck = 62 -jointIndex = RightHandMiddle2 = 35 -jointIndex = HeadTop_End = 66 -jointIndex = LeftHandRing2 = 47 -jointIndex = RightHandThumb1 = 30 -jointIndex = RightHandRing3 = 24 -jointIndex = LeftHandIndex3 = 52 -jointIndex = LeftForeArm = 40 -jointIndex = face = 68 -jointIndex = LeftToe_End = 5 -jointIndex = RightHandThumb3 = 32 -jointIndex = RightEye = 65 -jointIndex = Spine = 11 -jointIndex = LeftEye = 64 -jointIndex = LeftToeBase = 4 -jointIndex = LeftHandIndex4 = 53 -jointIndex = RightHandPinky4 = 21 -jointIndex = RightHandMiddle1 = 34 -jointIndex = Spine1 = 12 -jointIndex = LeftHandIndex2 = 51 -jointIndex = RightToe_End = 10 -jointIndex = RightHand = 17 -jointIndex = LeftUpLeg = 1 -jointIndex = RightHandRing1 = 22 -jointIndex = RightUpLeg = 6 -jointIndex = RightHandMiddle4 = 37 -jointIndex = Head = 63 -jointIndex = RightHandMiddle3 = 36 -jointIndex = RightHandIndex1 = 26 -jointIndex = LeftHandMiddle4 = 61 -jointIndex = LeftHandPinky4 = 45 -jointIndex = Hips = 0 -jointIndex = body = 67 -jointIndex = RightHandThumb2 = 31 -jointIndex = LeftHandThumb2 = 55 -jointIndex = RightHandThumb4 = 33 -jointIndex = RightHandPinky3 = 20 -jointIndex = LeftHandPinky2 = 43 -jointIndex = LeftShoulder = 38 -jointIndex = RightHandIndex3 = 28 -jointIndex = LeftHandThumb4 = 57 -jointIndex = RightLeg = 7 -jointIndex = RightHandIndex2 = 27 -jointIndex = LeftHandMiddle3 = 60 -jointIndex = RightHandRing4 = 25 -jointIndex = LeftHandThumb1 = 54 -jointIndex = LeftArm = 39 -jointIndex = LeftHandThumb3 = 56 -jointIndex = LeftHandMiddle1 = 58 -jointIndex = RightHandPinky1 = 18 -jointIndex = Spine2 = 13 -jointIndex = RightHandRing2 = 23 -jointIndex = RightForeArm = 16 -jointIndex = LeftHandIndex1 = 50 -jointIndex = RightFoot = 8 -jointIndex = LeftHandMiddle2 = 59 -jointIndex = LeftHand = 41 -jointIndex = LeftFoot = 3 diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml deleted file mode 100644 index 424b4d616db..00000000000 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ /dev/null @@ -1,1250 +0,0 @@ -// -// Checkout.qml -// qml/hifi/commerce/checkout -// -// Checkout -// -// Created by Zach Fox on 2017-08-25 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../wallet" as HifiWallet -import "../common" as HifiCommerceCommon -import "../.." as HifiCommon - -// references XXX from root context - -Rectangle { - HifiConstants { id: hifi; } - - id: root; - objectName: "checkout" - property string activeView: "initialize"; - property bool ownershipStatusReceived: false; - property bool balanceReceived: false; - property bool availableUpdatesReceived: false; - property bool itemInfoReceived: false; - property bool dataReady: itemInfoReceived && ownershipStatusReceived && balanceReceived && availableUpdatesReceived; - property string baseItemName: ""; - property string itemName; - property string itemId; - property string itemHref; - property string itemAuthor; - property int itemEdition: -1; - property bool hasSomethingToTradeIn: itemEdition > 0; // i.e., don't trade in your artist's proof - property bool isTradingIn: canUpdate && hasSomethingToTradeIn; - property bool isStocking: (availability === 'not for sale') && (creator === Account.username) && !updated_item_id; - property string certificateId; - property double balanceAfterPurchase; - property bool alreadyOwned: false; // Including proofs - property int itemPrice: -1; - property bool isCertified; - property string itemType: "unknown"; - property var itemTypesArray: ["entity", "wearable", "contentSet", "app", "avatar", "unknown"]; - property var itemTypesText: ["entity", "wearable", "content set", "app", "avatar", "item"]; - property var buttonTextNormal: ["REZ", "WEAR", "REPLACE CONTENT SET", "INSTALL", "WEAR", "REZ"]; - property var buttonTextClicked: ["REZZED!", "WORN!", "CONTENT SET REPLACED!", "INSTALLED!", "AVATAR CHANGED!", "REZZED!"] - property var buttonGlyph: [hifi.glyphs.wand, hifi.glyphs.hat, hifi.glyphs.globe, hifi.glyphs.install, hifi.glyphs.avatar, hifi.glyphs.wand]; - property bool shouldBuyWithControlledFailure: false; - property bool debugCheckoutSuccess: false; - property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified(); - property string referrer; - property bool isInstalled; - property bool canUpdate; - property string availability: "available"; - property string updated_item_id: ""; - property string creator: ""; - property string baseAppURL; - property int currentUpdatesPage: 1; - // Style - color: hifi.colors.white; - Connections { - target: Commerce; - - onWalletStatusResult: { - if (walletStatus === 0) { - if (root.activeView !== "needsLogIn") { - root.activeView = "needsLogIn"; - } - } else if ((walletStatus === 1) || (walletStatus === 2) || (walletStatus === 3)) { - if (root.activeView !== "notSetUp") { - root.activeView = "notSetUp"; - notSetUpTimer.start(); - } - } else if (walletStatus === 4) { - if (root.activeView !== "passphraseModal") { - root.activeView = "passphraseModal"; - UserActivityLogger.commercePassphraseEntry("marketplace checkout"); - } - } else if (walletStatus === 5) { - authSuccessStep(); - } else { - console.log("ERROR in Checkout.qml: Unknown wallet status: " + walletStatus); - } - } - - onLoginStatusResult: { - if (!isLoggedIn && root.activeView !== "needsLogIn") { - root.activeView = "needsLogIn"; - } else { - Commerce.getWalletStatus(); - } - } - - onBuyResult: { - if (result.status !== 'success') { - failureErrorText.text = result.data.message; - root.activeView = "checkoutFailure"; - UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.data.message); - } else { - root.certificateId = result.data.certificate_id; - root.itemHref = result.data.download_url; - root.activeView = "checkoutSuccess"; - UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned); - } - } - - onBalanceResult: { - if (result.status !== 'success') { - console.log("Failed to get balance", result.data.message); - } else { - root.balanceAfterPurchase = result.data.balance - root.itemPrice; - root.balanceReceived = true; - root.refreshBuyUI(); - } - } - - onAlreadyOwnedResult: { - if (result.status !== 'success') { - console.log("Failed to get Already Owned status", result.data.message); - } else { - if (result.data.marketplace_item_id === root.itemId) { - root.alreadyOwned = result.data.already_owned; - } else { - console.log("WARNING - Received 'Already Owned' status about different Marketplace ID!"); - root.alreadyOwned = false; - } - root.ownershipStatusReceived = true; - root.refreshBuyUI(); - } - } - - onAppInstalled: { - if (appID === root.itemId) { - root.isInstalled = true; - } - } - - onAvailableUpdatesResult: { - // Answers the updatable original item cert data still owned by this user that are EITHER instances of this marketplace id, or update to this marketplace id. - if (result.status !== 'success') { - console.log("Failed to get Available Updates", result.data.message); - } else { - for (var i = 0; i < result.data.updates.length; i++) { - // If the ItemID of the item we're looking at matches EITHER the ID of a "base" item - // OR the ID of an "updated" item, we're updating. - if (root.itemId === result.data.updates[i].item_id || - root.itemId === result.data.updates[i].updated_item_id) { - if (root.itemEdition !== -1 && root.itemEdition !== parseInt(result.data.updates[i].edition_number)) { - continue; - } - root.canUpdate = true; - root.baseItemName = result.data.updates[i].base_item_title; - // This CertID is the one corresponding to the base item CertID that the user already owns - root.certificateId = result.data.updates[i].certificate_id; - if (root.itemType === "app") { - root.baseAppURL = result.data.updates[i].item_download_url; - } - break; - } - } - - if (result.data.updates.length === 0 || root.canUpdate) { - root.availableUpdatesReceived = true; - refreshBuyUI(); - } else { - root.currentUpdatesPage++; - Commerce.getAvailableUpdates(root.itemId, currentUpdatesPage) - } - } - } - - onUpdateItemResult: { - if (result.status !== 'success') { - failureErrorText.text = result.data ? (result.data.message || "Unknown Error") : JSON.stringify(result); - root.activeView = "checkoutFailure"; - } else { - root.itemHref = result.data.download_url; - root.activeView = "checkoutSuccess"; - } - } - } - - onItemIdChanged: { - root.ownershipStatusReceived = false; - root.itemInfoReceived = false; - Commerce.alreadyOwned(root.itemId); - root.availableUpdatesReceived = false; - root.currentUpdatesPage = 1; - Commerce.getAvailableUpdates(root.itemId); - - var MARKETPLACE_API_URL = Account.metaverseServerURL + "/api/v1/marketplace/items/"; - http.request({uri: MARKETPLACE_API_URL + root.itemId}, updateCheckoutQMLFromHTTP); - } - - onItemTypeChanged: { - if (root.itemType === "entity" || root.itemType === "wearable" || - root.itemType === "contentSet" || root.itemType === "avatar" || root.itemType === "app") { - root.isCertified = true; - } else { - root.isCertified = false; - } - } - - onItemPriceChanged: { - root.balanceReceived = false; - Commerce.balance(); - } - - Timer { - id: notSetUpTimer; - interval: 200; - onTriggered: { - sendToScript({method: 'checkout_walletNotSetUp', itemId: itemId, referrer: referrer}); - } - } - - HifiCommerceCommon.CommerceLightbox { - id: lightboxPopup; - visible: false; - anchors.fill: parent; - - Connections { - onSendToParent: { - sendToScript(msg); - } - } - } - - // - // TITLE BAR START - // - HifiCommerceCommon.EmulatedMarketplaceHeader { - id: titleBarContainer; - z: 998; - visible: !needsLogIn.visible; - // Size - width: parent.width; - height: 70; - // Anchors - anchors.left: parent.left; - anchors.top: parent.top; - - Connections { - onSendToParent: { - if (msg.method === 'needsLogIn' && root.activeView !== "needsLogIn") { - root.activeView = "needsLogIn"; - } else if (msg.method === 'showSecurityPicLightbox') { - lightboxPopup.titleText = "Your Security Pic"; - lightboxPopup.bodyImageSource = msg.securityImageSource; - lightboxPopup.bodyText = lightboxPopup.securityPicBodyText; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } else { - sendToScript(msg); - } - } - } - } - // - // TITLE BAR END - // - - Rectangle { - id: initialize; - visible: root.activeView === "initialize"; - anchors.top: titleBarContainer.bottom; - anchors.bottom: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - color: hifi.colors.white; - - Component.onCompleted: { - ownershipStatusReceived = false; - balanceReceived = false; - availableUpdatesReceived = false; - itemInfoReceived = false; - Commerce.getWalletStatus(); - } - } - - HifiWallet.NeedsLogIn { - id: needsLogIn; - visible: root.activeView === "needsLogIn"; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - - Connections { - onSendSignalToWallet: { - sendToScript(msg); - } - } - } - Connections { - target: GlobalServices - onMyUsernameChanged: { - Commerce.getLoginStatus(); - } - } - - HifiWallet.PassphraseModal { - id: passphraseModal; - visible: root.activeView === "passphraseModal"; - anchors.fill: parent; - titleBarText: "Checkout"; - titleBarIcon: hifi.glyphs.wallet; - - Connections { - onSendSignalToParent: { - if (msg.method === "authSuccess") { - authSuccessStep(); - } else { - sendToScript(msg); - } - } - } - } - - HifiCommerceCommon.FirstUseTutorial { - id: firstUseTutorial; - z: 999; - visible: root.activeView === "firstUseTutorial"; - anchors.fill: parent; - - Connections { - onSendSignalToParent: { - switch (message.method) { - case 'tutorial_skipClicked': - case 'tutorial_finished': - Settings.setValue("isFirstUseOfPurchases", false); - root.activeView = "checkoutSuccess"; - break; - } - } - } - } - - // - // CHECKOUT CONTENTS START - // - Item { - id: checkoutContents; - visible: root.activeView === "checkoutMain"; - anchors.top: titleBarContainer.bottom; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - - Rectangle { - id: loading; - z: 997; - visible: !root.ownershipStatusReceived || !root.balanceReceived || !root.availableUpdatesReceived || !root.itemInfoReceived; - anchors.fill: parent; - color: hifi.colors.white; - - // This object is always used in a popup. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup/section. - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - propagateComposedEvents: false; - } - - AnimatedImage { - id: loadingImage; - source: "../common/images/loader-blue.gif" - width: 74; - height: width; - anchors.verticalCenter: parent.verticalCenter; - anchors.horizontalCenter: parent.horizontalCenter; - } - } - - RalewayRegular { - id: confirmPurchaseText; - anchors.top: parent.top; - anchors.topMargin: 30; - anchors.left: parent.left; - anchors.leftMargin: 16; - width: paintedWidth; - height: paintedHeight; - text: "Review:"; - color: hifi.colors.black; - size: 28; - } - - HifiControlsUit.Separator { - id: separator; - colorScheme: 1; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: confirmPurchaseText.bottom; - anchors.topMargin: 16; - } - - Item { - id: itemContainer; - anchors.top: separator.bottom; - anchors.topMargin: 24; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: 120; - - Image { - id: itemPreviewImage; - anchors.left: parent.left; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - width: height; - fillMode: Image.PreserveAspectCrop; - } - - RalewaySemiBold { - id: itemNameText; - text: root.itemName; - // Text size - size: 26; - // Anchors - anchors.top: parent.top; - anchors.left: itemPreviewImage.right; - anchors.leftMargin: 12; - anchors.right: parent.right; - anchors.rightMargin: 8; - height: 30; - // Style - color: hifi.colors.blueAccent; - elide: Text.ElideRight; - // Alignment - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignTop; - } - - // "Item Price" container - Item { - id: itemPriceContainer; - // Anchors - anchors.top: itemNameText.bottom; - anchors.topMargin: 8; - anchors.left: itemNameText.left; - height: 30; - width: itemPriceText.width + 20; - - // "HFC" label - HiFiGlyphs { - id: itemPriceTextLabel; - visible: !isTradingIn && (root.itemPrice > 0); - text: hifi.glyphs.hfc; - // Size - size: 30; - // Anchors - anchors.right: parent.right; - //anchors.rightMargin: 4; - anchors.top: parent.top; - anchors.topMargin: 0; - width: paintedWidth; - height: paintedHeight; - // Style - color: hifi.colors.blueAccent; - } - FiraSansSemiBold { - id: itemPriceText; - text: isTradingIn ? "FREE\nUPDATE" : - (isStocking ? "Free for creator" : - ((root.itemPrice === -1) ? "--" : ((root.itemPrice > 0) ? root.itemPrice : "FREE"))); - // Text size - size: isTradingIn ? 20 : 26; - // Anchors - anchors.top: parent.top; - anchors.left: itemPriceTextLabel.visible ? itemPriceTextLabel.right : parent.left; - anchors.leftMargin: 4; - width: paintedWidth; - height: paintedHeight; - // Style - color: hifi.colors.blueAccent; - } - } - } - - HifiControlsUit.Separator { - id: separator2; - colorScheme: 1; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: itemContainer.bottom; - anchors.topMargin: itemContainer.anchors.topMargin; - } - - - // - // ACTION BUTTONS AND TEXT START - // - Item { - id: checkoutActionButtonsContainer; - // Size - width: root.width; - // Anchors - anchors.top: separator2.bottom; - anchors.topMargin: 0; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 8; - - Rectangle { - id: buyTextContainer; - visible: buyText.text !== ""; - anchors.top: parent.top; - anchors.topMargin: 10; - anchors.left: parent.left; - anchors.right: parent.right; - height: buyText.height + 30; - radius: 4; - border.width: 2; - - HiFiGlyphs { - id: buyGlyph; - // Size - size: 46; - // Anchors - anchors.left: parent.left; - anchors.leftMargin: 4; - anchors.top: parent.top; - anchors.topMargin: 8; - anchors.bottom: parent.bottom; - width: paintedWidth; - // Style - color: hifi.colors.baseGray; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignTop; - } - - RalewayRegular { - id: buyText; - // Text size - size: 18; - // Anchors - anchors.left: buyGlyph.right; - anchors.leftMargin: 8; - anchors.right: parent.right; - anchors.rightMargin: 12; - anchors.verticalCenter: parent.verticalCenter; - height: paintedHeight; - // Style - color: hifi.colors.black; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignVCenter; - onLinkActivated: { - // Only case is to go to the bank. - sendToScript({method: 'gotoBank'}); - } - } - } - - // "View in Inventory" button - HifiControlsUit.Button { - id: viewInMyPurchasesButton; - visible: isCertified && dataReady && (isTradingIn ? hasSomethingToTradeIn : alreadyOwned); - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.light; - anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top; - anchors.topMargin: 10; - height: 50; - anchors.left: parent.left; - anchors.right: parent.right; - text: (canUpdate && !isTradingIn) ? "UPDATE TO THIS ITEM FOR FREE" : "VIEW THIS ITEM IN YOUR INVENTORY"; - onClicked: { - if (root.canUpdate) { - sendToScript({method: 'checkout_goToPurchases', filterText: root.baseItemName}); - } else { - sendToScript({method: 'checkout_goToPurchases', filterText: root.itemName}); - } - } - } - - // "Buy" button - HifiControlsUit.Button { - id: buyButton; - visible: isTradingIn || !alreadyOwned || isStocking || !(root.itemType === "avatar" || root.itemType === "app"); - property bool checkBalance: dataReady && (root.availability === "available") - enabled: (checkBalance && (balanceAfterPurchase >= 0)) || !isCertified || isTradingIn || isStocking; - text: isTradingIn ? "Confirm Update" : - (enabled ? (viewInMyPurchasesButton.visible ? "Get It Again" : (dataReady ? "Get Item" : "--")) : - (checkBalance ? "Insufficient Funds" : availability)) - color: viewInMyPurchasesButton.visible ? hifi.buttons.white : hifi.buttons.blue; - colorScheme: hifi.colorSchemes.light; - anchors.top: viewInMyPurchasesButton.visible ? viewInMyPurchasesButton.bottom : - (buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top); - anchors.topMargin: 10; - height: 50; - anchors.left: parent.left; - anchors.right: parent.right; - onClicked: { - if (isTradingIn) { - // If we're updating an app, the existing app needs to be uninstalled. - // This call will fail/return `false` if the app isn't installed, but that's OK. - if (root.itemType === "app") { - Commerce.uninstallApp(root.baseAppURL); - } - buyButton.enabled = false; - loading.visible = true; - Commerce.updateItem(root.certificateId); - } else if (root.isCertified) { - if (!root.shouldBuyWithControlledFailure) { - if (root.itemType === "contentSet" && !Entities.canReplaceContent()) { - lightboxPopup.titleText = "Get Content Set"; - lightboxPopup.bodyText = "You will not be able to replace this domain's content with " + root.itemName + - " until the server owner gives you 'Replace Content' permissions.

Are you sure you want to get this content set?"; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - Commerce.buy(root.itemId, root.itemPrice); - lightboxPopup.visible = false; - buyButton.enabled = false; - loading.visible = true; - }; - lightboxPopup.visible = true; - } else { - buyButton.enabled = false; - loading.visible = true; - Commerce.buy(root.itemId, root.itemPrice); - } - } else { - buyButton.enabled = false; - loading.visible = true; - Commerce.buy(root.itemId, root.itemPrice, true); - } - } else { - if (urlHandler.canHandleUrl(itemHref)) { - urlHandler.handleUrl(itemHref); - } - } - } - } - - // "Cancel" button - HifiControlsUit.Button { - id: cancelPurchaseButton; - color: hifi.buttons.noneBorderlessGray; - colorScheme: hifi.colorSchemes.light; - anchors.top: buyButton.visible ? buyButton.bottom : viewInMyPurchasesButton.bottom; - anchors.topMargin: 10; - height: 50; - anchors.left: parent.left; - anchors.right: parent.right; - text: "Cancel" - onClicked: { - sendToScript({method: 'checkout_cancelClicked', itemId: itemId}); - } - } - } - // - // ACTION BUTTONS END - // - } - // - // CHECKOUT CONTENTS END - // - - // - // CHECKOUT SUCCESS START - // - Item { - id: checkoutSuccess; - visible: root.activeView === "checkoutSuccess"; - anchors.top: titleBarContainer.bottom; - anchors.bottom: root.bottom; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - - RalewayRegular { - id: completeText; - anchors.top: parent.top; - anchors.topMargin: 18; - anchors.left: parent.left; - width: paintedWidth; - height: paintedHeight; - text: "Thank you for your order!"; - color: hifi.colors.baseGray; - size: 36; - } - - RalewaySemiBold { - id: completeText2; - text: "The " + (root.itemTypesText)[itemTypesArray.indexOf(root.itemType)] + - ' ' + root.itemName + '' + - " has been added to your Inventory."; - // Text size - size: 18; - // Anchors - anchors.top: completeText.bottom; - anchors.topMargin: 15; - height: paintedHeight; - anchors.left: parent.left; - anchors.right: parent.right; - // Style - color: hifi.colors.black; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignVCenter; - onLinkActivated: { - sendToScript({method: 'checkout_itemLinkClicked', itemId: itemId}); - } - } - - Rectangle { - id: rezzedNotifContainer; - z: 997; - visible: false; - color: hifi.colors.blueHighlight; - anchors.fill: rezNowButton; - radius: 5; - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - RalewayBold { - anchors.fill: parent; - text: (root.buttonTextClicked)[itemTypesArray.indexOf(root.itemType)]; - size: 18; - color: hifi.colors.white; - verticalAlignment: Text.AlignVCenter; - horizontalAlignment: Text.AlignHCenter; - } - - Timer { - id: rezzedNotifContainerTimer; - interval: 2000; - onTriggered: rezzedNotifContainer.visible = false - } - } - // "Rez" button - HifiControlsUit.Button { - id: rezNowButton; - enabled: (root.itemType === "entity" && root.canRezCertifiedItems) || - (root.itemType === "contentSet" && Entities.canReplaceContent()) || - root.itemType === "wearable" || root.itemType === "avatar" || root.itemType === "app"; - buttonGlyph: (root.buttonGlyph)[itemTypesArray.indexOf(root.itemType)]; - color: hifi.buttons.red; - colorScheme: hifi.colorSchemes.light; - anchors.top: completeText2.bottom; - anchors.topMargin: 27; - height: 50; - anchors.left: parent.left; - anchors.right: parent.right; - text: root.itemType === "app" && root.isInstalled ? "OPEN APP" : (root.buttonTextNormal)[itemTypesArray.indexOf(root.itemType)]; - onClicked: { - if (root.itemType === "contentSet") { - lightboxPopup.titleText = "Replace Content"; - lightboxPopup.bodyText = "Rezzing this content set will replace the existing environment and all of the items in this domain. " + - "If you want to save the state of the content in this domain, create a backup before proceeding.

" + - "For more information about backing up and restoring content, " + - "" + - "click here to open info on your desktop browser."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - Commerce.replaceContentSet(root.itemHref, root.certificateId, root.itemName); - lightboxPopup.visible = false; - rezzedNotifContainer.visible = true; - rezzedNotifContainerTimer.start(); - UserActivityLogger.commerceEntityRezzed(root.itemId, 'checkout', root.itemType); - }; - lightboxPopup.visible = true; - } else if (root.itemType === "avatar") { - lightboxPopup.titleText = "Change Avatar"; - lightboxPopup.bodyText = "This will change your current avatar to " + root.itemName + " while retaining your wearables."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - MyAvatar.useFullAvatarURL(root.itemHref); - lightboxPopup.visible = false; - }; - lightboxPopup.visible = true; - } else if (root.itemType === "app") { - if (root.isInstalled) { - Commerce.openApp(root.itemHref); - } else { - Commerce.installApp(root.itemHref); - } - } else { - sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, itemType: root.itemType}); - rezzedNotifContainer.visible = true; - rezzedNotifContainerTimer.start(); - UserActivityLogger.commerceEntityRezzed(root.itemId, "checkout", root.itemType); - } - } - } - RalewaySemiBold { - id: noPermissionText; - visible: !root.canRezCertifiedItems && root.itemType === "entity"; - text: 'You do not have Certified Rez permissions in this domain.' - // Text size - size: 16; - // Anchors - anchors.top: rezNowButton.bottom; - anchors.topMargin: 4; - height: paintedHeight; - anchors.left: parent.left; - anchors.right: parent.right; - // Style - color: hifi.colors.redAccent; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - onLinkActivated: { - lightboxPopup.titleText = "Rez Permission Required"; - lightboxPopup.bodyText = "You don't have permission to rez certified items in this domain.

" + - "Use the GOTO app to visit another domain or go to your own sandbox."; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "OPEN GOTO"; - lightboxPopup.button2method = function() { - sendToScript({method: 'checkout_openGoTo'}); - lightboxPopup.visible = false; - }; - lightboxPopup.visible = true; - } - } - RalewaySemiBold { - id: explainRezText; - visible: root.itemType === "entity"; - text: 'What does "Rez" mean?' - // Text size - size: 16; - // Anchors - anchors.top: noPermissionText.visible ? noPermissionText.bottom : rezNowButton.bottom; - anchors.topMargin: 6; - height: paintedHeight; - anchors.left: parent.left; - anchors.right: parent.right; - // Style - color: hifi.colors.redAccent; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - onLinkActivated: { - root.activeView = "firstUseTutorial"; - } - } - - RalewaySemiBold { - id: myPurchasesLink; - text: 'View this item in your Inventory'; - // Text size - size: 18; - // Anchors - anchors.top: explainRezText.visible ? explainRezText.bottom : (noPermissionText.visible ? noPermissionText.bottom : rezNowButton.bottom); - anchors.topMargin: 40; - height: paintedHeight; - anchors.left: parent.left; - anchors.right: parent.right; - // Style - color: hifi.colors.black; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignVCenter; - onLinkActivated: { - sendToScript({method: 'checkout_goToPurchases', filterText: root.itemName}); - } - } - - RalewaySemiBold { - id: walletLink; - visible: !WalletScriptingInterface.limitedCommerce; - text: 'View receipt in Recent Activity'; - // Text size - size: 18; - // Anchors - anchors.top: myPurchasesLink.bottom; - anchors.topMargin: 16; - height: paintedHeight; - anchors.left: parent.left; - anchors.right: parent.right; - // Style - color: hifi.colors.black; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignVCenter; - onLinkActivated: { - sendToScript({method: 'checkout_openRecentActivity'}); - } - } - - RalewayRegular { - id: pendingText; - text: 'Your item is marked "pending" while the transfer is being confirmed. ' + - 'Learn More'; - // Text size - size: 18; - // Anchors - anchors.top: walletLink.visible ? walletLink.bottom : myPurchasesLink.bottom; - anchors.topMargin: 32; - height: paintedHeight; - anchors.left: parent.left; - anchors.right: parent.right; - // Style - color: hifi.colors.black; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignVCenter; - onLinkActivated: { - lightboxPopup.titleText = "Confirmations"; - lightboxPopup.bodyText = 'Your item is marked "pending" while the transfer is being confirmed.

' + - 'Confirmations usually take about 90 seconds.'; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } - } - - // "Continue" button - HifiControlsUit.Button { - id: continueButton; - color: hifi.buttons.noneBorderlessGray; - colorScheme: hifi.colorSchemes.light; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 54; - anchors.right: parent.right; - width: 193; - height: 44; - text: "Continue"; - onClicked: { - sendToScript({method: 'checkout_continue', itemId: itemId}); - } - } - } - // - // CHECKOUT SUCCESS END - // - - // - // CHECKOUT FAILURE START - // - Item { - id: checkoutFailure; - visible: root.activeView === "checkoutFailure"; - anchors.top: titleBarContainer.bottom; - anchors.bottom: root.bottom; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - - RalewayRegular { - id: failureHeaderText; - text: "Purchase Failed.
Your Inventory and HFC balance haven't changed."; - // Text size - size: 24; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 40; - height: paintedHeight; - anchors.left: parent.left; - anchors.right: parent.right; - // Style - color: hifi.colors.black; - wrapMode: Text.WordWrap; - } - - Rectangle { - id: failureErrorTextContainer; - anchors.top: failureHeaderText.bottom; - anchors.topMargin: 35; - anchors.left: parent.left; - anchors.right: parent.right; - height: failureErrorText.height + 30; - radius: 4; - border.width: 2; - border.color: "#F3808F"; - color: "#FFC3CD"; - - AnonymousProRegular { - id: failureErrorText; - // Text size - size: 16; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 15; - anchors.left: parent.left; - anchors.leftMargin: 8; - anchors.right: parent.right; - anchors.rightMargin: 8; - height: paintedHeight; - // Style - color: hifi.colors.black; - wrapMode: Text.Wrap; - verticalAlignment: Text.AlignVCenter; - } - } - - Item { - id: backToMarketplaceButtonContainer; - // Size - width: root.width; - height: 50; - // Anchors - anchors.left: parent.left; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 16; - // "Back to Marketplace" button - HifiControlsUit.Button { - id: backToMarketplaceButton; - color: hifi.buttons.noneBorderlessGray; - colorScheme: hifi.colorSchemes.light; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.leftMargin: 16; - width: parent.width/2 - anchors.leftMargin*2; - text: "Back to Marketplace"; - onClicked: { - sendToScript({method: 'checkout_continue', itemId: itemId}); - } - } - } - } - // - // CHECKOUT FAILURE END - // - - Keys.onPressed: { - if ((event.key == Qt.Key_F) && (event.modifiers & Qt.ControlModifier)) { - if (!root.shouldBuyWithControlledFailure) { - buyButton.text += " DEBUG FAIL ON" - buyButton.color = hifi.buttons.red; - root.shouldBuyWithControlledFailure = true; - } else { - buyButton.text = (root.isCertified ? - (dataReady ? - (root.alreadyOwned ? "Buy Another" : "Buy") : - "--") : - "Get Item"); - buyButton.color = hifi.buttons.blue; - root.shouldBuyWithControlledFailure = false; - } - } - } - - - HifiCommon.RootHttpRequest { - id: http; - } - - // - // FUNCTION DEFINITIONS START - // - - function updateCheckoutQMLFromHTTP(error, result) { - if (error || (result.status !== 'success')) { - // The QML will display a loading spinner forever if the user is stuck here. - console.log("Error in Checkout.qml when getting marketplace item info!"); - return; - } - - root.itemInfoReceived = true; - root.itemName = result.data.title; - root.itemPrice = result.data.cost; - root.itemAuthor = result.data.creator; - root.itemType = result.data.item_type || "unknown"; - root.availability = result.data.availability; - root.updated_item_id = result.data.updated_item_id || "" - root.creator = result.data.creator; - if (root.itemType === "unknown") { - root.itemHref = result.data.review_url; - } else { - root.itemHref = Account.metaverseServerURL + result.data.path; - } - itemPreviewImage.source = result.data.thumbnail_url; - refreshBuyUI(); - } - - // - // Function Name: fromScript() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the JavaScript, in this case the Marketplaces JavaScript. - // Messages are in format "{method, params}", like json-rpc. - // - // Description: - // Called when a message is received from a script. - // - - function fromScript(message) { - switch (message.method) { - case 'updateCheckoutQMLItemID': - if (!message.params.itemId) { - console.log("A message with method 'updateCheckoutQMLItemID' was sent without an itemId!"); - return; - } - - // If we end up following the referrer (i.e. in case the wallet "isn't set up" or the user cancels), - // we want the user to be placed back on the individual item's page - thus we set the - // default of the referrer in this case to "itemPage". - root.referrer = message.params.referrer || "itemPage"; - root.itemEdition = message.params.itemEdition || -1; - root.itemId = message.params.itemId; - break; - case 'http.response': - http.handleHttpResponse(message); - break; - default: - console.log('Checkout.qml: Unrecognized message from marketplaces.js'); - } - } - signal sendToScript(var message); - - function canBuyAgain() { - return root.itemType === "entity" || root.itemType === "wearable" || root.itemType === "contentSet" || root.itemType === "unknown" || isStocking; - } - - function handleContentSets() { - if (root.itemType === "contentSet" && !Entities.canReplaceContent()) { - buyText.text = "The domain owner must enable 'Replace Content' permissions for you in this " + - "domain's server settings before you can replace this domain's content with " + root.itemName + ""; - buyTextContainer.color = "#FFC3CD"; - buyTextContainer.border.color = "#F3808F"; - buyGlyph.text = hifi.glyphs.alert; - buyGlyph.size = 54; - } - } - - function handleBuyAgainLogic() { - // General rules, implemented in various scattered places in this file: - // 1. If you already own the item, a viewInMyPurchasesButton is visible, - // and the buyButton is visible (and says "Buy it again") ONLY if it is a type you canBuyAgain. - // 2. Separately, - // a. If you don't have enough money to buy, the buyText becomes visible and tells you, and the buyButton is disabled. - // b. Otherwise, if the item is a content set and you don't have rez permission, the buyText becomes visible and tells you so. - - // If you can't afford another copy of the item... - if (root.balanceAfterPurchase < 0) { - // If you already own the item... - if (!root.alreadyOwned) { - buyText.text = "You do not have sufficient funds to purchase this item."; - // Else if you don't already own the item... - } else if (canBuyAgain()) { - buyText.text = "You do not have sufficient funds to purchase this item again."; - } else { - buyText.text = "While you do not have sufficient funds to buy this, you already have this item." - } - buyText.text += " Visit Bank of High Fidelity to get more HFC." - buyTextContainer.color = "#FFC3CD"; - buyTextContainer.border.color = "#F3808F"; - buyGlyph.text = hifi.glyphs.alert; - buyGlyph.size = 54; - // If you CAN afford another copy of the item... - } else { - handleContentSets(); - } - } - - function refreshBuyUI() { - if (root.isCertified) { - if (dataReady) { - buyText.text = ""; - - // If the user IS on the checkout page for the updated version of an owned item... - if (root.canUpdate) { - // If the user HAS already selected a specific edition to update... - if (hasSomethingToTradeIn) { - buyText.text = "By pressing \"Confirm Update\", you agree to trade in your old item for the updated item that replaces it."; - buyTextContainer.color = "#FFFFFF"; - buyTextContainer.border.color = "#FFFFFF"; - // Else if the user HAS NOT selected a specific edition to update... - } else { - handleBuyAgainLogic(); - } - // If the user IS NOT on the checkout page for the updated verison of an owned item... - // (i.e. they are checking out an item "normally") - } else { - handleBuyAgainLogic(); - } - } else { - buyText.text = ""; - } - } else { - buyText.text = 'This type of item cannot currently be certified, so it will not show up in "Inventory". You can access it again for free from the Marketplace.'; - buyTextContainer.color = hifi.colors.white; - buyTextContainer.border.color = hifi.colors.white; - buyGlyph.text = ""; - buyGlyph.size = 0; - } - } - - function authSuccessStep() { - if (!root.debugCheckoutSuccess) { - root.activeView = "checkoutMain"; - root.ownershipStatusReceived = false; - Commerce.alreadyOwned(root.itemId); - root.availableUpdatesReceived = false; - root.currentUpdatesPage = 1; - Commerce.getAvailableUpdates(root.itemId); - root.balanceReceived = false; - Commerce.balance(); - } else { - root.activeView = "checkoutSuccess"; - } - } - - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml deleted file mode 100644 index b7215500d22..00000000000 --- a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml +++ /dev/null @@ -1,188 +0,0 @@ -// -// CommerceLightbox.qml -// qml/hifi/commerce/common -// -// CommerceLightbox -// -// Created by Zach Fox on 2017-09-19 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "qrc:////qml//controls" as HifiControls - -// references XXX from root context - -Rectangle { - property string titleText; - property string bodyImageSource; - property string bodyText; - property string button1color: hifi.buttons.noneBorderlessGray; - property string button1text; - property var button1method; - property string button2color: hifi.buttons.blue; - property string button2text; - property var button2method; - property string buttonLayout: "leftright"; - - readonly property string securityPicBodyText: "When you see your Security Pic, your actions and data are securely making use of your " + - "private keys.

You can change your Security Pic via Settings > Security..."; - - id: root; - visible: false; - anchors.fill: parent; - color: Qt.rgba(0, 0, 0, 0.5); - z: 999; - - HifiConstants { id: hifi; } - - onVisibleChanged: { - if (!visible) { - resetLightbox(); - } - } - - // This object is always used in a popup. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - Rectangle { - anchors.centerIn: parent; - width: parent.width - 100; - height: childrenRect.height + 30; - color: "white"; - - RalewaySemiBold { - id: titleText; - text: root.titleText; - anchors.top: parent.top; - anchors.topMargin: 30; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.right: parent.right; - anchors.rightMargin: 30; - height: paintedHeight; - color: hifi.colors.black; - size: 24; - verticalAlignment: Text.AlignTop; - wrapMode: Text.WordWrap; - } - - Image { - id: bodyImage; - visible: root.bodyImageSource; - source: root.bodyImageSource ? root.bodyImageSource : ""; - anchors.top: root.titleText ? titleText.bottom : parent.top; - anchors.topMargin: root.titleText ? 20 : 30; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.right: parent.right; - anchors.rightMargin: 30; - height: 140; - fillMode: Image.PreserveAspectFit; - mipmap: true; - cache: false; - } - - RalewayRegular { - id: bodyText; - text: root.bodyText; - anchors.top: root.bodyImageSource ? bodyImage.bottom : (root.titleText ? titleText.bottom : parent.top); - anchors.topMargin: root.bodyImageSource ? 20 : (root.titleText ? 20 : 30); - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.right: parent.right; - anchors.rightMargin: 30; - height: paintedHeight; - color: hifi.colors.black; - size: 20; - verticalAlignment: Text.AlignTop; - wrapMode: Text.WordWrap; - - onLinkActivated: { - sendToParent({ method: 'commerceLightboxLinkClicked', linkUrl: link }); - } - } - - Item { - id: buttons; - anchors.top: bodyText.bottom; - anchors.topMargin: 30; - anchors.left: parent.left; - anchors.right: parent.right; - height: root.buttonLayout === "leftright" ? 70 : 150; - - // Button 1 - HifiControlsUit.Button { - id: button1; - color: root.button1color; - colorScheme: hifi.colorSchemes.light; - anchors.top: root.buttonLayout === "leftright" ? parent.top : parent.top; - anchors.left: parent.left; - anchors.leftMargin: root.buttonLayout === "leftright" ? 30 : 10; - anchors.right: root.buttonLayout === "leftright" ? undefined : parent.right; - anchors.rightMargin: root.buttonLayout === "leftright" ? undefined : 10; - width: root.buttonLayout === "leftright" ? (root.button2text ? parent.width/2 - anchors.leftMargin*2 : parent.width - anchors.leftMargin * 2) : - (undefined); - height: 40; - text: root.button1text; - onClicked: { - button1method(); - } - } - - // Button 2 - HifiControlsUit.Button { - id: button2; - visible: root.button2text; - color: root.button2color; - colorScheme: hifi.colorSchemes.light; - anchors.top: root.buttonLayout === "leftright" ? parent.top : button1.bottom; - anchors.topMargin: root.buttonLayout === "leftright" ? undefined : 20; - anchors.left: root.buttonLayout === "leftright" ? undefined : parent.left; - anchors.leftMargin: root.buttonLayout === "leftright" ? undefined : 10; - anchors.right: parent.right; - anchors.rightMargin: root.buttonLayout === "leftright" ? 30 : 10; - width: root.buttonLayout === "leftright" ? parent.width/2 - anchors.rightMargin*2 : undefined; - height: 40; - text: root.button2text; - onClicked: { - button2method(); - } - } - } - } - - // - // FUNCTION DEFINITIONS START - // - signal sendToParent(var msg); - - function resetLightbox() { - root.titleText = ""; - root.bodyImageSource = ""; - root.bodyText = ""; - root.button1color = hifi.buttons.noneBorderlessGray; - root.button1text = ""; - root.button1method = function() {}; - root.button2color = hifi.buttons.blue; - root.button2text = ""; - root.button2method = function() {}; - root.buttonLayout = "leftright"; - } - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml deleted file mode 100644 index 759d61b9246..00000000000 --- a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml +++ /dev/null @@ -1,145 +0,0 @@ -// -// EmulatedMarketplaceHeader.qml -// qml/hifi/commerce/common -// -// EmulatedMarketplaceHeader -// -// Created by Zach Fox on 2017-09-18 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.7 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls - -// references XXX from root context - -Item { - HifiConstants { id: hifi; } - - id: root; - - height: mainContainer.height; - - Connections { - target: Commerce; - - onWalletStatusResult: { - if (walletStatus === 0) { - sendToParent({method: "needsLogIn"}); - } else if (walletStatus === 5) { - Commerce.getSecurityImage(); - } else if (walletStatus > 5) { - console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus); - } - } - - onLoginStatusResult: { - if (!isLoggedIn) { - sendToParent({method: "needsLogIn"}); - } else { - Commerce.getWalletStatus(); - } - } - - onSecurityImageResult: { - if (exists) { - securityImage.source = ""; - securityImage.source = "image://security/securityImage"; - } - } - } - - Component.onCompleted: { - Commerce.getWalletStatus(); - } - - Connections { - target: GlobalServices - onMyUsernameChanged: { - Commerce.getLoginStatus(); - } - } - - Rectangle { - id: mainContainer; - color: hifi.colors.white; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: parent.top; - height: 70; - - Image { - id: marketplaceHeaderImage; - source: "images/marketplaceHeaderImage.png"; - anchors.top: parent.top; - anchors.topMargin: 2; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 10; - anchors.left: parent.left; - anchors.leftMargin: 8; - width: 140; - fillMode: Image.PreserveAspectFit; - - MouseArea { - anchors.fill: parent; - onClicked: { - sendToParent({method: "header_marketplaceImageClicked"}); - } - } - } - - Image { - id: securityImage; - source: ""; - visible: securityImage.source !== ""; - anchors.right: parent.right; - anchors.rightMargin: 6; - anchors.top: parent.top; - anchors.topMargin: 6; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 16; - width: height; - mipmap: true; - cache: false; - - MouseArea { - enabled: securityImage.visible; - anchors.fill: parent; - onClicked: { - sendToParent({method: "showSecurityPicLightbox", securityImageSource: securityImage.source}); - } - } - } - - LinearGradient { - z: 996; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - height: 10; - start: Qt.point(0, 0); - end: Qt.point(0, height); - gradient: Gradient { - GradientStop { position: 0.0; color: hifi.colors.lightGrayText } - GradientStop { position: 1.0; color: hifi.colors.white } - } - } - - } - - - // - // FUNCTION DEFINITIONS START - // - signal sendToParent(var msg); - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml deleted file mode 100644 index c2d85b68b45..00000000000 --- a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml +++ /dev/null @@ -1,221 +0,0 @@ -// -// FirstUseTutorial.qml -// qml/hifi/commerce/purchases -// -// FirstUseTutorial -// -// Created by Zach Fox on 2017-09-13 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls - -// references XXX from root context - -Rectangle { - HifiConstants { id: hifi; } - - id: root; - property int activeView: 1; - - onVisibleChanged: { - if (visible) { - root.activeView = 1; - } - } - - Image { - anchors.fill: parent; - source: "images/Purchase-First-Run-" + root.activeView + ".jpg"; - } - - // This object is always used in a popup. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - Item { - id: header; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - height: childrenRect.height; - - Image { - id: marketplaceHeaderImage; - source: "../common/images/marketplaceHeaderImage.png"; - anchors.top: parent.top; - anchors.topMargin: 2; - anchors.left: parent.left; - anchors.leftMargin: 8; - width: 140; - height: 58; - fillMode: Image.PreserveAspectFit; - visible: false; - } - ColorOverlay { - anchors.fill: marketplaceHeaderImage; - source: marketplaceHeaderImage; - color: "#FFFFFF" - } - RalewayRegular { - id: introText1; - text: "INTRODUCTION TO"; - // Text size - size: 15; - // Anchors - anchors.top: marketplaceHeaderImage.bottom; - anchors.topMargin: 8; - anchors.left: parent.left; - anchors.leftMargin: 12; - anchors.right: parent.right; - height: paintedHeight; - // Style - color: hifi.colors.white; - } - RalewayRegular { - id: introText2; - text: "Inventory"; - // Text size - size: 22; - // Anchors - anchors.top: introText1.bottom; - anchors.left: parent.left; - anchors.leftMargin: 24; - anchors.right: parent.right; - height: paintedHeight; - // Style - color: hifi.colors.white; - } - } - - // - // "STEP 1" START - // - Item { - id: step_1; - visible: root.activeView === 1; - anchors.top: header.bottom; - anchors.topMargin: 100; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - - RalewayRegular { - id: step1text; - text: "The 'REZ IT' button makes your item appear in front of you."; - // Text size - size: 20; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - width: 180; - height: paintedHeight; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - } - - // "Next" button - HifiControlsUit.Button { - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: step1text.bottom; - anchors.topMargin: 16; - anchors.left: parent.left; - width: 150; - height: 40; - text: "Next"; - onClicked: { - root.activeView++; - } - } - - // "SKIP" button - HifiControlsUit.Button { - color: hifi.buttons.noneBorderlessGray; - colorScheme: hifi.colorSchemes.dark; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 32; - anchors.right: parent.right; - anchors.rightMargin: 16; - width: 150; - height: 40; - text: "SKIP"; - onClicked: { - sendSignalToParent({method: 'tutorial_finished'}); - } - } - } - // - // "STEP 1" END - // - - // - // "STEP 2" START - // - Item { - id: step_2; - visible: root.activeView === 2; - anchors.top: header.bottom; - anchors.topMargin: 45; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - - RalewayRegular { - id: step2text; - text: "If you rez an item twice, the first one will disappear."; - // Text size - size: 20; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - width: 180; - height: paintedHeight; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - } - - // "GOT IT" button - HifiControlsUit.Button { - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: step2text.bottom; - anchors.topMargin: 16; - anchors.left: parent.left; - width: 150; - height: 40; - text: "GOT IT"; - onClicked: { - sendSignalToParent({method: 'tutorial_finished'}); - } - } - } - // - // "STEP 2" END - // - - // - // FUNCTION DEFINITIONS START - // - signal sendSignalToParent(var message); - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/common/SortableListModel.qml b/interface/resources/qml/hifi/commerce/common/SortableListModel.qml deleted file mode 100644 index cfdd4abe047..00000000000 --- a/interface/resources/qml/hifi/commerce/common/SortableListModel.qml +++ /dev/null @@ -1,96 +0,0 @@ -// -// SortableListModel.qml -// qml/hifi/commerce/common -// -// SortableListModel -// -// Created by Zach Fox on 2017-09-28 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 - -ListModel { - id: root; - property string sortColumnName: ""; - property bool isSortingDescending: true; - property bool valuesAreNumerical: false; - - function swap(a, b) { - if (a < b) { - move(a, b, 1); - move(b - 1, a, 1); - } else if (a > b) { - move(b, a, 1); - move(a - 1, b, 1); - } - } - - function partition(begin, end, pivot) { - if (valuesAreNumerical) { - var piv = get(pivot)[sortColumnName]; - swap(pivot, end - 1); - var store = begin; - var i; - - for (i = begin; i < end - 1; ++i) { - var currentElement = get(i)[sortColumnName]; - if (isSortingDescending) { - if (currentElement > piv) { - swap(store, i); - ++store; - } - } else { - if (currentElement < piv) { - swap(store, i); - ++store; - } - } - } - swap(end - 1, store); - - return store; - } else { - var piv = get(pivot)[sortColumnName].toLowerCase(); - swap(pivot, end - 1); - var store = begin; - var i; - - for (i = begin; i < end - 1; ++i) { - var currentElement = get(i)[sortColumnName].toLowerCase(); - if (isSortingDescending) { - if (currentElement > piv) { - swap(store, i); - ++store; - } - } else { - if (currentElement < piv) { - swap(store, i); - ++store; - } - } - } - swap(end - 1, store); - - return store; - } - } - - function qsort(begin, end) { - if (end - 1 > begin) { - var pivot = begin + Math.floor(Math.random() * (end - begin)); - - pivot = partition(begin, end, pivot); - - qsort(begin, pivot); - qsort(pivot + 1, end); - } - } - - function quickSort() { - qsort(0, count) - } -} \ No newline at end of file diff --git a/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-1.jpg b/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-1.jpg deleted file mode 100644 index 5632467c32c..00000000000 Binary files a/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-1.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-2.jpg b/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-2.jpg deleted file mode 100644 index 38ebf08162a..00000000000 Binary files a/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-2.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/common/images/loader-blue.gif b/interface/resources/qml/hifi/commerce/common/images/loader-blue.gif deleted file mode 100644 index 8b9e17053b2..00000000000 Binary files a/interface/resources/qml/hifi/commerce/common/images/loader-blue.gif and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/common/images/loader.gif b/interface/resources/qml/hifi/commerce/common/images/loader.gif deleted file mode 100644 index 0536bd1884f..00000000000 Binary files a/interface/resources/qml/hifi/commerce/common/images/loader.gif and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/common/images/marketplaceHeaderImage.png b/interface/resources/qml/hifi/commerce/common/images/marketplaceHeaderImage.png deleted file mode 100644 index f49504c5396..00000000000 Binary files a/interface/resources/qml/hifi/commerce/common/images/marketplaceHeaderImage.png and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml deleted file mode 100644 index 1eb8af31e6d..00000000000 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml +++ /dev/null @@ -1,128 +0,0 @@ -// -// ConnectionItem.qml -// qml/hifi/commerce/common/sendAsset -// -// ConnectionItem -// -// Created by Zach Fox on 2018-01-09 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../../controls" as HifiControls -import "../../wallet" as HifiWallet - -Item { - HifiConstants { id: hifi; } - - id: root; - property bool isSelected: false; - property string userName; - property string profilePicUrl; - - height: 75; - width: parent.width; - - Rectangle { - id: mainContainer; - // Style - color: root.isSelected ? hifi.colors.faintGray80 : hifi.colors.white; - // Size - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: parent.top; - height: root.height; - - Item { - id: avatarImage; - visible: profilePicUrl !== "" && userName !== ""; - // Size - anchors.verticalCenter: parent.verticalCenter; - anchors.left: parent.left; - anchors.leftMargin: 36; - height: 50; - width: visible ? height : 0; - clip: true; - Image { - id: userImage; - source: root.profilePicUrl !== "" ? ((0 === root.profilePicUrl.indexOf("http")) ? - root.profilePicUrl : (Account.metaverseServerURL + root.profilePicUrl)) : ""; - mipmap: true; - // Anchors - anchors.fill: parent - layer.enabled: true - layer.effect: OpacityMask { - maskSource: Item { - width: userImage.width; - height: userImage.height; - Rectangle { - anchors.centerIn: parent; - width: userImage.width; // This works because userImage is square - height: width; - radius: width; - } - } - } - } - AnimatedImage { - source: "../../../../../icons/profilePicLoading.gif" - anchors.fill: parent; - visible: userImage.status != Image.Ready; - } - } - - RalewaySemiBold { - id: userName; - anchors.left: avatarImage.right; - anchors.leftMargin: 12; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.right: chooseButton.visible ? chooseButton.left : parent.right; - anchors.rightMargin: chooseButton.visible ? 10 : 0; - // Text size - size: 18; - // Style - color: hifi.colors.blueAccent; - text: root.userName; - elide: Text.ElideRight; - // Alignment - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignVCenter; - } - - // "Choose" button - HifiControlsUit.Button { - id: chooseButton; - visible: root.isSelected; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.verticalCenter: parent.verticalCenter; - anchors.right: parent.right; - anchors.rightMargin: 28; - height: 35; - width: 100; - text: "CHOOSE"; - onClicked: { - var msg = { method: 'chooseConnection', userName: root.userName, profilePicUrl: root.profilePicUrl }; - sendToParent(msg); - } - } - } - - // - // FUNCTION DEFINITIONS START - // - signal sendToParent(var msg); - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml deleted file mode 100644 index 10756957d35..00000000000 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml +++ /dev/null @@ -1,118 +0,0 @@ -// -// RecipientDisplay.qml -// qml/hifi/commerce/common/sendAsset -// -// RecipientDisplay -// -// Created by Zach Fox on 2018-01-11 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.6 -import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../../controls" as HifiControls -import "../" as HifiCommerceCommon - -Item { - HifiConstants { id: hifi; } - - id: root; - - // true when sending to 'nearby' or when a script raises the send asset dialog - property bool multiLineDisplay; - property string displayName; - property string userName; - property string profilePic; - property string textColor: hifi.colors.white; - - Item { - visible: root.multiLineDisplay; - anchors.fill: parent; - - RalewaySemiBold { - id: recipientDisplayName; - text: root.displayName; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.rightMargin: 12; - height: parent.height/2; - // Text size - size: 18; - // Style - color: root.textColor; - verticalAlignment: Text.AlignBottom; - elide: Text.ElideRight; - } - - RalewaySemiBold { - text: root.userName; - // Anchors - anchors.bottom: parent.bottom; - anchors.left: recipientDisplayName.anchors.left; - anchors.leftMargin: recipientDisplayName.anchors.leftMargin; - anchors.right: recipientDisplayName.anchors.right; - anchors.rightMargin: recipientDisplayName.anchors.rightMargin; - height: parent.height/2; - // Text size - size: 16; - // Style - color: root.textColor; - verticalAlignment: Text.AlignTop; - elide: Text.ElideRight; - } - } - - Item { - visible: !root.multiLineDisplay; - anchors.fill: parent; - - Image { - id: userImage; - source: root.profilePic; - mipmap: true; - // Anchors - anchors.left: parent.left; - anchors.verticalCenter: parent.verticalCenter; - height: parent.height - 36; - width: height; - layer.enabled: true; - layer.effect: OpacityMask { - maskSource: Item { - width: userImage.width; - height: userImage.height; - Rectangle { - anchors.centerIn: parent; - width: userImage.width; // This works because userImage is square - height: width; - radius: width; - } - } - } - } - - RalewaySemiBold { - text: root.userName; - // Anchors - anchors.left: userImage.right; - anchors.leftMargin: 8; - anchors.right: parent.right; - anchors.verticalCenter: parent.verticalCenter; - height: parent.height - 4; - // Text size - size: 16; - // Style - color: root.textColor; - verticalAlignment: Text.AlignVCenter; - elide: Text.ElideRight; - } - } -} diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml deleted file mode 100644 index e159344d5c9..00000000000 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml +++ /dev/null @@ -1,2269 +0,0 @@ -// -// SendAsset.qml -// qml/hifi/commerce/common/sendAsset -// -// SendAsset -// -// Created by Zach Fox on 2018-01-09 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.6 -import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../../controls" as HifiControls -import "../" as HifiCommerceCommon -import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. - -Item { - HifiConstants { id: hifi; } - - id: root; - property int parentAppTitleBarHeight; - property int parentAppNavBarHeight; - property string currentActiveView: "sendAssetHome"; - property string nextActiveView: ""; - property bool shouldShowTopAndBottomOfParent: chooseRecipientConnection.visible || - chooseRecipientNearby.visible || paymentSuccess.visible || paymentFailure.visible; - property bool shouldShowTopOfParent: sendAssetStep.visible; - property bool isCurrentlySendingAsset: false; - property string assetName: ""; - property string assetCertID: ""; - property string couponID: ""; - property string authorizationID: ""; - property string sendingPubliclyEffectImage; - property var http; - property var listModelName; - property var keyboardContainer; - - // This object is always used in a popup or full-screen Wallet section. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup/section. - MouseArea { - x: 0; - y: (root.shouldShowTopAndBottomOfParent && !root.shouldShowTopOfParent) ? 0 : root.parentAppTitleBarHeight; - width: parent.width; - height: (root.shouldShowTopAndBottomOfParent || root.shouldShowTopOfParent) ? parent.height : parent.height - root.parentAppTitleBarHeight - root.parentAppNavBarHeight; - propagateComposedEvents: false; - hoverEnabled: true; - } - - // Background - Rectangle { - z: 1; - visible: root.assetCertID !== "" && sendAssetStep.referrer !== "payIn" && sendAssetStep.visible; - anchors.top: parent.top; - anchors.topMargin: root.parentAppTitleBarHeight; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - color: hifi.colors.white; - } - - Connections { - target: Commerce; - - onBalanceResult : { - balanceText.text = result.data.balance; - sendButton.enabled = true; - } - - onTransferAssetToNodeResult: { - if (!root.visible) { - return; - } - - root.isCurrentlySendingAsset = false; - - if (result.status === 'success') { - root.nextActiveView = 'paymentSuccess'; - if (sendPubliclyCheckbox.checked && sendAssetStep.referrer === "nearby") { - sendSignalToParent({ - method: 'sendAsset_sendPublicly', - recipient: sendAssetStep.selectedRecipientNodeID, - amount: parseInt(amountTextField.text), - effectImage: root.sendingPubliclyEffectImage - }); - } - } else { - root.nextActiveView = 'paymentFailure'; - } - } - - onTransferAssetToUsernameResult: { - if (!root.visible) { - return; - } - - root.isCurrentlySendingAsset = false; - - if (result.status === 'success') { - root.nextActiveView = 'paymentSuccess'; - } else { - root.nextActiveView = 'paymentFailure'; - } - } - - onAuthorizeAssetTransferResult: { - if (!root.visible) { - return; - } - - root.isCurrentlySendingAsset = false; - - if (result.status === 'success') { - root.authorizationID = result.data.authorization_id; - authorizationIDText.text = root.authorizationID; - root.couponID = result.data.coupon_id; - couponIDText.text = root.couponID - if (couponIDTextField.text !== root.couponID) { - console.log("SendAsset: Returned coupon ID doesn't match client-generated coupon ID!"); - } - root.nextActiveView = 'paymentSuccess'; - } else { - root.nextActiveView = 'paymentFailure'; - } - } - - onCertificateInfoResult: { - if (result.status !== 'success') { - console.log("Failed to get certificate info", result.data.message); - } else { - root.assetName = result.data.marketplace_item_name; - } - } - } - - Connections { - target: GlobalServices - onMyUsernameChanged: { - usernameText.text = Account.username; - } - } - - Component.onCompleted: { - Commerce.balance(); - } - - onNextActiveViewChanged: { - if (root.currentActiveView === 'chooseRecipientNearby') { - sendSignalToParent({method: 'disable_ChooseRecipientNearbyMode'}); - } - - root.currentActiveView = root.nextActiveView; - - if (root.currentActiveView === 'chooseRecipientConnection') { - // Refresh connections model - connectionsModel.getFirstPage(); - } else if (root.currentActiveView === 'sendAssetHome') { - Commerce.balance(); - } else if (root.currentActiveView === 'chooseRecipientNearby') { - sendSignalToParent({method: 'enable_ChooseRecipientNearbyMode'}); - } - } - - HifiCommerceCommon.CommerceLightbox { - id: lightboxPopup; - visible: false; - anchors.fill: parent; - } - - // Send Asset Home BEGIN - Item { - id: sendAssetHome; - z: 996; - visible: root.currentActiveView === "sendAssetHome" || root.currentActiveView === "chooseRecipientConnection" || root.currentActiveView === "chooseRecipientNearby"; - anchors.fill: parent; - anchors.topMargin: root.parentAppTitleBarHeight; - anchors.bottomMargin: root.parentAppNavBarHeight; - - Item { - id: userInfoContainer; - visible: root.assetCertID === ""; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - height: 160; - - // Username Text - RalewayRegular { - id: usernameText; - text: Account.username; - // Text size - size: 24; - // Style - color: hifi.colors.white; - elide: Text.ElideRight; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: parent.width/2; - height: 80; - } - - // HFC Balance Container - Item { - id: hfcBalanceContainer; - // Anchors - anchors.top: parent.top; - anchors.right: parent.right; - anchors.leftMargin: 20; - width: parent.width/2; - height: 80; - - // "HFC" balance label - HiFiGlyphs { - id: balanceLabel; - text: hifi.glyphs.hfc; - // Size - size: 40; - // Anchors - anchors.left: parent.left; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - // Style - color: hifi.colors.white; - } - - // Balance Text - FiraSansRegular { - id: balanceText; - text: "--"; - // Text size - size: 28; - // Anchors - anchors.top: balanceLabel.top; - anchors.bottom: balanceLabel.bottom; - anchors.left: balanceLabel.right; - anchors.leftMargin: 10; - anchors.right: parent.right; - anchors.rightMargin: 4; - // Style - color: hifi.colors.white; - // Alignment - verticalAlignment: Text.AlignVCenter; - } - - // "balance" text below field - RalewayRegular { - text: "BALANCE (HFC)"; - // Text size - size: 14; - // Anchors - anchors.top: balanceLabel.top; - anchors.topMargin: balanceText.paintedHeight + 20; - anchors.bottom: balanceLabel.bottom; - anchors.left: balanceText.left; - anchors.right: balanceText.right; - height: paintedHeight; - // Style - color: hifi.colors.white; - } - } - } - - // Send Asset - Rectangle { - id: sendAssetContainer; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - anchors.top: userInfoContainer.visible ? undefined : parent.top; - height: userInfoContainer.visible ? 440 : undefined; - color: hifi.colors.white; - - LinearGradient { - anchors.fill: parent; - visible: root.assetCertID === ""; - start: Qt.point(0, 0); - end: Qt.point(0, height); - gradient: Gradient { - GradientStop { position: 0.0; color: hifi.colors.white } - GradientStop { position: 1.0; color: hifi.colors.faintGray } - } - } - - RalewaySemiBold { - id: sendAssetText; - text: root.assetCertID === "" ? "Send Money To:" : "Send \"" + root.assetName + "\" To:"; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 26; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - elide: Text.ElideRight; - height: 30; - // Text size - size: 22; - // Style - color: hifi.colors.baseGray; - } - - Item { - id: connectionButton; - // Anchors - anchors.top: sendAssetText.bottom; - anchors.topMargin: 40; - anchors.left: parent.left; - anchors.leftMargin: 75; - height: 95; - width: 95; - - Image { - anchors.top: parent.top; - source: "./images/connection.svg"; - height: 70; - width: parent.width; - fillMode: Image.PreserveAspectFit; - horizontalAlignment: Image.AlignHCenter; - verticalAlignment: Image.AlignTop; - mipmap: true; - } - - RalewaySemiBold { - text: "Connection"; - // Anchors - anchors.bottom: parent.bottom; - height: 15; - width: parent.width; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - horizontalAlignment: Text.AlignHCenter; - } - - MouseArea { - anchors.fill: parent; - onClicked: { - root.nextActiveView = "chooseRecipientConnection"; - filterBar.text = ""; - } - } - } - - Item { - id: nearbyButton; - // Anchors - anchors.top: sendAssetText.bottom; - anchors.topMargin: connectionButton.anchors.topMargin; - anchors.right: parent.right; - anchors.rightMargin: connectionButton.anchors.leftMargin; - height: connectionButton.height; - width: connectionButton.width; - - Image { - anchors.top: parent.top; - source: "./images/nearby.svg"; - height: 70; - width: parent.width; - fillMode: Image.PreserveAspectFit; - horizontalAlignment: Image.AlignHCenter; - verticalAlignment: Image.AlignTop; - mipmap: true; - } - - RalewaySemiBold { - text: "Someone Nearby"; - // Anchors - anchors.bottom: parent.bottom; - height: 15; - width: parent.width; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - horizontalAlignment: Text.AlignHCenter; - } - - MouseArea { - anchors.fill: parent; - onClicked: { - root.nextActiveView = "chooseRecipientNearby"; - } - } - } - - Item { - id: createCouponButton; - // Anchors - anchors.top: nearbyButton.bottom; - anchors.topMargin: 32; - anchors.horizontalCenter: parent.horizontalCenter; - height: connectionButton.height; - width: connectionButton.width; - - Image { - anchors.top: parent.top; - source: "./images/coupon.svg"; - height: 70; - width: parent.width; - fillMode: Image.PreserveAspectFit; - horizontalAlignment: Image.AlignHCenter; - verticalAlignment: Image.AlignTop; - mipmap: true; - } - - RalewaySemiBold { - text: "Create Coupon"; - // Anchors - anchors.bottom: parent.bottom; - height: 15; - width: parent.width; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - horizontalAlignment: Text.AlignHCenter; - } - - MouseArea { - anchors.fill: parent; - onClicked: { - sendAssetStep.referrer = "createCoupon"; - sendAssetStep.selectedRecipientNodeID = ""; - couponIDTextField.text = generateRandomCouponID(); - - root.nextActiveView = "sendAssetStep"; - } - } - } - - HifiControlsUit.Button { - id: backButton_sendAssetHome; - visible: parentAppNavBarHeight === 0; - color: hifi.buttons.white; - colorScheme: hifi.colorSchemes.light; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 40; - height: 40; - text: "BACK"; - onClicked: { - resetSendAssetData(); - sendSignalToParent({method: 'sendAssetHome_back'}); - } - } - } - } - // Send Asset Home END - - // Choose Recipient Connection BEGIN - Rectangle { - id: chooseRecipientConnection; - z: 997; - visible: root.currentActiveView === "chooseRecipientConnection"; - anchors.fill: parent; - color: "#80000000"; - - // This object is always used in a popup or full-screen Wallet section. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup/section. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - HifiModels.PSFListModel { - id: connectionsModel; - http: root.http; - listModelName: root.listModelName || ""; - endpoint: "/api/v1/users?filter=connections"; - itemsPerPage: 9; - listView: connectionsList; - processPage: function (data) { - return data.users; - }; - searchFilter: filterBar.text; - } - - Rectangle { - anchors.centerIn: parent; - width: parent.width - 30; - height: parent.height - 30; - color: "#FFFFFF"; - radius: 8; - - RalewaySemiBold { - id: chooseRecipientText_connections; - text: "Choose Recipient:"; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 26; - anchors.left: parent.left; - anchors.leftMargin: 36; - width: paintedWidth; - height: 30; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - } - - HiFiGlyphs { - id: closeGlyphButton_connections; - text: hifi.glyphs.close; - color: root.assetCertID === "" ? hifi.colors.lightGrayText : hifi.colors.baseGray; - size: 26; - anchors.top: parent.top; - anchors.topMargin: 10; - anchors.right: parent.right; - anchors.rightMargin: 10; - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - onEntered: { - parent.text = hifi.glyphs.closeInverted; - } - onExited: { - parent.text = hifi.glyphs.close; - } - onClicked: { - root.nextActiveView = "sendAssetHome"; - } - } - } - - // - // FILTER BAR START - // - Item { - id: filterBarContainer; - visible: !connectionInstructions.visible; - // Size - height: 40; - // Anchors - anchors.left: parent.left; - anchors.leftMargin: 36; - anchors.right: parent.right; - anchors.rightMargin: 16; - anchors.top: chooseRecipientText_connections.bottom; - anchors.topMargin: 12; - - HifiControlsUit.TextField { - id: filterBar; - colorScheme: hifi.colorSchemes.faintGray; - hasClearButton: true; - hasRoundedBorder: true; - hasDefocusedBorder: false; - roundedBorderRadius: filterBar.height/2; - anchors.fill: parent; - centerPlaceholderGlyph: hifi.glyphs.search; - - onAccepted: { - focus = false; - } - } - } - // - // FILTER BAR END - // - - Item { - id: connectionsContainer; - anchors.top: filterBarContainer.bottom; - anchors.topMargin: 16; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - - AnimatedImage { - id: connectionsLoading; - visible: !connectionsModel.retrievedAtLeastOnePage; - source: "../../../../../icons/profilePicLoading.gif" - width: 120; - height: width; - anchors.top: parent.top; - anchors.topMargin: 185; - anchors.horizontalCenter: parent.horizontalCenter; - } - - ListView { - id: connectionsList; - ScrollBar.vertical: ScrollBar { - policy: connectionsList.contentHeight > parent.parent.height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded; - parent: connectionsList.parent; - anchors.top: connectionsList.top; - anchors.right: connectionsList.right; - anchors.bottom: connectionsList.bottom; - width: 20; - } - visible: !connectionsLoading.visible; - clip: true; - model: connectionsModel; - snapMode: ListView.SnapToItem; - // Anchors - anchors.fill: parent; - delegate: ConnectionItem { - isSelected: connectionsList.currentIndex === index; - userName: model.username; - profilePicUrl: model.images.thumbnail; - anchors.topMargin: 6; - anchors.bottomMargin: 6; - - Connections { - onSendToParent: { - sendAssetStep.referrer = "connections"; - sendAssetStep.selectedRecipientNodeID = ''; - sendAssetStep.selectedRecipientDisplayName = 'connection'; - sendAssetStep.selectedRecipientUserName = msg.userName; - sendAssetStep.selectedRecipientProfilePic = msg.profilePicUrl; - - root.nextActiveView = "sendAssetStep"; - } - } - - MouseArea { - enabled: connectionsList.currentIndex !== index; - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - onClicked: { - connectionsList.currentIndex = index; - } - } - } - } - - // "Make a Connection" instructions - Rectangle { - id: connectionInstructions; - visible: connectionsModel.count === 0 && !connectionsModel.searchFilter && !connectionsLoading.visible; - anchors.fill: parent; - color: "white"; - - RalewayRegular { - id: makeAConnectionText; - // Properties - text: "Make a Connection"; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 20; - anchors.left: parent.left; - anchors.right: parent.right; - // Text Size - size: 24; - // Text Positioning - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter; - // Style - color: hifi.colors.darkGray; - } - - Image { - id: connectionImage; - source: "qrc:/icons/connection.svg"; - width: 150; - height: 150; - mipmap: true; - // Anchors - anchors.top: makeAConnectionText.bottom; - anchors.topMargin: 15; - anchors.horizontalCenter: parent.horizontalCenter; - } - - FontLoader { id: ralewayRegular; source: "qrc:/fonts/Raleway-Regular.ttf"; } - Text { - id: connectionHelpText; - // Anchors - anchors.top: connectionImage.bottom; - anchors.topMargin: 15; - anchors.left: parent.left - anchors.leftMargin: 40; - anchors.right: parent.right - anchors.rightMargin: 40; - // Text alignment - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHLeft - // Style - font.pixelSize: 18; - font.family: ralewayRegular.name - color: hifi.colors.darkGray; - wrapMode: Text.Wrap - textFormat: Text.StyledText; - property string instructions: - "When you meet someone you want to remember later, you can connect with a handshake:

" - property string hmdMountedInstructions: - "1. Put your hand out onto their hand and squeeze your controller's grip button on its side.
" + - "2. Once the other person puts their hand onto yours, you'll see your connection form.
" + - "3. After about 3 seconds, you're connected!" - property string hmdNotMountedInstructions: - "1. Press and hold the 'x' key to extend your arm.
" + - "2. Once the other person puts their hand onto yours, you'll see your connection form.
" + - "3. After about 3 seconds, you're connected!"; - // Text - text: - HMD.mounted ? instructions + hmdMountedInstructions : instructions + hmdNotMountedInstructions - } - } - } - } - } - // Choose Recipient Connection END - - // Choose Recipient Nearby BEGIN - Rectangle { - id: chooseRecipientNearby; - z: 997; - color: "#80000000"; - - property string selectedRecipient; - - visible: root.currentActiveView === "chooseRecipientNearby"; - anchors.fill: parent; - - // This object is always used in a popup or full-screen Wallet section. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup/section. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - Rectangle { - anchors.centerIn: parent; - width: parent.width - 30; - height: parent.height - 30; - color: "#FFFFFF"; - radius: 8; - - RalewaySemiBold { - text: "Choose Recipient:"; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 26; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: paintedWidth; - height: 30; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - } - - HiFiGlyphs { - id: closeGlyphButton_nearby; - text: hifi.glyphs.close; - color: root.assetCertID === "" ? hifi.colors.lightGrayText : hifi.colors.baseGray; - size: 26; - anchors.top: parent.top; - anchors.topMargin: 10; - anchors.right: parent.right; - anchors.rightMargin: 10; - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - onEntered: { - parent.text = hifi.glyphs.closeInverted; - } - onExited: { - parent.text = hifi.glyphs.close; - } - onClicked: { - root.nextActiveView = "sendAssetHome"; - resetSendAssetData(); - } - } - } - - RalewaySemiBold { - id: selectionInstructions; - text: chooseRecipientNearby.selectedRecipient === "" ? "Trigger or click on\nsomeone nearby to select them" : - "Trigger or click on\nsomeone else to select again"; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 100; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: anchors.leftMargin; - height: paintedHeight; - // Text size - size: 20; - // Style - color: hifi.colors.baseGray; - horizontalAlignment: Text.AlignHCenter; - wrapMode: Text.Wrap; - } - - Image { - anchors.top: selectionInstructions.bottom; - anchors.topMargin: 20; - anchors.bottom: selectionMadeContainer.top; - anchors.bottomMargin: 30; - source: "./images/p2p-nearby-unselected.svg"; - width: parent.width; - fillMode: Image.PreserveAspectFit; - horizontalAlignment: Image.AlignHCenter; - verticalAlignment: Image.AlignVCenter; - mipmap: true; - } - - Rectangle { - id: selectionMadeContainer; - visible: chooseRecipientNearby.selectedRecipient !== ""; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - height: 190; - color: "#F3F3F3"; - radius: 8; - - // Used to square off the top left and top right edges of this container - Rectangle { - color: "#F3F3F3"; - height: selectionMadeContainer.radius; - anchors.top: selectionMadeContainer.top; - anchors.left: selectionMadeContainer.left; - anchors.right: selectionMadeContainer.right; - } - - RalewaySemiBold { - id: sendToText; - text: root.assetCertID === "" ? "Send to:" : "Gift to:"; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 36; - anchors.left: parent.left; - anchors.leftMargin: 36; - width: paintedWidth; - height: paintedHeight; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - } - - Image { - id: selectedImage; - anchors.top: parent.top; - anchors.topMargin: 24; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 32; - anchors.left: sendToText.right; - anchors.leftMargin: 4; - source: "./images/p2p-nearby-selected.svg"; - width: 50; - fillMode: Image.PreserveAspectFit; - horizontalAlignment: Image.AlignHCenter; - verticalAlignment: Image.AlignVCenter; - mipmap: true; - } - - RalewaySemiBold { - id: avatarDisplayName; - text: '"' + AvatarList.getAvatar(chooseRecipientNearby.selectedRecipient).sessionDisplayName + '"'; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 34; - anchors.left: selectedImage.right; - anchors.leftMargin: 10; - anchors.right: parent.right; - anchors.rightMargin: 10; - height: paintedHeight; - // Text size - size: 20; - // Style - color: hifi.colors.blueAccent; - } - - RalewaySemiBold { - id: avatarUserName; - text: sendAssetStep.selectedRecipientUserName; - // Anchors - anchors.top: avatarDisplayName.bottom; - anchors.topMargin: 16; - anchors.left: selectedImage.right; - anchors.leftMargin: 10; - anchors.right: parent.right; - anchors.rightMargin: 10; - height: paintedHeight; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - } - - // "CHOOSE" button - HifiControlsUit.Button { - id: chooseButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.horizontalCenter: parent.horizontalCenter; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 20; - height: 40; - width: 110; - text: "CHOOSE"; - onClicked: { - sendAssetStep.referrer = "nearby"; - sendAssetStep.selectedRecipientNodeID = chooseRecipientNearby.selectedRecipient; - chooseRecipientNearby.selectedRecipient = ""; - - root.nextActiveView = "sendAssetStep"; - } - } - } - } - } - // Choose Recipient Nearby END - - // Send Asset Screen BEGIN - Item { - id: sendAssetStep; - z: 996; - - property string referrer; // either "connections", "nearby", "payIn", or "createCoupon" - property string selectedRecipientNodeID; - property string selectedRecipientDisplayName; - property string selectedRecipientUserName; - property string selectedRecipientProfilePic; - - visible: root.currentActiveView === "sendAssetStep" || paymentSuccess.visible || paymentFailure.visible; - anchors.fill: parent; - anchors.topMargin: root.parentAppTitleBarHeight; - - RalewaySemiBold { - id: sendAssetText_sendAssetStep; - text: ((sendAssetStep.referrer === "payIn" || sendAssetStep.referrer === "createCoupon") && - root.assetCertID !== "") ? "Send \"" + root.assetName + "\":" : - (root.assetCertID === "" ? "Send Money To:" : "Gift \"" + root.assetName + "\" To:"); - // Anchors - anchors.top: parent.top; - anchors.topMargin: 26; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - elide: Text.ElideRight; - height: 30; - // Text size - size: 22; - // Style - color: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colors.white : hifi.colors.black; - } - - Item { - id: sendToContainer; - anchors.top: sendAssetText_sendAssetStep.bottom; - anchors.topMargin: 20; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 80; - - RalewaySemiBold { - id: sendToText_sendAssetStep; - text: sendAssetStep.referrer === "createCoupon" ? "Coupon ID:" : - (root.assetCertID === "" || sendAssetStep.referrer === "payIn") ? "Send to:" : "Gift to:"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: paintedWidth; - // Text size - size: 18; - // Style - color: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colors.white : hifi.colors.black; - verticalAlignment: Text.AlignVCenter; - } - - RecipientDisplay { - visible: sendAssetStep.referrer !== "createCoupon"; - anchors.top: parent.top; - anchors.left: sendToText_sendAssetStep.right; - anchors.leftMargin: 16; - anchors.right: changeButton.left; - anchors.rightMargin: 12; - height: parent.height; - textColor: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colors.white : hifi.colors.black; - - displayName: sendAssetStep.selectedRecipientDisplayName; - userName: sendAssetStep.selectedRecipientUserName; - profilePic: sendAssetStep.selectedRecipientProfilePic !== "" ? ((0 === sendAssetStep.selectedRecipientProfilePic.indexOf("http")) ? - sendAssetStep.selectedRecipientProfilePic : (Account.metaverseServerURL + sendAssetStep.selectedRecipientProfilePic)) : ""; - multiLineDisplay: sendAssetStep.referrer === "nearby" || sendAssetStep.referrer === "payIn"; - } - - Item { - id: couponIDContainer; - visible: sendAssetStep.referrer === "createCoupon"; - anchors.top: parent.top; - anchors.left: sendToText_sendAssetStep.right; - anchors.right: parent.right; - height: parent.height; - - RalewaySemiBold { - id: couponIDHelp; - text: "[?]"; - // Anchors - anchors.left: parent.left; - anchors.leftMargin: 8; - anchors.verticalCenter: parent.verticalCenter; - height: 30; - width: paintedWidth; - // Text size - size: 18; - // Style - color: hifi.colors.blueAccent; - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - onEntered: { - parent.color = hifi.colors.blueHighlight; - } - onExited: { - parent.color = hifi.colors.blueAccent; - } - onClicked: { - lightboxPopup.titleText = "Coupon ID"; - lightboxPopup.bodyText = "This alphanumeric text string will be used to ensure " + - "that only you can redeem the coupon for the asset that you are sending. Keep it private!"; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } - } - } - - HifiControlsUit.TextField { - id: couponIDTextField; - colorScheme: root.assetCertID === "" ? hifi.colorSchemes.dark : hifi.colorSchemes.light; - // Anchors - anchors.verticalCenter: parent.verticalCenter; - anchors.left: couponIDHelp.right; - anchors.leftMargin: 16; - anchors.right: parent.right; - height: 50; - // Style - activeFocusOnPress: true; - activeFocusOnTab: true; - - onAccepted: { - optionalMessage.focus = true; - } - } - } - - // "CHANGE" button - HifiControlsUit.Button { - id: changeButton; - color: root.assetCertID === "" ? hifi.buttons.none : hifi.buttons.white; - colorScheme: hifi.colorSchemes.dark; - anchors.right: parent.right; - anchors.verticalCenter: parent.verticalCenter; - height: 35; - width: 100; - text: "CHANGE"; - visible: sendAssetStep.referrer !== "payIn" && sendAssetStep.referrer !== "createCoupon"; - onClicked: { - if (sendAssetStep.referrer === "connections") { - root.nextActiveView = "chooseRecipientConnection"; - } else if (sendAssetStep.referrer === "nearby") { - root.nextActiveView = "chooseRecipientNearby"; - } - resetSendAssetData(); - } - } - } - - Item { - id: amountContainer; - visible: root.assetCertID === ""; - anchors.top: sendToContainer.bottom; - anchors.topMargin: 2; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 80; - - RalewaySemiBold { - id: amountText; - text: "Amount:"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: 90; - // Text size - size: 18; - // Style - color: hifi.colors.white; - verticalAlignment: Text.AlignVCenter; - } - - HifiControlsUit.TextField { - id: amountTextField; - readOnly: sendAssetStep.referrer === "payIn"; - text: root.assetCertID === "" ? "" : "1"; - colorScheme: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colorSchemes.dark : hifi.colorSchemes.light; - inputMethodHints: Qt.ImhDigitsOnly; - // Anchors - anchors.verticalCenter: parent.verticalCenter; - anchors.left: amountText.right; - anchors.right: parent.right; - height: 50; - // Style - leftPermanentGlyph: hifi.glyphs.hfc; - activeFocusOnPress: !amountTextField.readOnly; - activeFocusOnTab: !amountTextField.readOnly; - - validator: IntValidator { bottom: 0; } - - onAccepted: { - optionalMessage.focus = true; - } - } - - FiraSansSemiBold { - visible: amountTextFieldError.text === ""; - text: "Balance: "; - // Anchors - anchors.top: amountTextField.bottom; - anchors.topMargin: 2; - anchors.left: amountTextField.left; - anchors.right: sendAssetBalanceText_HFC.left; - width: paintedWidth; - height: 40; - // Text size - size: 16; - // Style - color: hifi.colors.lightGrayText; - verticalAlignment: Text.AlignTop; - horizontalAlignment: Text.AlignRight; - } - HiFiGlyphs { - id: sendAssetBalanceText_HFC; - visible: amountTextFieldError.text === ""; - text: hifi.glyphs.hfc; - // Size - size: 16; - // Anchors - anchors.top: amountTextField.bottom; - anchors.topMargin: 2; - anchors.right: sendAssetBalanceText.left; - width: paintedWidth; - height: 40; - // Style - color: hifi.colors.lightGrayText; - verticalAlignment: Text.AlignTop; - horizontalAlignment: Text.AlignRight; - } - FiraSansSemiBold { - id: sendAssetBalanceText; - visible: amountTextFieldError.text === ""; - text: balanceText.text; - // Anchors - anchors.top: amountTextField.bottom; - anchors.topMargin: 2; - anchors.right: amountTextField.right; - width: paintedWidth; - height: 40; - // Text size - size: 16; - // Style - color: hifi.colors.lightGrayText; - verticalAlignment: Text.AlignTop; - horizontalAlignment: Text.AlignRight; - } - - RalewaySemiBold { - id: amountTextFieldError; - // Anchors - anchors.top: amountTextField.bottom; - anchors.topMargin: 2; - anchors.left: amountTextField.left; - anchors.right: amountTextField.right; - height: 40; - // Text size - size: 16; - // Style - color: hifi.colors.white; - verticalAlignment: Text.AlignTop; - horizontalAlignment: Text.AlignRight; - } - } - - Item { - id: messageContainer; - anchors.top: amountContainer.visible ? amountContainer.bottom : sendToContainer.bottom; - anchors.topMargin: 16; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 95; - - TextArea { - id: optionalMessage; - readOnly: sendAssetStep.referrer === "payIn"; - property int maximumLength: 72; - property string previousText: text; - placeholderText: "Optional Public Message (" + maximumLength + " character limit)"; - font.family: "Fira Sans SemiBold"; - font.pixelSize: 20; - // Anchors - anchors.fill: parent; - // Style - background: Rectangle { - anchors.fill: parent; - color: (root.assetCertID === "" || sendAssetStep.referrer === "payIn") ? - (optionalMessage.activeFocus && !optionalMessage.readOnly ? hifi.colors.black : hifi.colors.baseGrayShadow) : - (optionalMessage.activeFocus ? "#EFEFEF" : "#EEEEEE"); - border.width: optionalMessage.activeFocus && !optionalMessage.readOnly ? 1 : 0; - border.color: optionalMessage.activeFocus && !optionalMessage.readOnly ? hifi.colors.primaryHighlight : hifi.colors.textFieldLightBackground; - } - color: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colors.white : hifi.colors.black; - textFormat: TextEdit.PlainText; - wrapMode: TextEdit.Wrap; - activeFocusOnPress: true; - activeFocusOnTab: true; - onTextChanged: { - // Don't allow tabs or newlines - if ((/[\n\r\t]/g).test(text)) { - var cursor = cursorPosition; - text = text.replace(/[\n\r\t]/g, ''); - cursorPosition = cursor-1; - } - // Workaround for no max length on TextAreas - if (text.length > maximumLength) { - var cursor = cursorPosition; - text = previousText; - if (cursor > text.length) { - cursorPosition = text.length; - } else { - cursorPosition = cursor-1; - } - } - previousText = text; - } - } - FiraSansSemiBold { - id: optionalMessageCharacterCount; - text: optionalMessage.text.length + "/" + optionalMessage.maximumLength; - // Anchors - anchors.top: optionalMessage.bottom; - anchors.topMargin: 4; - anchors.right: optionalMessage.right; - height: paintedHeight; - // Text size - size: 16; - // Style - color: optionalMessage.text.length === optionalMessage.maximumLength ? "#ea89a5" : - (root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight); - verticalAlignment: Text.AlignTop; - horizontalAlignment: Text.AlignRight; - } - } - - HifiControlsUit.CheckBox { - id: sendPubliclyCheckbox; - visible: sendAssetStep.referrer === "nearby"; - checked: Settings.getValue("sendAssetsNearbyPublicly", true); - text: "Show Effect" - // Anchors - anchors.verticalCenter: bottomBarContainer.verticalCenter; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: 130; - boxSize: 28; - onCheckedChanged: { - Settings.setValue("sendAssetsNearbyPublicly", checked); - } - } - RalewaySemiBold { - id: sendPubliclyCheckboxHelp; - visible: sendPubliclyCheckbox.visible; - text: "[?]"; - // Anchors - anchors.left: sendPubliclyCheckbox.right; - anchors.verticalCenter: sendPubliclyCheckbox.verticalCenter; - height: 30; - width: paintedWidth; - // Text size - size: 18; - // Style - color: hifi.colors.blueAccent; - MouseArea { - enabled: sendPubliclyCheckboxHelp.visible; - anchors.fill: parent; - hoverEnabled: true; - onEntered: { - parent.color = hifi.colors.blueHighlight; - } - onExited: { - parent.color = hifi.colors.blueAccent; - } - onClicked: { - lightboxPopup.titleText = (root.assetCertID === "" ? "Send Effect" : "Gift Effect"); - lightboxPopup.bodyImageSource = "sendAsset/images/send-money-effect-sm.jpg"; // Path relative to CommerceLightbox.qml - lightboxPopup.bodyText = "Enabling this option will create a particle effect between you and " + - "your recipient that is visible to everyone nearby."; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - if (keyboardContainer) { - keyboardContainer.keyboardRaised = false; - } - } - } - } - - Item { - id: bottomBarContainer; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - anchors.top: messageContainer.bottom; - anchors.topMargin: 20; - height: 60; - - // "CANCEL" button - HifiControlsUit.Button { - id: cancelButton_sendAssetStep; - color: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.buttons.noneBorderlessWhite : hifi.buttons.noneBorderlessGray; - colorScheme: hifi.colorSchemes.dark; - anchors.right: sendButton.left; - anchors.rightMargin: 24; - anchors.verticalCenter: parent.verticalCenter; - height: 40; - width: 100; - text: "CANCEL"; - onClicked: { - if (sendAssetStep.referrer === "payIn") { - sendToScript({method: "closeSendAsset"}); - } else { - resetSendAssetData(); - root.nextActiveView = "sendAssetHome"; - } - } - } - - // "SEND" button - HifiControlsUit.Button { - id: sendButton; - color: hifi.buttons.blue; - colorScheme: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colorSchemes.dark : hifi.colorSchemes.light; - anchors.right: parent.right; - anchors.rightMargin: 0; - anchors.verticalCenter: parent.verticalCenter; - height: 40; - width: 100; - text: "SUBMIT"; - enabled: false; - onClicked: { - if (root.assetCertID === "" && parseInt(amountTextField.text) > parseInt(balanceText.text)) { - amountTextField.focus = true; - amountTextField.error = true; - amountTextFieldError.text = "amount exceeds available funds"; - } else if (root.assetCertID === "" && (amountTextField.text === "" || parseInt(amountTextField.text) < 1)) { - amountTextField.focus = true; - amountTextField.error = true; - amountTextFieldError.text = "invalid amount"; - } else { - amountTextFieldError.text = ""; - amountTextField.error = false; - root.isCurrentlySendingAsset = true; - amountTextField.focus = false; - optionalMessage.focus = false; - if (sendAssetStep.referrer === "connections" || sendAssetStep.referrer === "payIn") { - Commerce.transferAssetToUsername(sendAssetStep.selectedRecipientUserName, - root.assetCertID, - parseInt(amountTextField.text), - optionalMessage.text); - } else if (sendAssetStep.referrer === "nearby") { - Commerce.transferAssetToNode(sendAssetStep.selectedRecipientNodeID, - root.assetCertID, - parseInt(amountTextField.text), - optionalMessage.text); - } else if (sendAssetStep.referrer === "createCoupon") { - Commerce.authorizeAssetTransfer(couponIDTextField.text || "", - root.assetCertID, - parseInt(amountTextField.text) || 1, - optionalMessage.text) - } - } - } - } - } - } - // Send Asset Screen END - - // Sending Asset Overlay START - Rectangle { - id: sendingAssetOverlay; - z: 999; - - visible: root.isCurrentlySendingAsset; - anchors.fill: parent; - color: Qt.rgba(0.0, 0.0, 0.0, 0.8); - - // This object is always used in a popup or full-screen Wallet section. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup/section. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - AnimatedImage { - id: sendingAssetImage; - source: "../../common/images/loader.gif" - width: 96; - height: width; - anchors.verticalCenter: parent.verticalCenter; - anchors.horizontalCenter: parent.horizontalCenter; - } - - RalewaySemiBold { - text: "Sending"; - // Anchors - anchors.top: sendingAssetImage.bottom; - anchors.topMargin: 4; - anchors.horizontalCenter: parent.horizontalCenter; - width: paintedWidth; - // Text size - size: 26; - // Style - color: hifi.colors.white; - verticalAlignment: Text.AlignVCenter; - } - } - // Sending Asset Overlay END - - // Payment Success BEGIN - Rectangle { - id: paymentSuccess; - z: 998; - - visible: root.currentActiveView === "paymentSuccess"; - anchors.fill: parent; - color: Qt.rgba(0.0, 0.0, 0.0, 0.8); - - // This object is always used in a popup or full-screen Wallet section. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup/section. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - Rectangle { - anchors.top: parent.top; - anchors.topMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" || - sendAssetStep.referrer === "createCoupon" ? 15 : 125; - anchors.left: parent.left; - anchors.leftMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" || - sendAssetStep.referrer === "createCoupon" ? 15 : 50; - anchors.right: parent.right; - anchors.rightMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" || - sendAssetStep.referrer === "createCoupon" ? 15 : 50; - anchors.bottom: parent.bottom; - anchors.bottomMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" || - sendAssetStep.referrer === "createCoupon" ? 15 : 125; - color: "#FFFFFF"; - - RalewaySemiBold { - id: paymentSentText; - text: root.assetCertID === "" ? (sendAssetStep.referrer === "createCoupon" ? "Payment Authorized" : "Payment Sent") : - (sendAssetStep.referrer === "createCoupon" ? "Item Transfer Authorized" : - (sendAssetStep.referrer === "payIn" ? "Item Sent" : "Gift Sent")); - // Anchors - anchors.top: parent.top; - anchors.topMargin: 26; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - elide: Text.ElideRight; - height: 30; - // Text size - size: 22; - // Style - color: hifi.colors.baseGray; - } - - HiFiGlyphs { - id: closeGlyphButton_paymentSuccess; - visible: root.assetCertID === "" && sendAssetStep.referrer !== "payIn"; - text: hifi.glyphs.close; - color: hifi.colors.lightGrayText; - size: 26; - anchors.top: parent.top; - anchors.topMargin: 10; - anchors.right: parent.right; - anchors.rightMargin: 10; - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - onEntered: { - parent.text = hifi.glyphs.closeInverted; - } - onExited: { - parent.text = hifi.glyphs.close; - } - onClicked: { - if (sendAssetStep.referrer === "payIn") { - sendToScript({method: "closeSendAsset"}); - } else if (sendAssetStep.referrer === "createCoupon") { - showDidYouCopyLightbox(); - } else { - root.nextActiveView = "sendAssetHome"; - resetSendAssetData(); - if (root.assetName !== "") { - sendSignalToParent({method: "closeSendAsset"}); - } - } - } - } - } - - Item { - id: sendToContainer_paymentSuccess; - anchors.top: paymentSentText.bottom; - anchors.topMargin: 20; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: childrenRect.height; - - Item { - id: sendToScriptContainer_paymentSuccess; - visible: sendAssetStep.referrer === "createCoupon"; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - height: childrenRect.height; - - RalewaySemiBold { - id: authorizationIDLabel; - text: "Authorization ID:"; - // Anchors - anchors.left: parent.left; - anchors.top: authorizationIDText.top; - width: paintedWidth; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - - RalewayRegular { - id: authorizationIDText; - text: root.authorizationID; - anchors.top: parent.top; - anchors.left: authorizationIDLabel.right; - anchors.leftMargin: 16; - anchors.right: authorizationIDClipboardButton.left; - anchors.rightMargin: 16; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - wrapMode: Text.WrapAnywhere; - } - - Image { - id: authorizationIDClipboardButton; - source: "images/clipboard.svg"; // clipboard by Bieutuong Bon from the Noun Project - fillMode: Image.PreserveAspectFit; - // Anchors - anchors.right: parent.right; - anchors.top: authorizationIDText.top; - height: 40; - width: height; - - MouseArea { - anchors.fill: parent; - onClicked: { - Window.copyToClipboard(root.authorizationID); - authorizationIDText.text = "Copied to Clipboard!\n"; - authorizationIDClipboardTimer.start(); - } - } - } - - Timer { - id: authorizationIDClipboardTimer; - interval: 2000; - repeat: false; - onTriggered: { - authorizationIDText.text = root.authorizationID; - } - } - - RalewaySemiBold { - id: couponIDLabel; - text: "Coupon ID:"; - // Anchors - anchors.left: parent.left; - anchors.top: couponIDText.top; - width: authorizationIDLabel.width; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - - RalewayRegular { - id: couponIDText; - text: root.couponID; - anchors.top: authorizationIDText.bottom; - anchors.topMargin: 16; - anchors.left: couponIDLabel.right; - anchors.leftMargin: 16; - anchors.right: couponIDClipboardButton.left; - anchors.rightMargin: 16; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - wrapMode: Text.WrapAnywhere; - } - - Image { - id: couponIDClipboardButton; - source: "images/clipboard.svg"; // clipboard by Bieutuong Bon from the Noun Project - fillMode: Image.PreserveAspectFit; - // Anchors - anchors.right: parent.right; - anchors.top: couponIDText.top; - height: 40; - width: height; - - MouseArea { - anchors.fill: parent; - onClicked: { - Window.copyToClipboard(root.couponID); - couponIDText.text = "Copied to Clipboard!\n"; - couponIDClipboardTimer.start(); - } - } - } - - Timer { - id: couponIDClipboardTimer; - interval: 2000; - repeat: false; - onTriggered: { - couponIDText.text = root.couponID; - } - } - } - - Item { - id: sendToRecipientContainer_paymentSuccess; - visible: !sendToScriptContainer_paymentSuccess.visible; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - height: 80; - - RalewaySemiBold { - id: sendToText_paymentSuccess; - text: "Sent To:"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: 90; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - - RecipientDisplay { - anchors.top: parent.top; - anchors.left: sendToText_paymentSuccess.right; - anchors.right: parent.right; - height: parent.height; - textColor: hifi.colors.blueAccent; - - displayName: sendAssetStep.selectedRecipientDisplayName; - userName: sendAssetStep.selectedRecipientUserName; - profilePic: sendAssetStep.selectedRecipientProfilePic !== "" ? ((0 === sendAssetStep.selectedRecipientProfilePic.indexOf("http")) ? - sendAssetStep.selectedRecipientProfilePic : (Account.metaverseServerURL + sendAssetStep.selectedRecipientProfilePic)) : ""; - multiLineDisplay: sendAssetStep.referrer === "nearby" || sendAssetStep.referrer === "payIn"; - } - } - } - - Item { - id: giftContainer_paymentSuccess; - visible: root.assetCertID !== ""; - anchors.top: sendToContainer_paymentSuccess.bottom; - anchors.topMargin: 8; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 30; - - RalewaySemiBold { - id: gift_paymentSuccess; - text: sendAssetStep.referrer === "payIn" || sendAssetStep.referrer === "createCoupon" ? - "Item:" : "Gift:"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: 90; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - - RalewaySemiBold { - text: root.assetName; - // Anchors - anchors.top: parent.top; - anchors.left: gift_paymentSuccess.right; - anchors.right: parent.right; - height: parent.height; - // Text size - size: 18; - // Style - elide: Text.ElideRight; - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - } - - Item { - id: amountContainer_paymentSuccess; - visible: root.assetCertID === ""; - anchors.top: sendToContainer_paymentSuccess.bottom; - anchors.topMargin: 16; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 80; - - RalewaySemiBold { - id: amountText_paymentSuccess; - text: "Amount:"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: 90; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - - // "HFC" balance label - HiFiGlyphs { - id: amountSentLabel; - text: hifi.glyphs.hfc; - // Size - size: 32; - // Anchors - anchors.left: amountText_paymentSuccess.right; - anchors.verticalCenter: parent.verticalCenter; - height: 50; - // Style - color: hifi.colors.blueAccent; - } - - FiraSansSemiBold { - id: amountSentText; - text: amountTextField.text; - // Anchors - anchors.verticalCenter: parent.verticalCenter; - anchors.left: amountSentLabel.right; - anchors.leftMargin: 20; - anchors.right: parent.right; - height: 50; - // Style - size: 22; - color: hifi.colors.blueAccent; - } - } - - RalewaySemiBold { - id: optionalMessage_paymentSuccess; - visible: root.assetCertID === ""; - text: optionalMessage.text; - // Anchors - anchors.top: amountContainer_paymentSuccess.visible ? amountContainer_paymentSuccess.bottom : sendToContainer_paymentSuccess.bottom; - anchors.left: parent.left; - anchors.leftMargin: 110; - anchors.right: parent.right; - anchors.rightMargin: 16; - anchors.bottom: closeButton.top; - anchors.bottomMargin: 40; - // Text size - size: 22; - // Style - color: hifi.colors.blueAccent; - wrapMode: Text.Wrap; - verticalAlignment: Text.AlignTop; - } - - // "Close" button - HifiControlsUit.Button { - id: closeButton; - color: hifi.buttons.blue; - colorScheme: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colorSchemes.dark : hifi.colorSchemes.light; - anchors.horizontalCenter: parent.horizontalCenter; - anchors.bottom: parent.bottom; - anchors.bottomMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 80 : 30; - height: 50; - width: 120; - text: "Close"; - onClicked: { - if (sendAssetStep.referrer === "payIn") { - sendToScript({method: "closeSendAsset"}); - } else if (sendAssetStep.referrer === "createCoupon") { - showDidYouCopyLightbox(); - } else { - root.nextActiveView = "sendAssetHome"; - resetSendAssetData(); - if (root.assetName !== "") { - sendSignalToParent({method: "closeSendAsset"}); - } - } - } - } - } - } - // Payment Success END - - // Payment Failure BEGIN - Rectangle { - id: paymentFailure; - z: 998; - - visible: root.currentActiveView === "paymentFailure"; - anchors.fill: parent; - color: Qt.rgba(0.0, 0.0, 0.0, 0.8); - - // This object is always used in a popup or full-screen Wallet section. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup/section. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - Rectangle { - anchors.top: parent.top; - anchors.topMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" || - sendAssetStep.referrer === "createCoupon" ? 15 : 150; - anchors.left: parent.left; - anchors.leftMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" || - sendAssetStep.referrer === "createCoupon" ? 15 : 50; - anchors.right: parent.right; - anchors.rightMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" || - sendAssetStep.referrer === "createCoupon" ? 15 : 50; - anchors.bottom: parent.bottom; - anchors.bottomMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" || - sendAssetStep.referrer === "createCoupon" ? 15 : 300; - color: "#FFFFFF"; - - RalewaySemiBold { - id: paymentFailureText; - text: root.assetCertID === "" && sendAssetStep.referrer !== "payIn" ? "Payment Failed" : "Failed"; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 26; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - elide: Text.ElideRight; - height: 30; - // Text size - size: 22; - // Style - color: hifi.colors.baseGray; - } - - HiFiGlyphs { - id: closeGlyphButton_paymentFailure; - visible: root.assetCertID === "" && sendAssetStep.referrer !== "payIn"; - text: hifi.glyphs.close; - color: hifi.colors.lightGrayText; - size: 26; - anchors.top: parent.top; - anchors.topMargin: 10; - anchors.right: parent.right; - anchors.rightMargin: 10; - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - onEntered: { - parent.text = hifi.glyphs.closeInverted; - } - onExited: { - parent.text = hifi.glyphs.close; - } - onClicked: { - root.nextActiveView = "sendAssetHome"; - resetSendAssetData(); - if (root.assetName !== "") { - sendSignalToParent({method: "closeSendAsset"}); - } - } - } - } - - RalewaySemiBold { - id: paymentFailureDetailText; - text: sendAssetStep.referrer === "createCoupon" ? "The server was unable to handle your request. Please try again later." : - ("The recipient you specified was unable to receive your " + - (root.assetCertID === "" ? "payment." : (sendAssetStep.referrer === "payIn" ? "item." : "gift."))); - anchors.top: paymentFailureText.bottom; - anchors.topMargin: 20; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 80; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - wrapMode: Text.Wrap; - } - - Item { - id: sendToContainer_paymentFailure; - visible: (root.assetCertID === "" || sendAssetStep.referrer === "payIn") && - sendAssetStep.referrer !== "createCoupon"; - anchors.top: paymentFailureDetailText.bottom; - anchors.topMargin: 8; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 80; - - RalewaySemiBold { - id: sentToText_paymentFailure; - text: "Sent To:"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: 90; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - - RecipientDisplay { - anchors.top: parent.top; - anchors.left: sentToText_paymentFailure.right; - anchors.right: parent.right; - height: parent.height; - textColor: hifi.colors.baseGray; - - displayName: sendAssetStep.selectedRecipientDisplayName; - userName: sendAssetStep.selectedRecipientUserName; - profilePic: sendAssetStep.selectedRecipientProfilePic !== "" ? ((0 === sendAssetStep.selectedRecipientProfilePic.indexOf("http")) ? - sendAssetStep.selectedRecipientProfilePic : (Account.metaverseServerURL + sendAssetStep.selectedRecipientProfilePic)) : ""; - multiLineDisplay: sendAssetStep.referrer === "nearby" || sendAssetStep.referrer === "payIn"; - } - } - - Item { - id: amountContainer_paymentFailure; - visible: root.assetCertID === ""; - anchors.top: sendToContainer_paymentFailure.visible ? - sendToContainer_paymentFailure.bottom : paymentFailureDetailText.bottom; - anchors.topMargin: 16; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 80; - - RalewaySemiBold { - id: amountText_paymentFailure; - text: "Amount:"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: 90; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - - // "HFC" balance label - HiFiGlyphs { - id: amountSentLabel_paymentFailure; - text: hifi.glyphs.hfc; - // Size - size: 32; - // Anchors - anchors.left: amountText_paymentFailure.right; - anchors.verticalCenter: parent.verticalCenter; - height: 50; - // Style - color: hifi.colors.baseGray; - } - - FiraSansSemiBold { - id: amountSentText_paymentFailure; - text: amountTextField.text; - // Anchors - anchors.verticalCenter: parent.verticalCenter; - anchors.left: amountSentLabel_paymentFailure.right; - anchors.leftMargin: 20; - anchors.right: parent.right; - height: 50; - // Style - size: 22; - color: hifi.colors.baseGray; - } - } - - RalewaySemiBold { - id: optionalMessage_paymentFailure; - visible: root.assetCertID === "" || sendAssetStep.referrer === "payIn"; - text: optionalMessage.text; - // Anchors - anchors.top: amountContainer_paymentFailure.visible ? amountContainer_paymentFailure.bottom : sendToContainer_paymentFailure.bottom; - anchors.left: parent.left; - anchors.leftMargin: 110; - anchors.right: parent.right; - anchors.rightMargin: 16; - anchors.bottom: closeButton_paymentFailure.top; - anchors.bottomMargin: 40; - // Text size - size: 22; - // Style - color: hifi.colors.baseGray; - wrapMode: Text.Wrap; - verticalAlignment: Text.AlignTop; - } - - // "Cancel" button - HifiControlsUit.Button { - id: closeButton_paymentFailure; - color: hifi.buttons.noneBorderless; - colorScheme: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colorSchemes.dark : hifi.colorSchemes.light; - anchors.right: retryButton_paymentFailure.left; - anchors.rightMargin: 12; - anchors.bottom: parent.bottom; - anchors.bottomMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 80 : 30; - height: 50; - width: 120; - text: "Cancel"; - onClicked: { - if (sendAssetStep.referrer === "payIn") { - sendToScript({method: "closeSendAsset"}); - } else { - root.nextActiveView = "sendAssetHome"; - resetSendAssetData(); - if (root.assetName !== "") { - sendSignalToParent({method: "closeSendAsset"}); - } - } - } - } - - // "Retry" button - HifiControlsUit.Button { - id: retryButton_paymentFailure; - color: hifi.buttons.blue; - colorScheme: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? hifi.colorSchemes.dark : hifi.colorSchemes.light; - anchors.right: parent.right; - anchors.rightMargin: 12; - anchors.bottom: parent.bottom; - anchors.bottomMargin: root.assetCertID === "" || sendAssetStep.referrer === "payIn" ? 80 : 30; - height: 50; - width: 120; - text: "Retry"; - onClicked: { - root.isCurrentlySendingAsset = true; - if (sendAssetStep.referrer === "connections" || sendAssetStep.referrer === "payIn") { - Commerce.transferAssetToUsername(sendAssetStep.selectedRecipientUserName, - root.assetCertID, - parseInt(amountTextField.text), - optionalMessage.text); - } else if (sendAssetStep.referrer === "nearby") { - Commerce.transferAssetToNode(sendAssetStep.selectedRecipientNodeID, - root.assetCertID, - parseInt(amountTextField.text), - optionalMessage.text); - } else if (sendAssetStep.referrer === "createCoupon") { - Commerce.authorizeAssetTransfer(couponIDTextField.text || "", - root.assetCertID, - parseInt(amountTextField.text) || 1, - optionalMessage.text) - } - } - } - } - } - // Payment Failure END - - - // - // FUNCTION DEFINITIONS START - // - - function resetSendAssetData() { - amountTextField.focus = false; - optionalMessage.focus = false; - amountTextFieldError.text = ""; - amountTextField.error = false; - chooseRecipientNearby.selectedRecipient = ""; - sendAssetStep.selectedRecipientNodeID = ""; - sendAssetStep.selectedRecipientDisplayName = ""; - sendAssetStep.selectedRecipientUserName = ""; - sendAssetStep.selectedRecipientProfilePic = ""; - amountTextField.text = ""; - optionalMessage.text = ""; - sendPubliclyCheckbox.checked = Settings.getValue("sendAssetsNearbyPublicly", true); - sendAssetStep.referrer = ""; - } - - function generateRandomCouponID() { - var RANDOM_COUPON_ID_LENGTH = 25; - var randomCouponID = ""; - var possibleCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - - for (var i = 0; i < RANDOM_COUPON_ID_LENGTH; i++) { - randomCouponID += possibleCharacters.charAt(Math.floor(Math.random() * possibleCharacters.length)); - } - - return randomCouponID; - } - - function showDidYouCopyLightbox() { - lightboxPopup.titleText = "Close Confirmation"; - lightboxPopup.bodyText = "Did you copy your Authorization ID and your Coupon ID?\n\n" + - "You won't be able to see your Authorization ID or your Coupon ID once " + - "you close this window."; - lightboxPopup.button1text = "GO BACK"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "I'M ALL SET"; - lightboxPopup.button2method = function() { - lightboxPopup.visible = false; - root.nextActiveView = "sendAssetHome"; - resetSendAssetData(); - if (root.assetName !== "") { - sendSignalToParent({method: "closeSendAsset"}); - } - } - lightboxPopup.visible = true; - } - - // - // Function Name: fromScript() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the JavaScript. - // Messages are in format "{method, params}", like json-rpc. - // - // Description: - // Called when a message is received from a script. - // - function fromScript(message) { - switch (message.method) { - case 'selectRecipient': - if (message.isSelected) { - chooseRecipientNearby.selectedRecipient = message.id; - sendAssetStep.selectedRecipientDisplayName = message.displayName; - sendAssetStep.selectedRecipientUserName = message.userName; - } else { - chooseRecipientNearby.selectedRecipient = ""; - sendAssetStep.selectedRecipientDisplayName = ''; - sendAssetStep.selectedRecipientUserName = ''; - } - break; - case 'updateSelectedRecipientUsername': - sendAssetStep.selectedRecipientUserName = message.userName; - break; - case 'updateSendAssetQML': - root.assetName = ""; - root.assetCertID = message.assetCertID || ""; - if (root.assetCertID === "") { - amountTextField.text = message.amount || 1; - } else { - amountTextField.text = ""; - Commerce.certificateInfo(root.assetCertID); - } - sendAssetStep.referrer = "payIn"; - sendAssetStep.selectedRecipientNodeID = ""; - sendAssetStep.selectedRecipientDisplayName = "Determined by script:"; - sendAssetStep.selectedRecipientUserName = message.username || ""; - optionalMessage.text = message.message || "No Message Provided"; - - if (sendAssetStep.selectedRecipientUserName === "") { - console.log("SendAsset: Script didn't specify a recipient username!"); - sendAssetHome.visible = false; - root.nextActiveView = 'paymentFailure'; - return; - } - - root.nextActiveView = "sendAssetStep"; - break; - case 'inspectionCertificate_resetCert': - // NOP - break; - default: - console.log('SendAsset: Unrecognized message from wallet.js'); - } - } - signal sendSignalToParent(var msg); - signal sendToScript(var message); - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/images/clipboard.svg b/interface/resources/qml/hifi/commerce/common/sendAsset/images/clipboard.svg deleted file mode 100644 index 798fdaaab1b..00000000000 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/images/clipboard.svg +++ /dev/null @@ -1 +0,0 @@ -Created by Bieutuong Bonfrom the Noun Project \ No newline at end of file diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/images/connection.svg b/interface/resources/qml/hifi/commerce/common/sendAsset/images/connection.svg deleted file mode 100644 index 7c5403fda36..00000000000 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/images/connection.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/images/coupon.svg b/interface/resources/qml/hifi/commerce/common/sendAsset/images/coupon.svg deleted file mode 100644 index 2b7c0525897..00000000000 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/images/coupon.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/images/nearby.svg b/interface/resources/qml/hifi/commerce/common/sendAsset/images/nearby.svg deleted file mode 100644 index dec87e658d1..00000000000 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/images/nearby.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/images/p2p-nearby-selected.svg b/interface/resources/qml/hifi/commerce/common/sendAsset/images/p2p-nearby-selected.svg deleted file mode 100644 index 59635a99b1d..00000000000 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/images/p2p-nearby-selected.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/images/p2p-nearby-unselected.svg b/interface/resources/qml/hifi/commerce/common/sendAsset/images/p2p-nearby-unselected.svg deleted file mode 100644 index bba07b95674..00000000000 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/images/p2p-nearby-unselected.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/images/send-money-effect-sm.jpg b/interface/resources/qml/hifi/commerce/common/sendAsset/images/send-money-effect-sm.jpg deleted file mode 100644 index 7cabf9414a1..00000000000 Binary files a/interface/resources/qml/hifi/commerce/common/sendAsset/images/send-money-effect-sm.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml deleted file mode 100644 index 16faf2feb71..00000000000 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ /dev/null @@ -1,717 +0,0 @@ -// -// InspectionCertificate.qml -// qml/hifi/commerce/inspectionCertificate -// -// InspectionCertificate -// -// Created by Zach Fox on 2017-09-14 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../wallet" as HifiWallet - -Rectangle { - HifiConstants { id: hifi; } - - id: root; - property string entityId: ""; - property string certificateId: ""; - property string itemName: "--"; - property string itemOwner: "--"; - property string itemEdition: "--"; - property string dateAcquired: "--"; - property string itemCost: "--"; - property string marketplace_item_id: ""; - property bool standaloneOptimized: false; - property bool standaloneIncompatible: false; - property string certTitleTextColor: hifi.colors.darkGray; - property string certTextColor: hifi.colors.white; - property string infoTextColor: hifi.colors.blueAccent; - // 0 means replace none - // 4 means replace all but "Item Edition" - // 5 means replace all 5 replaceable fields - property int certInfoReplaceMode: 5; - property bool isLightbox: false; - property bool isMyCert: false; - property bool useGoldCert: true; - property bool certificateInfoPending: true; - property int certificateStatus: 0; - property bool certificateStatusPending: true; - // Style - color: hifi.colors.faintGray; - Connections { - target: Commerce; - - onCertificateInfoResult: { - if (result.status !== 'success') { - console.log("Failed to get certificate info", result.data.message); - // We should still tell the user that static cert verification failed - if (root.certificateStatus !== 3) { // CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED - root.useGoldCert = false; - root.certTitleTextColor = hifi.colors.redHighlight; - root.certTextColor = hifi.colors.redHighlight; - root.infoTextColor = hifi.colors.redHighlight; - titleBarText.text = "Certificate Unavailable"; - popText.text = ""; - showInMarketplaceButton.visible = false; - root.certInfoReplaceMode = 0; - root.itemName = ""; - root.itemEdition = ""; - root.itemOwner = ""; - root.dateAcquired = ""; - root.itemCost = ""; - errorText.text = "Information about this certificate is currently unavailable. Please try again later."; - } - } else { - root.marketplace_item_id = result.data.marketplace_item_id; - root.isMyCert = result.isMyCert ? result.isMyCert : false; - root.standaloneOptimized = result.data.standalone_optimized; - root.standaloneIncompatible = result.data.standalone_incompatible; - - if (root.certInfoReplaceMode > 3) { - root.itemName = result.data.marketplace_item_name; - // "\u2022" is the Unicode character 'BULLET' - it's what's used in password fields on the web, etc - root.itemOwner = root.isMyCert ? Account.username : - "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"; - root.dateAcquired = root.isMyCert ? getFormattedDate(result.data.transfer_created_at * 1000) : "Undisclosed"; - root.itemCost = (root.isMyCert && result.data.cost !== undefined) ? - (parseInt(result.data.cost) > 0 ? result.data.cost : "Free") : "Undisclosed"; - } - if (root.certInfoReplaceMode > 4) { - root.itemEdition = result.data.edition_number + "/" + (result.data.limited_run === -1 ? "\u221e" : result.data.limited_run); - } - - if (root.certificateStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED - if (root.isMyCert) { - errorText.text = "This item is an uncertified copy of an item you acquired."; - } else { - errorText.text = "The person who placed this item doesn't own it."; - } - } - - if (result.data.invalid_reason || result.data.transfer_status[0] === "failed") { - root.useGoldCert = false; - root.certTitleTextColor = hifi.colors.redHighlight; - root.certTextColor = hifi.colors.redHighlight; - root.infoTextColor = hifi.colors.redHighlight; - titleBarText.text = "Certificate\nNo Longer Valid"; - popText.text = ""; - showInMarketplaceButton.visible = false; - // "Edition" text previously set above in this function - // "Owner" text previously set above in this function - // "Acquisition Date" text previously set above in this function - // "Acquisition Price" text previously set above in this function - if (result.data.invalid_reason) { - errorText.text = result.data.invalid_reason; - } - } else if (result.data.transfer_status[0] === "pending") { - root.useGoldCert = false; - root.certTitleTextColor = hifi.colors.redHighlight; - root.certTextColor = hifi.colors.redHighlight; - root.infoTextColor = hifi.colors.redHighlight; - titleBarText.text = "Certificate Pending"; - popText.text = ""; - showInMarketplaceButton.visible = true; - // "Edition" text previously set above in this function - // "Owner" text previously set above in this function - // "Acquisition Date" text previously set above in this function - // "Acquisition Price" text previously set above in this function - errorText.text = "The status of this item is still pending confirmation. If the purchase is not confirmed, " + - "this entity will be cleaned up by the domain."; - } - } - root.certificateInfoPending = false; - } - - onUpdateCertificateStatus: { - updateCertificateStatus(certStatus); - } - } - - function updateCertificateStatus(status) { - root.certificateStatus = status; - if (root.certificateStatus === 1) { // CERTIFICATE_STATUS_VERIFICATION_SUCCESS - root.useGoldCert = true; - root.certTitleTextColor = hifi.colors.darkGray; - root.certTextColor = hifi.colors.white; - root.infoTextColor = hifi.colors.blueAccent; - titleBarText.text = "Certificate"; - popText.text = "PROOF OF PROVENANCE"; - showInMarketplaceButton.visible = true; - root.certInfoReplaceMode = 5; - // "Item Name" text will be set in "onCertificateInfoResult()" - // "Edition" text will be set in "onCertificateInfoResult()" - // "Owner" text will be set in "onCertificateInfoResult()" - // "Acquisition Date" text will be set in "onCertificateInfoResult()" - // "Acquisition Price" text will be set in "onCertificateInfoResult()" - errorText.text = ""; - } else if (root.certificateStatus === 2) { // CERTIFICATE_STATUS_VERIFICATION_TIMEOUT - root.useGoldCert = false; - root.certTitleTextColor = hifi.colors.redHighlight; - root.certTextColor = hifi.colors.redHighlight; - root.infoTextColor = hifi.colors.redHighlight; - titleBarText.text = "Request Timed Out"; - popText.text = ""; - showInMarketplaceButton.visible = false; - root.certInfoReplaceMode = 0; - root.itemName = ""; - root.itemEdition = ""; - root.itemOwner = ""; - root.dateAcquired = ""; - root.itemCost = ""; - errorText.text = "Your request to inspect this item timed out. Please try again later."; - } else if (root.certificateStatus === 3) { // CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED - root.useGoldCert = false; - root.certTitleTextColor = hifi.colors.redHighlight; - root.certTextColor = hifi.colors.redHighlight; - root.infoTextColor = hifi.colors.redHighlight; - titleBarText.text = "Certificate\nNo Longer Valid"; - popText.text = ""; - showInMarketplaceButton.visible = true; - root.certInfoReplaceMode = 5; - // "Item Name" text will be set in "onCertificateInfoResult()" - // "Edition" text will be set in "onCertificateInfoResult()" - // "Owner" text will be set in "onCertificateInfoResult()" - // "Acquisition Date" text will be set in "onCertificateInfoResult()" - // "Acquisition Price" text will be set in "onCertificateInfoResult()" - errorText.text = "The information associated with this item has been modified and it no longer matches the original certified item."; - } else if (root.certificateStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED - root.useGoldCert = false; - root.certTitleTextColor = hifi.colors.redHighlight; - root.certTextColor = hifi.colors.redHighlight; - root.infoTextColor = hifi.colors.redHighlight; - titleBarText.text = "Invalid Certificate"; - popText.text = ""; - showInMarketplaceButton.visible = true; - root.certInfoReplaceMode = 4; - // "Item Name" text will be set in "onCertificateInfoResult()" - root.itemEdition = "Uncertified Copy" - // "Owner" text will be set in "onCertificateInfoResult()" - // "Acquisition Date" text will be set in "onCertificateInfoResult()" - // "Acquisition Price" text will be set in "onCertificateInfoResult()" - // "Error Text" text will be set in "onCertificateInfoResult()" - } else { - console.log("Unknown certificate status received from ledger signal!"); - } - - root.certificateStatusPending = false; - // We've gotten cert status - we are GO on getting the cert info - Commerce.certificateInfo(root.certificateId); - } - - // This object is always used in a popup. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - Rectangle { - id: loadingOverlay; - z: 998; - - visible: root.certificateInfoPending || root.certificateStatusPending; - anchors.fill: parent; - color: Qt.rgba(0.0, 0.0, 0.0, 0.7); - - // This object is always used in a popup or full-screen Wallet section. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup/section. - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - propagateComposedEvents: false; - } - - AnimatedImage { - source: "../common/images/loader.gif" - width: 96; - height: width; - anchors.verticalCenter: parent.verticalCenter; - anchors.horizontalCenter: parent.horizontalCenter; - } - } - - Image { - id: backgroundImage; - anchors.fill: parent; - source: root.useGoldCert ? "images/cert-bg-gold-split.png" : "images/nocert-bg-split.png"; - } - - // Title text - RalewayLight { - id: titleBarText; - text: "Certificate"; - // Text size - size: 40; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 40; - anchors.left: parent.left; - anchors.leftMargin: 36; - anchors.right: parent.right; - anchors.rightMargin: 8; - height: paintedHeight; - // Style - color: root.certTitleTextColor; - wrapMode: Text.WordWrap; - } - // Title text - RalewayRegular { - id: popText; - // Text size - size: 16; - // Anchors - anchors.top: titleBarText.bottom; - anchors.topMargin: 4; - anchors.left: titleBarText.left; - anchors.right: titleBarText.right; - height: text === "" ? 0 : paintedHeight; - // Style - color: root.certTitleTextColor; - } - - // "Close" button - HiFiGlyphs { - z: 999; - id: closeGlyphButton; - text: hifi.glyphs.close; - color: hifi.colors.white; - size: 26; - anchors.top: parent.top; - anchors.topMargin: 10; - anchors.right: parent.right; - anchors.rightMargin: 10; - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - onEntered: { - parent.text = hifi.glyphs.closeInverted; - } - onExited: { - parent.text = hifi.glyphs.close; - } - onClicked: { - if (root.isLightbox) { - root.visible = false; - } else { - sendToScript({method: 'inspectionCertificate_closeClicked', closeGoesToPurchases: root.closeGoesToPurchases}); - } - } - } - } - - // - // "CERTIFICATE" START - // - Item { - id: certificateContainer; - anchors.top: titleBarText.top; - anchors.topMargin: 110; - anchors.bottom: infoContainer.top; - anchors.left: parent.left; - anchors.leftMargin: titleBarText.anchors.leftMargin; - anchors.right: parent.right; - anchors.rightMargin: 24; - - RalewayRegular { - id: itemNameHeader; - text: "ITEM NAME"; - // Text size - size: 16; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - height: paintedHeight; - // Style - color: hifi.colors.darkGray; - } - RalewaySemiBold { - id: itemName; - text: root.itemName; - // Text size - size: 28; - // Anchors - anchors.top: itemNameHeader.bottom; - anchors.topMargin: 8; - anchors.left: itemNameHeader.left; - anchors.right: itemNameHeader.right; - height: paintedHeight; - // Style - color: root.certTextColor; - elide: Text.ElideRight; - MouseArea { - enabled: showInMarketplaceButton.visible; - anchors.fill: parent; - hoverEnabled: enabled; - onClicked: { - sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', itemId: root.marketplace_item_id}); - } - onEntered: itemName.color = hifi.colors.blueHighlight; - onExited: itemName.color = root.certTextColor; - } - } - - RalewayRegular { - id: editionHeader; - text: "EDITION"; - // Text size - size: 16; - // Anchors - anchors.top: itemName.bottom; - anchors.topMargin: 28; - anchors.left: parent.left; - anchors.right: parent.right; - height: paintedHeight; - // Style - color: hifi.colors.darkGray; - } - AnonymousProRegular { - id: edition; - text: root.itemEdition; - // Text size - size: 18; - // Anchors - anchors.top: editionHeader.bottom; - anchors.topMargin: 8; - anchors.left: editionHeader.left; - anchors.right: editionHeader.right; - height: paintedHeight; - // Style - color: root.certTextColor; - } - - // "Show In Marketplace" button - HifiControlsUit.Button { - id: showInMarketplaceButton; - enabled: root.marketplace_item_id && marketplace_item_id !== ""; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.light; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 48; - anchors.right: parent.right; - width: 200; - height: 40; - text: "View In Market" - onClicked: { - sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', itemId: root.marketplace_item_id}); - } - } - } - // - // "CERTIFICATE" END - // - - // - // "INFO CONTAINER" START - // - Item { - id: infoContainer; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.leftMargin: titleBarText.anchors.leftMargin; - anchors.right: parent.right; - anchors.rightMargin: 24; - height: root.useGoldCert ? 220 : 372; - - HiFiGlyphs { - id: standaloneOptomizedBadge - - anchors { - right: parent.right - top: ownedByHeader.top - rightMargin: 15 - topMargin: 28 - } - - visible: root.standaloneOptimized - - text: hifi.glyphs.hmd - size: 34 - horizontalAlignment: Text.AlignHCenter - color: hifi.colors.blueHighlight - } - - RalewayRegular { - id: errorText; - visible: !root.useGoldCert; - // Text size - size: 20; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 36; - anchors.left: parent.left; - anchors.right: parent.right; - height: 116; - // Style - wrapMode: Text.WordWrap; - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignTop; - } - - RalewayRegular { - id: ownedByHeader; - text: "OWNER"; - // Text size - size: 16; - // Anchors - anchors.top: errorText.visible ? errorText.bottom : parent.top; - anchors.topMargin: 28; - anchors.left: parent.left; - anchors.right: parent.right; - height: paintedHeight; - // Style - color: hifi.colors.darkGray; - } - - RalewayRegular { - id: ownedBy; - text: root.itemOwner; - // Text size - size: 22; - // Anchors - anchors.top: ownedByHeader.bottom; - anchors.topMargin: 8; - anchors.left: ownedByHeader.left; - height: paintedHeight; - // Style - color: root.infoTextColor; - elide: Text.ElideRight; - } - - AnonymousProRegular { - id: isMyCertText; - visible: root.isMyCert && ownedBy.text !== "--" && ownedBy.text !== ""; - text: "(Private)"; - size: 18; - // Anchors - anchors.top: ownedBy.top; - anchors.topMargin: 4; - anchors.bottom: ownedBy.bottom; - anchors.left: ownedBy.right; - anchors.leftMargin: 6; - anchors.right: ownedByHeader.right; - // Style - color: root.infoTextColor; - elide: Text.ElideRight; - verticalAlignment: Text.AlignVCenter; - } - - RalewayRegular { - id: standaloneHeader; - text: root.standaloneOptimized ? "STAND-ALONE OPTIMIZED" : "STAND-ALONE INCOMPATIBLE"; - // Text size - size: 16; - // Anchors - anchors.top: ownedBy.bottom; - anchors.topMargin: 15; - anchors.left: parent.left; - anchors.right: parent.right; - visible: root.standaloneOptimized || root.standaloneIncompatible; - height: visible ? paintedHeight : 0; - // Style - color: hifi.colors.darkGray; - } - - RalewayRegular { - id: standaloneText; - text: root.standaloneOptimized ? "This item is stand-alone optimized" : "This item is incompatible with stand-alone devices"; - // Text size - size: 18; - // Anchors - anchors.top: standaloneHeader.bottom; - anchors.topMargin: 8; - anchors.left: standaloneHeader.left; - visible: root.standaloneOptimized || root.standaloneIncompatible; - height: visible ? paintedHeight : 0; - // Style - color: root.infoTextColor; - elide: Text.ElideRight; - } - - RalewayRegular { - id: dateAcquiredHeader; - text: "ACQUISITION DATE"; - // Text size - size: 16; - // Anchors - anchors.top: standaloneText.bottom; - anchors.topMargin: 20; - anchors.left: parent.left; - anchors.right: parent.horizontalCenter; - anchors.rightMargin: 8; - height: paintedHeight; - // Style - color: hifi.colors.darkGray; - } - AnonymousProRegular { - id: dateAcquired; - text: root.dateAcquired; - // Text size - size: 18; - // Anchors - anchors.top: dateAcquiredHeader.bottom; - anchors.topMargin: 8; - anchors.left: dateAcquiredHeader.left; - anchors.right: dateAcquiredHeader.right; - height: paintedHeight; - // Style - color: root.infoTextColor; - } - - RalewayRegular { - id: priceHeader; - text: "ACQUISITION PRICE"; - // Text size - size: 16; - // Anchors - anchors.top: standaloneText.bottom; - anchors.topMargin: 20; - anchors.left: parent.horizontalCenter; - anchors.right: parent.right; - height: paintedHeight; - // Style - color: hifi.colors.darkGray; - } - HiFiGlyphs { - id: hfcGlyph; - visible: priceText.text !== "Undisclosed" && priceText.text !== "" && priceText.text !== "Free"; - text: hifi.glyphs.hfc; - // Size - size: 24; - // Anchors - anchors.top: priceHeader.bottom; - anchors.topMargin: 8; - anchors.left: priceHeader.left; - width: visible ? paintedWidth + 6 : 0; - height: 40; - // Style - color: root.infoTextColor; - verticalAlignment: Text.AlignTop; - horizontalAlignment: Text.AlignLeft; - } - AnonymousProRegular { - id: priceText; - text: root.itemCost; - // Text size - size: 18; - // Anchors - anchors.top: priceHeader.bottom; - anchors.topMargin: 8; - anchors.left: hfcGlyph.right; - anchors.right: priceHeader.right; - height: paintedHeight; - // Style - color: root.infoTextColor; - } - } - // - // "INFO CONTAINER" END - // - - // - // FUNCTION DEFINITIONS START - // - // - // Function Name: fromScript() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the JavaScript, in this case the Marketplaces JavaScript. - // Messages are in format "{method, params}", like json-rpc. - // - // Description: - // Called when a message is received from a script. - // - function fromScript(message) { - switch (message.method) { - case 'inspectionCertificate_setCertificateId': - resetCert(false); - root.certificateId = message.certificateId; - if (message.entityId === "") { - updateCertificateStatus(1); // CERTIFICATE_STATUS_VERIFICATION_SUCCESS - } else { - root.entityId = message.entityId; - sendToScript({method: 'inspectionCertificate_requestOwnershipVerification', entity: root.entityId}); - } - break; - case 'inspectionCertificate_resetCert': - resetCert(true); - break; - default: - console.log('InspectionCertificate.qml: Unrecognized message from marketplaces.js'); - } - } - signal sendToScript(var message); - - function resetCert(alsoResetCertID) { - if (alsoResetCertID) { - root.entityId = ""; - root.certificateId = ""; - } - root.certInfoReplaceMode = 5; - root.certificateInfoPending = true; - root.certificateStatusPending = true; - root.useGoldCert = true; - root.certTitleTextColor = hifi.colors.darkGray; - root.certTextColor = hifi.colors.white; - root.infoTextColor = hifi.colors.blueAccent; - titleBarText.text = "Certificate"; - popText.text = ""; - root.itemName = "--"; - root.itemOwner = "--"; - root.itemEdition = "--"; - root.dateAcquired = "--"; - root.marketplace_item_id = ""; - root.itemCost = "--"; - root.isMyCert = false; - errorText.text = ""; - } - - function getFormattedDate(timestamp) { - if (timestamp === "--") { - return "--"; - } - function addLeadingZero(n) { - return n < 10 ? '0' + n : '' + n; - } - - var a = new Date(timestamp); - var year = a.getFullYear(); - var month = addLeadingZero(a.getMonth() + 1); - var day = addLeadingZero(a.getDate()); - var hour = a.getHours(); - var drawnHour = hour; - if (hour === 0) { - drawnHour = 12; - } else if (hour > 12) { - drawnHour -= 12; - } - drawnHour = addLeadingZero(drawnHour); - - var amOrPm = "AM"; - if (hour >= 12) { - amOrPm = "PM"; - } - - var min = addLeadingZero(a.getMinutes()); - var sec = addLeadingZero(a.getSeconds()); - return year + '-' + month + '-' + day + ' ' + drawnHour + ':' + min + amOrPm; - } - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/images/cert-bg-gold-split.png b/interface/resources/qml/hifi/commerce/inspectionCertificate/images/cert-bg-gold-split.png deleted file mode 100644 index 14a17df0b16..00000000000 Binary files a/interface/resources/qml/hifi/commerce/inspectionCertificate/images/cert-bg-gold-split.png and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/images/nocert-bg-split.png b/interface/resources/qml/hifi/commerce/inspectionCertificate/images/nocert-bg-split.png deleted file mode 100644 index b2f5a492653..00000000000 Binary files a/interface/resources/qml/hifi/commerce/inspectionCertificate/images/nocert-bg-split.png and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml deleted file mode 100644 index 65453ba21de..00000000000 --- a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml +++ /dev/null @@ -1,1282 +0,0 @@ -// -// Marketplace.qml -// qml/hifi/commerce/marketplace -// -// Marketplace -// -// Created by Roxanne Skelly on 2019-01-18 -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../common" as HifiCommerceCommon -import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. -import "../common/sendAsset" -import "../.." as HifiCommon - -Rectangle { - HifiConstants { - id: hifi - } - - id: root - - property string activeView: "initialize" - property int currentSortIndex: 1 - property string sortString: "recent" - property bool isAscending: false - property string categoryString: "" - property string searchString: "" - property bool keyboardEnabled: HMD.active - property bool keyboardRaised: false - property string searchScopeString: "Featured" - property bool isLoggedIn: false - property bool supports3DHTML: true - property bool pendingGetMarketplaceItemCall: false - - anchors.fill: (typeof parent === undefined) ? undefined : parent - - function getMarketplaceItems() { - marketplaceItemView.visible = false; - itemsList.visible = true; - licenseInfo.visible = false; - marketBrowseModel.getFirstPage(); - { - if(root.searchString !== undefined && root.searchString !== "") { - root.searchScopeString = "Search Results: \"" + root.searchString + "\""; - } else if (root.categoryString !== "") { - root.searchScopeString = root.categoryString; - } else { - root.searchScopeString = "Featured"; - } - } - } - - Component.onCompleted: { - Commerce.getLoginStatus(); - - supports3DHTML = PlatformInfo.has3DHTML(); - } - - Component.onDestruction: { - keyboard.raised = false; - } - - Connections { - target: GlobalServices - - onMyUsernameChanged: { - Commerce.getLoginStatus(); - } - } - - Connections { - target: MarketplaceScriptingInterface - - onGetMarketplaceCategoriesResult: { - if (result.status !== 'success') { - console.log("Failed to get Marketplace Categories", result.data.message); - } else { - categoriesModel.clear(); - result.data.categories.forEach(function(category) { - categoriesModel.append({ - id: category.id, - name: category.name, - count: category.count - }); - }); - } - getMarketplaceItems(); - } - onGetMarketplaceItemsResult: { - if (!pendingGetMarketplaceItemCall) { - marketBrowseModel.handlePage(result.status !== "success" && result.message, result); - } - } - - onGetMarketplaceItemResult: { - if (result.status !== 'success') { - console.log("Failed to get Marketplace Item", result.data.message); - } else { - marketplaceItem.supports3DHTML = root.supports3DHTML; - marketplaceItem.item_id = result.data.id; - marketplaceItem.image_url = result.data.thumbnail_url; - marketplaceItem.name = result.data.title; - marketplaceItem.likes = result.data.likes; - if (result.data.has_liked !== undefined) { - marketplaceItem.liked = result.data.has_liked; - } - marketplaceItem.creator = result.data.creator; - marketplaceItem.categories = result.data.categories; - marketplaceItem.price = result.data.cost; - marketplaceItem.description = result.data.description; - marketplaceItem.attributions = result.data.attributions; - marketplaceItem.license = result.data.license; - marketplaceItem.availability = result.data.availability; - marketplaceItem.updated_item_id = result.data.updated_item_id || ""; - marketplaceItem.created_at = result.data.created_at; - marketplaceItem.standaloneOptimized = result.data.standalone_optimized; - marketplaceItem.standaloneVisible = result.data.standalone_optimized || result.data.standalone_incompatible; - marketplaceItemScrollView.contentHeight = marketplaceItemContent.height; - itemsList.visible = false; - marketplaceItemView.visible = true; - pendingGetMarketplaceItemCall = false; - } - } - } - - Connections { - target: Commerce - - onLoginStatusResult: { - root.isLoggedIn = isLoggedIn; - } - } - - HifiCommerceCommon.CommerceLightbox { - id: lightboxPopup - visible: false - anchors.fill: parent - } - - // - // HEADER BAR START - // - - Rectangle { - id: headerShadowBase - anchors.fill: header - color: "white" - } - DropShadow { - anchors.fill: headerShadowBase - source: headerShadowBase - verticalOffset: 4 - horizontalOffset: 4 - radius: 6 - samples: 9 - color: hifi.colors.baseGrayShadow - z:5 - } - Rectangle { - id: header; - - visible: true - anchors { - left: parent.left - top: parent.top - right: parent.right - } - - height: childrenRect.height+5 - z: 5 - - Rectangle { - id: titleBarContainer - - anchors.left: parent.left - anchors.top: parent.top - width: parent.width - height: 60 - visible: true - - Image { - id: marketplaceHeaderImage - source: "../common/images/marketplaceHeaderImage.png" - anchors.top: parent.top - anchors.topMargin: 2 - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 8 - width: 140 - fillMode: Image.PreserveAspectFit - - MouseArea { - anchors.fill: parent; - onClicked: { - sendToParent({method: "header_marketplaceImageClicked"}); - } - } - } - } - - Rectangle { - id: searchBarContainer - - anchors.top: titleBarContainer.bottom - width: parent.width - height: 50 - - visible: true - clip: false - - // - // TODO: Possibly change this to be a combo box - // - Rectangle { - id: categoriesButton - - anchors { - left: parent.left - leftMargin: 10 - verticalCenter: parent.verticalCenter - } - height: 34 - width: categoriesText.width + 25 - - color: hifi.colors.white - radius: 4 - border.width: 1 - border.color: hifi.colors.lightGrayText - - RalewayRegular { - id: categoriesText - - anchors.centerIn: parent - - text: "Categories" - size: 14 - color: hifi.colors.lightGrayText - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - rightPadding: 10 - } - - HiFiGlyphs { - id: categoriesDropdownIcon - - anchors { - right: parent.right - rightMargin: -8 - verticalCenter: parent.verticalCenter - } - - text: hifi.glyphs.caratDn - size: 34 - horizontalAlignment: Text.AlignHCenter - color: hifi.colors.baseGray - } - - MouseArea { - anchors.fill: parent - - hoverEnabled: enabled - onClicked: { - categoriesDropdown.visible = !categoriesDropdown.visible; - categoriesButton.color = categoriesDropdown.visible ? hifi.colors.lightGray : hifi.colors.white; - categoriesDropdown.forceActiveFocus(); - } - onEntered: categoriesText.color = hifi.colors.baseGrayShadow - onExited: categoriesText.color = hifi.colors.baseGray - } - - Component.onCompleted: { - MarketplaceScriptingInterface.getMarketplaceCategories(); - } - } - - // or - RalewayRegular { - id: orText - - anchors.left: categoriesButton.right - anchors.verticalCenter: parent.verticalCenter - width: 25 - - text: "or" - size: 18; - color: hifi.colors.baseGray - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - rightPadding: 10 - leftPadding: 10 - } - - HifiControlsUit.TextField { - id: searchField - - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - left: orText.right - rightMargin: 10 - } - height: 34 - - isSearchField: true - colorScheme: hifi.colorSchemes.faintGray - font.family: "Fira Sans" - font.pixelSize: hifi.fontSizes.textFieldInput - placeholderText: "Search Marketplace" - - Timer { - id: keypressTimer - running: false - repeat: false - interval: 300 - onTriggered: searchField.accepted() - - } - - // workaround for https://bugreports.qt.io/browse/QTBUG-49297 - Keys.onPressed: { - switch (event.key) { - case Qt.Key_Return: - case Qt.Key_Enter: - event.accepted = true; - keypressTimer.stop(); - root.searchString = searchField.text; - searchField.text = ""; - - getMarketplaceItems(); - searchField.forceActiveFocus(); - break; - default: - keypressTimer.restart(); - break; - } - } - - onAccepted: { - if (root.searchString !== searchField.text) { - root.searchString = searchField.text; - getMarketplaceItems(); - searchField.forceActiveFocus(); - } - } - - onActiveFocusChanged: { - root.keyboardRaised = activeFocus; - } - - } - } - } - // - // HEADER BAR END - // - - // - // CATEGORIES LIST START - // - Item { - id: categoriesDropdown - - anchors.fill: parent; - anchors.topMargin: 2 - - visible: false - z: 10 - MouseArea { - anchors.fill: parent - propagateComposedEvents: true - onClicked: { - categoriesDropdown.visible = false; - categoriesButton.color = hifi.colors.white; - } - } - - Rectangle { - anchors { - left: parent.left - bottom: parent.bottom - top: parent.top - topMargin: 100 - } - width: parent.width*2/3 - - color: hifi.colors.white - - ListModel { - id: categoriesModel - } - - ListView { - id: categoriesListView; - - anchors.fill: parent - anchors.rightMargin: 10 - width: parent.width - currentIndex: -1; - clip: true - - model: categoriesModel - delegate: ItemDelegate { - id: categoriesItemDelegate - height: 34 - width: parent.width - - clip: true - contentItem: Rectangle { - id: categoriesItem - - anchors.fill: parent - - color: hifi.colors.white - visible: true - border.color: hifi.colors.blueHighlight - border.width: 0 - - RalewaySemiBold { - id: categoriesItemText - - anchors.leftMargin: 15 - anchors.top:parent.top - anchors.bottom: parent.bottom - anchors.left: categoryItemCount.right - - elide: Text.ElideRight - text: model.name - color: categoriesItemDelegate.ListView.isCurrentItem ? hifi.colors.blueHighlight : hifi.colors.baseGray - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - size: 14 - } - Rectangle { - id: categoryItemCount - anchors { - top: parent.top - bottom: parent.bottom - topMargin: 7 - bottomMargin: 7 - leftMargin: 10 - rightMargin: 10 - left: parent.left - } - width: childrenRect.width - color: hifi.colors.faintGray - radius: height/2 - - RalewaySemiBold { - anchors.top: parent.top - anchors.bottom: parent.bottom - width: 50 - - text: model.count - color: hifi.colors.lightGrayText - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - size: 16 - } - } - } - MouseArea { - anchors.fill: parent - z: 10 - hoverEnabled: true - propagateComposedEvents: false - - onPositionChanged: { - // Must use onPositionChanged and not onEntered - // due to a QML bug where a mouseenter event was - // being fired on open of the categories list even - // though the mouse was outside the borders - categoriesItem.border.width = 2; - } - onExited: { - categoriesItem.border.width = 0; - } - - onCanceled: { - categoriesItem.border.width = 0; - } - - onClicked: { - categoriesListView.currentIndex = index; - categoriesText.text = categoriesItemText.text; - categoriesDropdown.visible = false; - categoriesButton.color = hifi.colors.white; - root.categoryString = categoriesItemText.text; - getMarketplaceItems(); - } - } - } - - ScrollBar.vertical: ScrollBar { - parent: categoriesListView.parent - - anchors { - top: categoriesListView.top - bottom: categoriesListView.bottom - left: categoriesListView.right - } - - contentItem.opacity: 1 - } - } - } - } - // - // CATEGORIES LIST END - // - - // - // ITEMS LIST START - // - Item { - id: itemsList - - anchors { - fill: parent - topMargin: 115 - bottomMargin: 50 - } - - visible: true - - HifiModels.PSFListModel { - id: marketBrowseModel - - itemsPerPage: 7 - listModelName: 'marketBrowse' - listView: marketBrowseList - - getPage: function () { - MarketplaceScriptingInterface.getMarketplaceItems( - root.searchString === "" ? undefined : root.searchString, - "", - root.categoryString.toLowerCase(), - "", - "", - root.sortString, - root.isAscending, - WalletScriptingInterface.limitedCommerce, - marketBrowseModel.currentPageToRetrieve, - marketBrowseModel.itemsPerPage - ); - } - - processPage: function(data) { - return data.items; - } - } - ListView { - id: marketBrowseList - - anchors.fill: parent - anchors.rightMargin: 10 - - model: marketBrowseModel - - orientation: ListView.Vertical - focus: true - clip: true - - delegate: MarketplaceListItem { - item_id: model.id - - anchors.topMargin: 10 - - image_url:model.thumbnail_url - name: model.title - likes: model.likes - liked: model.has_liked ? model.has_liked : false - creator: model.creator - category: model.primary_category - price: model.cost - availability: model.availability - isLoggedIn: root.isLoggedIn; - standaloneOptimized: model.standalone_optimized - - onShowItem: { - // reset the edition back to -1 to clear the 'update item' status - marketplaceItem.edition = -1; - MarketplaceScriptingInterface.getMarketplaceItem(item_id); - } - - onBuy: { - sendToScript({method: 'marketplace_checkout', itemId: item_id}); - } - - onCategoryClicked: { - root.categoryString = category; - categoriesText.text = category; - getMarketplaceItems(); - } - - onRequestReload: getMarketplaceItems(); - } - - ScrollBar.vertical: ScrollBar { - parent: marketBrowseList.parent - - anchors { - top: marketBrowseList.top - bottom: marketBrowseList.bottom - left: marketBrowseList.right - } - - contentItem.opacity: 1 - } - - headerPositioning: ListView.InlineHeader - - header: Item { - id: itemsHeading - - height: childrenRect.height - width: parent.width - - Rectangle { - id: itemsSpacer; - height: 20 - } - - Rectangle { - id: itemsLoginStatus; - anchors { - top: itemsSpacer.bottom - left: parent.left - right: parent.right - leftMargin: 15 - } - height: root.isLoggedIn ? 0 : 80 - - visible: !root.isLoggedIn - color: hifi.colors.greenHighlight - border.color: hifi.colors.greenShadow - border.width: 1 - radius: 4 - z: 10000 - - HifiControlsUit.Button { - id: loginButton; - anchors { - left: parent.left - top: parent.top - bottom: parent.bottom - leftMargin: 15 - topMargin:10 - bottomMargin: 10 - } - width: 80; - - text: "LOG IN" - - onClicked: { - sendToScript({method: 'marketplace_loginClicked'}); - } - } - - RalewayRegular { - id: itemsLoginText - - anchors { - leftMargin: 15 - top: parent.top; - bottom: parent.bottom; - right: parent.right; - left: loginButton.right - } - - text: "to get items from the Marketplace." - color: hifi.colors.baseGray - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - size: 18 - } - } - - Item { - id: breadcrumbs - - anchors.top: itemsLoginStatus.bottom; - anchors.left: parent.left - anchors.right: parent.right - height: 34 - visible: categoriesListView.currentIndex >= 0 - - RalewayRegular { - id: categoriesItemText - - anchors.leftMargin: 15 - anchors.fill:parent - - text: "Home /" - color: hifi.colors.blueHighlight - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - size: 18 - } - - MouseArea { - anchors.fill: parent - - onClicked: { - categoriesListView.currentIndex = -1; - categoriesText.text = "Categories"; - root.categoryString = ""; - searchField.text = ""; - getMarketplaceItems(); - } - } - } - - Item { - id: searchScope - - anchors { - top: breadcrumbs.bottom - left: parent.left - right: parent.right - } - height: 50 - - RalewaySemiBold { - id: searchScopeText; - - anchors { - leftMargin: 15 - fill:parent - topMargin: 10 - } - - text: searchScopeString - color: hifi.colors.baseGray - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - size: 22 - } - } - Item { - id: sort - visible: searchString === undefined || searchString === "" - - anchors { - top: searchScope.bottom; - left: parent.left; - right: parent.right; - topMargin: 10; - leftMargin: 15; - } - height: visible ? 36 : 0 - - RalewayRegular { - id: sortText - - anchors.leftMargin: 15 - anchors.rightMargin: 20 - height: 34 - - text: "Sort:" - color: hifi.colors.lightGrayText - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - size: 14 - } - - Rectangle { - anchors { - left: sortText.right - top: parent.top - leftMargin: 20 - } - - width: root.isLoggedIn ? 342 : 262 - height: parent.height - - radius: 4 - border.width: 1 - border.color: hifi.colors.faintGray - - ListModel { - id: sortModel - - ListElement { - name: "Name" - sortString: "alpha" - ascending: true - } - - ListElement { - name: "Date" - sortString: "recent" - ascending: false - } - - ListElement { - name: "Popular" - sortString: "likes" - ascending: false - } - - ListElement { - name: "My Likes" - sortString: "my_likes" - ascending: false - } - } - - ListView { - id: sortListView - - anchors { - top: parent.top - bottom: parent.bottom - left: parent.left - topMargin:1 - bottomMargin:1 - leftMargin:1 - rightMargin:1 - } - width: childrenRect.width - height: 34 - - orientation: ListView.Horizontal - focus: true - clip: true - highlightFollowsCurrentItem: false - currentIndex: 1; - - delegate: SortButton { - width: 85 - height: parent.height - - ascending: model.ascending - text: model.name - - visible: root.isLoggedIn || model.sortString != "my_likes" - - checked: ListView.isCurrentItem - - onClicked: { - if(root.currentSortIndex == index) { - ascending = !ascending; - } else { - ascending = model.ascending; - } - root.isAscending = ascending; - root.currentSortIndex = index; - sortListView.positionViewAtIndex(index, ListView.Beginning); - sortListView.currentIndex = index; - root.sortString = model.sortString; - getMarketplaceItems(); - } - } - highlight: Rectangle { - width: 85 - height: parent.height - - color: hifi.colors.faintGray - x: sortListView.currentItem.x - } - - model: sortModel - } - } - } - } - } - } - - // - // ITEMS LIST END - // - - // - // ITEM START - // - Item { - id: marketplaceItemView - - anchors.fill: parent - anchors.topMargin: 115 - anchors.bottomMargin: 50 - width: parent.width - - visible: false - - ScrollView { - id: marketplaceItemScrollView - - anchors.fill: parent - - clip: true - ScrollBar.vertical.policy: ScrollBar.AlwaysOn - contentWidth: parent.width - contentHeight: childrenRect.height - - function resize() { - contentHeight = (marketplaceItemContent.y - itemSpacer.y + marketplaceItemContent.height); - } - - Item { - id: itemSpacer - anchors.top: parent.top - height: 15 - } - - Rectangle { - id: itemLoginStatus; - anchors { - left: parent.left - right: parent.right - top: itemSpacer.bottom - topMargin: 10 - leftMargin: 15 - rightMargin: 15 - } - height: root.isLoggedIn ? 0 : 80 - - visible: !root.isLoggedIn - color: hifi.colors.greenHighlight - border.color: hifi.colors.greenShadow - border.width: 1 - radius: 4 - z: 10000 - - HifiControlsUit.Button { - id: loginButton; - anchors { - left: parent.left - top: parent.top - bottom: parent.bottom - leftMargin: 15 - topMargin:10 - bottomMargin: 10 - } - width: 80; - - text: "LOG IN" - - onClicked: { - sendToScript({method: 'marketplace_loginClicked'}); - } - } - - RalewayRegular { - id: itemsLoginText - - anchors { - leftMargin: 15 - top: parent.top; - bottom: parent.bottom; - right: parent.right; - left: loginButton.right - } - - text: "to get items from the Marketplace." - color: hifi.colors.baseGray - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - size: 18 - } - } - - - Rectangle { - id: marketplaceItemContent - anchors.top: itemLoginStatus.bottom - width: parent.width - height: childrenRect.height; - - RalewaySemiBold { - id: backText - - anchors { - top: parent.top - left: parent.left - topMargin: 10 - leftMargin: 15 - bottomMargin: 10 - } - width: paintedWidth - height: paintedHeight - - text: "Back" - size: hifi.fontSizes.overlayTitle - color: hifi.colors.blueHighlight - verticalAlignment: Text.AlignVCenter - } - - MouseArea { - anchors.fill: backText - - onClicked: { - getMarketplaceItems(); - } - } - - MarketplaceItem { - id: marketplaceItem - - - anchors.topMargin: 15 - anchors.top: backText.bottom - width: parent.width - height: childrenRect.height - - isLoggedIn: root.isLoggedIn; - - onBuy: { - sendToScript({method: 'marketplace_checkout', itemId: item_id, itemEdition: edition}); - } - - onShowLicense: { - var xhr = new XMLHttpRequest; - xhr.open("GET", url); - xhr.onreadystatechange = function() { - if (xhr.readyState == XMLHttpRequest.DONE) { - licenseText.text = xhr.responseText; - licenseInfo.visible = true; - } - }; - xhr.send(); - } - onCategoryClicked: { - root.categoryString = category; - categoriesText.text = category; - getMarketplaceItems(); - } - - onResized: { - marketplaceItemScrollView.resize(); - } - } - } - } - } - // - // ITEM END - // - - // - // FOOTER START - // - - Rectangle { - id: footer - - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - height: 50 - - color: hifi.colors.blueHighlight - - Item { - anchors { - fill: parent - rightMargin: 15 - leftMargin: 15 - } - - - - Item { - id: footerText - - anchors.fill: parent - visible: root.supports3DHTML && itemsList.visible - - HiFiGlyphs { - id: footerGlyph - - anchors { - left: parent.left - top: parent.top - bottom: parent.bottom - rightMargin: 10 - } - - text: hifi.glyphs.info - size: 34 - color: hifi.colors.white - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - - RalewaySemiBold { - id: footerInfo - - anchors { - left: footerGlyph.right - top: parent.top - bottom: parent.bottom - } - - text: "Get items from Clara.io!" - color: hifi.colors.white - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - size: 18 - } - } - - HifiControlsUit.Button { - anchors { - left: parent.left - top: parent.top - bottom: parent.bottom - topMargin: 10 - bottomMargin: 10 - leftMargin: 10 - rightMargin: 10 - } - - visible: marketplaceItemView.visible - text: "< BACK" - width: 100 - - onClicked: { - marketplaceItemView.visible = false; - itemsList.visible = true; - licenseInfo.visible = false; - } - } - - HifiControlsUit.Button { - anchors { - right: parent.right - top: parent.top - bottom: parent.bottom - topMargin: 10 - bottomMargin: 10 - leftMargin: 10 - rightMargin: 10 - } - - visible: root.supports3DHTML - - text: "SEE ALL MARKETS" - width: 180 - - onClicked: { - sendToScript({method: 'marketplace_marketplaces', itemId: marketplaceItemView.visible ? marketplaceItem.item_id : undefined}); - } - } - } - } - // - // FOOTER END - // - - - // - // LICENSE START - // - Rectangle { - id: licenseInfo - - anchors { - fill: root - topMargin: 120 - bottomMargin: 0 - } - - visible: false; - - ScrollView { - anchors { - bottomMargin: 1 - topMargin: 60 - leftMargin: 15 - fill: parent - } - - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - - RalewayRegular { - id: licenseText - - width:440 - wrapMode: Text.Wrap - - text: "" - size: 18; - color: hifi.colors.baseGray - } - } - - Item { - id: licenseClose - - anchors { - top: parent.top - right: parent.right - topMargin: 10 - rightMargin: 10 - } - width: 30 - height: 30 - - HiFiGlyphs { - anchors { - fill: parent - rightMargin: 0 - verticalCenter: parent.verticalCenter - } - height: 30 - - text: hifi.glyphs.close - size: 34 - horizontalAlignment: Text.AlignHCenter - color: hifi.colors.baseGray - } - - MouseArea { - anchors.fill: licenseClose - - onClicked: licenseInfo.visible = false; - } - } - } - // - // LICENSE END - // - - HifiControlsUit.Keyboard { - id: keyboard - - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - - raised: parent.keyboardEnabled && parent.keyboardRaised - numeric: false - } - - // - // Function Name: fromScript() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the JavaScript, in this case the Marketplaces JavaScript. - // Messages are in format "{method, params}", like json-rpc. - // - // Description: - // Called when a message is received from a script. - // - - function fromScript(message) { - switch (message.method) { - case 'updateMarketplaceQMLItem': - if (!message.params.itemId) { - console.log("A message with method 'updateMarketplaceQMLItem' was sent without an itemId!"); - return; - } - pendingGetMarketplaceItemCall = true; - marketplaceItem.edition = message.params.edition ? message.params.edition : -1; - MarketplaceScriptingInterface.getMarketplaceItem(message.params.itemId); - break; - } - } -} diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml deleted file mode 100644 index ce692c04d9c..00000000000 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceItem.qml +++ /dev/null @@ -1,725 +0,0 @@ -// -// MarketplaceListItem.qml -// qml/hifi/commerce/marketplace -// -// MarketplaceItem -// -// Created by Roxanne Skelly on 2019-01-22 -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import stylesUit 1.0 -import QtGraphicalEffects 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../common" as HifiCommerceCommon -import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. -import "../common/sendAsset" -import "../.." as HifiCommon - -Rectangle { - id: root; - - property string item_id: "" - property string image_url: "" - property string name: "" - property int likes: 0 - property bool liked: false - property string creator: "" - property var categories: [] - property int price: 0 - property string availability: "unknown" - property string updated_item_id: "" - property var attributions: [] - property string description: "" - property string license: "" - property string posted: "" - property string created_at: "" - property bool isLoggedIn: false - property int edition: -1 - property bool supports3DHTML: false - property bool standaloneVisible: false - property bool standaloneOptimized: false - - onCategoriesChanged: { - categoriesListModel.clear(); - categories.forEach(function(category) { - categoriesListModel.append({"category":category}); - }); - } - - onDescriptionChanged: { - descriptionText.text = description; - } - - onAttributionsChanged: { - attributionsModel.clear(); - if(root.attributions) { - root.attributions.forEach(function(attribution) { - attributionsModel.append(attribution); - }); - } - footer.evalHeight(); - } - - signal buy() - signal categoryClicked(string category) - signal showLicense(string url) - - HifiConstants { - id: hifi - } - - Connections { - target: MarketplaceScriptingInterface - - onMarketplaceItemLikeResult: { - if (result.status !== 'success') { - console.log("Like/Unlike item", result.data.message); - } else { - root.liked = !root.liked; - root.likes = root.liked ? root.likes + 1 : root.likes - 1; - } - } - } - function getFormattedDate(timestamp) { - function addLeadingZero(n) { - return n < 10 ? '0' + n : '' + n; - } - - var a = new Date(timestamp); - - var year = a.getFullYear(); - var month = addLeadingZero(a.getMonth() + 1); - var day = addLeadingZero(a.getDate()); - var hour = a.getHours(); - var drawnHour = hour; - if (hour === 0) { - drawnHour = 12; - } else if (hour > 12) { - drawnHour -= 12; - } - drawnHour = addLeadingZero(drawnHour); - - var amOrPm = "AM"; - if (hour >= 12) { - amOrPm = "PM"; - } - - var min = addLeadingZero(a.getMinutes()); - var sec = addLeadingZero(a.getSeconds()); - return a.toDateString() + " " + drawnHour + ':' + min + amOrPm; - } - function evalHeight() { - height = footer.y - header.y + footer.height; - } - - signal resized() - - onHeightChanged: { - resized(); - } - - anchors { - left: parent.left - right: parent.right - leftMargin: 15 - rightMargin: 15 - } - height: footer.y - header.y + footer.height - - Rectangle { - id: header - - anchors { - left: parent.left - right: parent.right - top: parent.top - } - height: 50 - - RalewaySemiBold { - id: nameText - - anchors { - top: parent.top - left: parent.left - bottom: parent.bottom - } - width: paintedWidth - - text: root.name - size: 24 - color: hifi.colors.baseGray - verticalAlignment: Text.AlignVCenter - } - - Item { - id: likes - - anchors { - top: parent.top - right: parent.right - bottom: parent.bottom - rightMargin: 5 - } - - RalewaySemiBold { - id: heart - - anchors { - top: parent.top - right: parent.right - rightMargin: 0 - verticalCenter: parent.verticalCenter - } - - text: "\u2665" - size: 20 - horizontalAlignment: Text.AlignHCenter - color: root.liked ? hifi.colors.redAccent : hifi.colors.lightGrayText - } - - RalewaySemiBold { - id: likesText - - anchors { - top: parent.top - right: heart.left - rightMargin: 5 - leftMargin: 15 - bottom: parent.bottom - } - width: paintedWidth - - text: root.likes - size: hifi.fontSizes.overlayTitle - color: hifi.colors.baseGray - verticalAlignment: Text.AlignVCenter - } - - MouseArea { - anchors { - left: likesText.left - right: heart.right - top: likesText.top - bottom: likesText.bottom - } - - onClicked: { - if (isLoggedIn) { - MarketplaceScriptingInterface.marketplaceItemLike(root.item_id, !root.liked); - } - } - } - } - } - - Image { - id: itemImage - - anchors { - top: header.bottom - left: parent.left - right: parent.right - } - height: width*0.5625 - - source: root.image_url - fillMode: Image.PreserveAspectCrop; - } - - Item { - id: footer - - anchors { - left: parent.left; - right: parent.right; - top: itemImage.bottom; - } - height: categoriesList.y - badges.y + categoriesList.height - - function evalHeight() { - height = categoriesList.y - badges.y + categoriesList.height; - } - - Item { - id: badges - - anchors { - right: buyButton.left - top: parent.top - rightMargin: 10 - } - height: childrenRect.height - - Image { - id: standaloneOptomizedBadge - - anchors { - topMargin: 15 - right: parent.right - top: parent.top - } - height: root.standaloneOptimized ? 50 : 0 - width: 50 - - visible: root.standaloneOptimized - fillMode: Image.PreserveAspectFit - source: "../../../../icons/standalone-optimized.svg" - } - ColorOverlay { - anchors.fill: standaloneOptomizedBadge - source: standaloneOptomizedBadge - color: hifi.colors.blueHighlight - visible: root.standaloneOptimized - } - } - - HifiControlsUit.Button { - id: buyButton - - anchors { - right: parent.right - top: parent.top - topMargin: 15 - } - height: 50 - width: 180 - - property bool isUpdate: root.edition >= 0 // Special case of updating from a specific older item - property bool isStocking: (creator === Account.username) && (availability === "not for sale") && !updated_item_id // Note: server will say "sold out" or "invalidated" before it says NFS - property bool isFreeSpecial: isStocking || isUpdate - enabled: isFreeSpecial || (availability === 'available') - buttonGlyph: (enabled && !isUpdate && (price > 0)) ? hifi.glyphs.hfc : "" - text: isUpdate ? "UPDATE" : (isStocking ? "FREE STOCK" : (enabled ? (price || "FREE") : availability)) - color: hifi.buttons.blue - - buttonGlyphSize: 24 - fontSize: 24 - - onClicked: root.buy(); - } - - Item { - id: creatorItem - - anchors { - top: parent.top - leftMargin: 15 - topMargin: 15 - } - width: paintedWidth - height: childrenRect.height - - RalewaySemiBold { - id: creatorLabel - - anchors.top: parent.top - anchors.left: parent.left - width: paintedWidth - - text: "CREATOR:" - size: 14 - color: hifi.colors.lightGrayText - verticalAlignment: Text.AlignVCenter - } - - RalewaySemiBold { - id: creatorText - - anchors { - top: creatorLabel.bottom - left: parent.left - topMargin: 10 - } - width: paintedWidth - text: root.creator - - size: 18 - color: hifi.colors.blueHighlight - verticalAlignment: Text.AlignVCenter - } - } - - Item { - id: posted - - anchors { - top: creatorItem.bottom - leftMargin: 15 - topMargin: 15 - } - width: parent.width - height: childrenRect.height - - RalewaySemiBold { - id: postedLabel - - anchors.top: parent.top - anchors.left: parent.left - width: paintedWidth - - text: "POSTED:" - size: 14 - color: hifi.colors.lightGrayText - verticalAlignment: Text.AlignVCenter - } - - RalewaySemiBold { - id: created_at - - anchors { - top: postedLabel.bottom - left: parent.left - right: parent.right - topMargin: 5 - } - - text: { getFormattedDate(root.created_at); } - size: 14 - color: hifi.colors.lightGray - verticalAlignment: Text.AlignVCenter - } - } - - Rectangle { - - anchors { - top: posted.bottom - leftMargin: 15 - topMargin: 15 - } - width: parent.width - height: 1 - - color: hifi.colors.lightGrayText - } - - Item { - id: attributions - - anchors { - top: posted.bottom - topMargin: 30 - left: parent.left - right: parent.right - } - width: parent.width - height: attributionsModel.count > 0 ? childrenRect.height : 0 - visible: attributionsModel.count > 0 - - RalewaySemiBold { - id: attributionsLabel - - anchors.top: parent.top - anchors.left: parent.left - width: paintedWidth - height: paintedHeight - - text: "ATTRIBUTIONS:" - size: 14 - color: hifi.colors.lightGrayText - verticalAlignment: Text.AlignVCenter - } - ListModel { - id: attributionsModel - } - - ListView { - anchors { - left: parent.left - right: parent.right - top: attributionsLabel.bottom - bottomMargin: 15 - } - - height: 24*model.count+10 - - model: attributionsModel - delegate: Item { - height: 24 - width: parent.width - RalewaySemiBold { - id: attributionName - - anchors.leftMargin: 15 - height: 24 - width: parent.width - - text: model.name - elide: Text.ElideRight - size: 14 - - color: (model.link && root.supports3DHTML)? hifi.colors.blueHighlight : hifi.colors.baseGray - verticalAlignment: Text.AlignVCenter - MouseArea { - anchors.fill: parent - - onClicked: { - if (model.link && root.supports3DHTML) { - sendToScript({method: 'marketplace_open_link', link: model.link}); - } - } - } - } - } - } - Rectangle { - - anchors { - bottom: attributions.bottom - leftMargin: 15 - } - width: parent.width - height: 1 - - color: hifi.colors.lightGrayText - } - } - Item { - id: licenseItem; - - anchors { - top: attributions.bottom - left: parent.left - topMargin: 15 - } - width: parent.width - height: childrenRect.height - - RalewaySemiBold { - id: licenseLabel - - anchors.top: parent.top; - anchors.left: parent.left; - width: paintedWidth; - - text: "SHARED UNDER:"; - size: 14; - color: hifi.colors.lightGrayText; - verticalAlignment: Text.AlignVCenter; - } - - RalewaySemiBold { - id: licenseText - - anchors.top: licenseLabel.bottom - anchors.left: parent.left - anchors.topMargin: 5 - width: paintedWidth - - text: root.license - size: 14 - color: hifi.colors.lightGray - verticalAlignment: Text.AlignVCenter - } - - RalewaySemiBold { - id: licenseHelp - - anchors.top: licenseText.bottom - anchors.left: parent.left - anchors.topMargin: 5 - width: paintedWidth - - text: "More about this license" - size: 14 - color: hifi.colors.blueHighlight - verticalAlignment: Text.AlignVCenter - - MouseArea { - anchors.fill: parent - - onClicked: { - licenseInfo.visible = true; - var url; - if (root.license === "No Rights Reserved (CC0)") { - url = "https://creativecommons.org/publicdomain/zero/1.0/" - } else if (root.license === "Attribution (CC BY)") { - url = "https://creativecommons.org/licenses/by/4.0/legalcode.txt" - } else if (root.license === "Attribution-ShareAlike (CC BY-SA)") { - url = "https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt" - } else if (root.license === "Attribution-NoDerivs (CC BY-ND)") { - url = "https://creativecommons.org/licenses/by-nd/4.0/legalcode.txt" - } else if (root.license === "Attribution-NonCommercial (CC BY-NC)") { - url = "https://creativecommons.org/licenses/by-nc/4.0/legalcode.txt" - } else if (root.license === "Attribution-NonCommercial-ShareAlike (CC BY-NC-SA)") { - url = "https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.txt" - } else if (root.license === "Attribution-NonCommercial-NoDerivs (CC BY-NC-ND)") { - url = "https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode.txt" - } else if (root.license === "Proof of Provenance License (PoP License)") { - url = "licenses/Popv1.txt" - } - if(url) { - showLicense(url) - } - } - } - } - } - - Item { - id: standaloneItem - - anchors { - top: licenseItem.bottom - topMargin: 15 - left: parent.left - right: parent.right - } - height: root.standaloneVisible ? childrenRect.height : 0 - - visible: root.standaloneVisible - - RalewaySemiBold { - id: standaloneLabel - - anchors.top: parent.top - anchors.left: parent.left - width: paintedWidth - height: 20 - - text: root.standaloneOptimized ? "STAND-ALONE OPTIMIZED:" : "STAND-ALONE INCOMPATIBLE:" - size: 14 - color: hifi.colors.lightGrayText - verticalAlignment: Text.AlignVCenter - } - - RalewaySemiBold { - id: standaloneOptimizedText - - anchors.top: standaloneLabel.bottom - anchors.left: parent.left - anchors.topMargin: 5 - width: paintedWidth - - text: root.standaloneOptimized ? "This item is stand-alone optimized" : "This item is incompatible with stand-alone devices" - size: 14 - color: hifi.colors.lightGray - verticalAlignment: Text.AlignVCenter - } - } - - Item { - id: descriptionItem - property string text: "" - - anchors { - top: standaloneItem.bottom - topMargin: 15 - left: parent.left - right: parent.right - } - height: childrenRect.height - onHeightChanged: { - footer.evalHeight(); - } - RalewaySemiBold { - id: descriptionLabel - - anchors.top: parent.top - anchors.left: parent.left - width: paintedWidth - height: 20 - - text: "DESCRIPTION:" - size: 14 - color: hifi.colors.lightGrayText - verticalAlignment: Text.AlignVCenter - } - - RalewaySemiBold { - id: descriptionText - - anchors.top: descriptionLabel.bottom - anchors.left: parent.left - anchors.topMargin: 5 - width: parent.width - - text: root.description - size: 14 - color: hifi.colors.lightGray - linkColor: root.supports3DHTML ? hifi.colors.blueHighlight : hifi.colors.lightGray - verticalAlignment: Text.AlignVCenter - textFormat: Text.RichText - wrapMode: Text.Wrap - onLinkActivated: { - if (root.supports3DHTML) { - sendToScript({method: 'marketplace_open_link', link: link}); - } - } - - onHeightChanged: { footer.evalHeight(); } - } - } - - Item { - id: categoriesList - - anchors { - top: descriptionItem.bottom - topMargin: 15 - left: parent.left - right: parent.right - } - width: parent.width - height: categoriesListModel.count*24 + categoryLabel.height + (isLoggedIn ? 50 : 150) - - onHeightChanged: { footer.evalHeight(); } - - RalewaySemiBold { - id: categoryLabel - - anchors.top: parent.top - anchors.left: parent.left - width: paintedWidth - - text: "IN:" - size: 14 - color: hifi.colors.lightGrayText - verticalAlignment: Text.AlignVCenter - } - ListModel { - id: categoriesListModel - } - - ListView { - anchors { - left: parent.left - right: parent.right - top: categoryLabel.bottom - bottomMargin: 15 - } - - height: 24*model.count+10 - - model: categoriesListModel - delegate: RalewaySemiBold { - id: categoryText - - anchors.leftMargin: 15 - width: paintedWidth - - text: model.category - size: 14 - height: 24 - color: hifi.colors.blueHighlight - verticalAlignment: Text.AlignVCenter - - MouseArea { - anchors.fill: categoryText - - onClicked: root.categoryClicked(model.category); - } - } - } - } - } -} diff --git a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml b/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml deleted file mode 100644 index 8ad6191f04a..00000000000 --- a/interface/resources/qml/hifi/commerce/marketplace/MarketplaceListItem.qml +++ /dev/null @@ -1,369 +0,0 @@ -// -// MarketplaceListItem.qml -// qml/hifi/commerce/marketplace -// -// MarketplaceListItem -// -// Created by Roxanne Skelly on 2019-01-22 -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../common" as HifiCommerceCommon -import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. -import "../common/sendAsset" -import "../.." as HifiCommon - -Rectangle { - id: root - - property string item_id: "" - property string image_url: "" - property string name: "" - property int likes: 0 - property bool liked: false - property string creator: "" - property string category: "" - property int price: 0 - property string availability: "unknown" - property bool isLoggedIn: false - property bool standaloneOptimized: false - - signal buy() - signal showItem() - signal categoryClicked(string category) - signal requestReload() - - HifiConstants { id: hifi } - - width: parent.width - height: childrenRect.height+50 - - DropShadow { - anchors.fill: shadowBase - - source: shadowBase - verticalOffset: 4 - horizontalOffset: 4 - radius: 6 - samples: 9 - color: hifi.colors.baseGrayShadow - } - - Rectangle { - id: shadowBase - - anchors.fill: itemRect - - color: "white" - } - - Rectangle { - id: itemRect - - anchors { - left: parent.left - right: parent.right - top: parent.top - topMargin: 20 - bottomMargin: 10 - leftMargin: 15 - rightMargin: 15 - } - height: childrenRect.height - - MouseArea { - anchors.fill: parent - - hoverEnabled: true - - onClicked: root.showItem(); - onEntered: hoverRect.visible = true; - onExited: hoverRect.visible = false; - - } - - Rectangle { - id: header - - anchors { - left: parent.left - right: parent.right - top: parent.top - } - height: 50 - - RalewaySemiBold { - id: nameText - - anchors { - top: parent.top - left: parent.left - right: parent.right - rightMargin: 50 - leftMargin: 15 - bottom: parent.bottom - } - width: paintedWidth - - text: root.name - size: hifi.fontSizes.overlayTitle - elide: Text.ElideRight - color: hifi.colors.blueHighlight - verticalAlignment: Text.AlignVCenter - } - - Item { - id: likes - - anchors { - top: parent.top - right: parent.right - rightMargin: 15 - bottom: parent.bottom - } - width: heart.width + likesText.width - - Connections { - target: MarketplaceScriptingInterface - - onMarketplaceItemLikeResult: { - if (result.status !== 'success') { - console.log("Failed to get Marketplace Categories", result.data.message); - root.requestReload(); - } - } - } - - RalewaySemiBold { - id: heart - - anchors { - top: parent.top - right: parent.right - rightMargin: 0 - verticalCenter: parent.verticalCenter - } - - text: "\u2665" - size: 20 - horizontalAlignment: Text.AlignHCenter; - color: root.liked ? hifi.colors.redAccent : hifi.colors.lightGrayText - } - - RalewaySemiBold { - id: likesText - - anchors { - top: parent.top - right: heart.left - rightMargin: 5 - leftMargin: 15 - bottom: parent.bottom - } - width: paintedWidth - - text: root.likes - size: hifi.fontSizes.overlayTitle - color: hifi.colors.baseGray - verticalAlignment: Text.AlignVCenter - } - - MouseArea { - anchors { - left: likesText.left - right: heart.right - top: parent.top - bottom: parent.bottom - } - onClicked: { - if (isLoggedIn) { - root.liked = !root.liked; - root.likes = root.liked ? root.likes + 1 : root.likes - 1; - MarketplaceScriptingInterface.marketplaceItemLike(root.item_id, root.liked); - } - } - } - } - } - - Image { - id: itemImage - - anchors { - top: header.bottom - left: parent.left - right: parent.right - } - height: width * 0.5625 - - source: root.image_url - fillMode: Image.PreserveAspectCrop - } - - Item { - id: footer - - anchors { - left: parent.left - right: parent.right - top: itemImage.bottom - } - height: 60 - - RalewaySemiBold { - id: creatorLabel - - anchors { - top: parent.top - left: parent.left - leftMargin: 15 - topMargin: 10 - } - width: paintedWidth - - text: "CREATOR:" - size: 14 - color: hifi.colors.lightGrayText - verticalAlignment: Text.AlignVCenter - } - - RalewaySemiBold { - id: creatorText - - anchors { - top: creatorLabel.top - left: creatorLabel.right - leftMargin: 15 - right: badges.left - } - width: paintedWidth - - text: root.creator - size: 14 - elide: Text.ElideRight - color: hifi.colors.lightGray - verticalAlignment: Text.AlignVCenter - } - - RalewaySemiBold { - id: categoryLabel - - anchors { - top: creatorLabel.bottom - left: parent.left - leftMargin: 15 - } - width: paintedWidth - - text: "IN:" - size: 14 - color: hifi.colors.lightGrayText - verticalAlignment: Text.AlignVCenter - } - - RalewaySemiBold { - id: categoryText - - anchors { - top: categoryLabel.top - left: categoryLabel.right - leftMargin: 15 - right: badges.left - } - width: paintedWidth - - text: root.category - size: 14 - color: hifi.colors.blueHighlight - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - MouseArea { - anchors.fill: parent - - onClicked: root.categoryClicked(root.category); - } - } - Item { - id: badges - - anchors { - right: buyButton.left - top: parent.top - topMargin: 10 - rightMargin: 10 - } - height: 50 - - Image { - id: standaloneOptomizedBadge - - anchors { - right: parent.right - top: parent.top - } - height: root.standaloneOptimized ? 40 : 0 - width: 40 - - visible: root.standaloneOptimized - fillMode: Image.PreserveAspectFit - source: "../../../../icons/standalone-optimized.svg" - } - ColorOverlay { - anchors.fill: standaloneOptomizedBadge - source: standaloneOptomizedBadge - color: hifi.colors.blueHighlight - visible: root.standaloneOptimized - } - } - - HifiControlsUit.Button { - id: buyButton - anchors { - right: parent.right - top: parent.top - bottom: parent.bottom - rightMargin: 15 - topMargin:10 - bottomMargin: 10 - } - width: 180 - - property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS - property bool isMine: creator === Account.username - property bool isUpgrade: root.edition >= 0 - property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price - property bool isAvailable: availability === "available" - - text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : availability) - enabled: isAvailable - buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : "" - - color: hifi.buttons.blue; - buttonGlyphSize: 24 - fontSize: 24 - onClicked: root.buy(); - } - } - - Rectangle { - id: hoverRect - - anchors.fill: parent - - border.color: hifi.colors.blueHighlight - border.width: 2 - color: "#00000000" - visible: false - } - } -} diff --git a/interface/resources/qml/hifi/commerce/marketplace/SortButton.qml b/interface/resources/qml/hifi/commerce/marketplace/SortButton.qml deleted file mode 100644 index 2673043b6b9..00000000000 --- a/interface/resources/qml/hifi/commerce/marketplace/SortButton.qml +++ /dev/null @@ -1,89 +0,0 @@ -// -// SortButton.qml -// qml/hifi/commerce/marketplace -// -// SortButton -// -// Created by Roxanne Skelly on 2019-01-18 -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../common" as HifiCommerceCommon -import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. -import "../common/sendAsset" -import "../.." as HifiCommon - -Item { - HifiConstants { id: hifi; } - - id: root; - - property string ascGlyph: "\u2193" - property string descGlyph: "\u2191" - property string text: "" - property bool ascending: false - property bool checked: false - signal clicked() - - width: childrenRect.width - height: parent.height - - Rectangle { - anchors.top: parent.top - anchors.left: parent.left - height: parent.height - width: 2 - color: hifi.colors.faintGray - visible: index > 0 - } - - RalewayRegular { - id: buttonGlyph - text: root.ascending ? root.ascGlyph : root.descGlyph - // Size - size: 14 - // Anchors - anchors.left: parent.left - anchors.leftMargin: 10 - anchors.top: parent.top - anchors.topMargin: 6 - anchors.bottom: parent.bottom - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignTop - // Style - color: hifi.colors.lightGray - } - RalewayRegular { - id: buttonText - text: root.text - // Text size - size: 14 - // Style - color: hifi.colors.lightGray - elide: Text.ElideRight - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - // Anchors - anchors.left: buttonGlyph.right - anchors.leftMargin: 5 - anchors.top: parent.top - height: parent.height - } - MouseArea { - anchors.fill: parent - hoverEnabled: enabled - onClicked: { - root.clicked(); - } - } -} \ No newline at end of file diff --git a/interface/resources/qml/hifi/commerce/marketplace/licenses/Popv1.txt b/interface/resources/qml/hifi/commerce/marketplace/licenses/Popv1.txt deleted file mode 100644 index 1f44fc19e6d..00000000000 --- a/interface/resources/qml/hifi/commerce/marketplace/licenses/Popv1.txt +++ /dev/null @@ -1,12 +0,0 @@ - -

Proof of Provenance License (PoP License) v1.0

-
-

- Subject to the terms and conditions of this license, the Copyright Holder grants a worldwide, non-exclusive, non-sublicensable, non-transferable (except by transfer of the Certificate or beneficial ownership thereof) license (i) to the Certificate Holder to display ONE COPY of the Item at a time across any and all virtual worlds WITHOUT MODIFICATION; (ii) to any party to view and interact with the Item as displayed by the Certificate Holder. Redistributions of source code must retain the all copyright notices. Notwithstanding the foregoing, modification of the Item may be permitted pursuant to terms provided in the Certificate. -

-

- THE ITEM IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR A CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ITEM, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -

-

- Reference to the “Certificate” means the Proof of Provenance Certificate containing a hash of the code used to generate the Item; ‘Item’ means the visual representation produced by the execution of the code hashed in the Certificate (which term includes the code itself); and “Certificate Holder” means a single holder of the private key for the Certificate. -

diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml deleted file mode 100644 index 157f3dda6ab..00000000000 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml +++ /dev/null @@ -1,364 +0,0 @@ -// -// ItemUnderTest -// qml/hifi/commerce/marketplaceItemTester -// -// Load items not in the marketplace for testing purposes -// -// Created by Kerry Ivan Kurian on 2018-10-18 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.10 -import QtQuick.Controls 2.3 -import Hifi 1.0 as Hifi -import stylesUit 1.0 as HifiStylesUit -import controlsUit 1.0 as HifiControlsUit - -Rectangle { - id: root; - color: hifi.colors.baseGray - width: parent.width - 16 - height: childrenRect.height + itemHeaderContainer.anchors.topMargin + detailsContainer.anchors.topMargin - - property var detailsExpanded: false - - property var actions: { - "forward": function(resource, assetType, resourceObjectId){ - switch(assetType) { - case "application": - Commerce.installApp(resource, true); - break; - case "avatar": - MyAvatar.useFullAvatarURL(resource); - break; - case "content set": - urlHandler.handleUrl("hifi://localhost/0,0,0"); - Commerce.replaceContentSet(toUrl(resource), "", ""); - break; - case "entity": - case "wearable": - rezEntity(resource, assetType, resourceObjectId); - break; - default: - print("Marketplace item tester unsupported assetType " + assetType); - } - }, - "trash": function(resource, assetType){ - if ("application" === assetType) { - Commerce.uninstallApp(resource); - } - sendToScript({ - method: "tester_deleteResourceObject", - objectId: resourceListModel.get(index).resourceObjectId}); - resourceListModel.remove(index); - } - } - - Item { - id: itemHeaderContainer - anchors.top: parent.top - anchors.topMargin: 8 - anchors.left: parent.left - anchors.leftMargin: 8 - width: parent.width - 16 - height: childrenRect.height - - Item { - id: itemNameContainer - width: parent.width * 0.5 - height: childrenRect.height - - HifiStylesUit.RalewaySemiBold { - id: resourceName - height: paintedHeight - width: parent.width - text: { - var match = resource.match(/\/([^/]*)$/); - return match ? match[1] : resource; - } - size: 14 - color: hifi.colors.white - wrapMode: Text.WrapAnywhere - } - - HifiStylesUit.RalewayRegular { - id: resourceUrl - anchors.top: resourceName.bottom; - anchors.topMargin: 4; - height: paintedHeight - width: parent.width - text: resource - size: 12 - color: hifi.colors.faintGray; - wrapMode: Text.WrapAnywhere - } - } - - HifiControlsUit.ComboBox { - id: comboBox - anchors.left: itemNameContainer.right - anchors.leftMargin: 4 - anchors.verticalCenter: itemNameContainer.verticalCenter - height: 30 - width: parent.width * 0.3 - anchors.leftMargin - - model: [ - "application", - "avatar", - "content set", - "entity", - "wearable", - "unknown" - ] - - currentIndex: (("entity or wearable" === assetType) ? - model.indexOf("unknown") : model.indexOf(assetType)) - - Component.onCompleted: { - onCurrentIndexChanged.connect(function() { - assetType = model[currentIndex]; - sendToScript({ - method: "tester_updateResourceObjectAssetType", - objectId: resourceListModel.get(index)["resourceObjectId"], - assetType: assetType }); - }); - } - } - - Button { - id: actionButton - property var glyphs: { - "application": hifi.glyphs.install, - "avatar": hifi.glyphs.avatar, - "content set": hifi.glyphs.globe, - "entity": hifi.glyphs.wand, - "trash": hifi.glyphs.trash, - "unknown": hifi.glyphs.circleSlash, - "wearable": hifi.glyphs.hat - } - property int color: hifi.buttons.blue; - property int colorScheme: hifi.colorSchemes.dark; - anchors.left: comboBox.right - anchors.leftMargin: 4 - anchors.verticalCenter: itemNameContainer.verticalCenter - width: parent.width * 0.10 - anchors.leftMargin - height: width - enabled: comboBox.model[comboBox.currentIndex] !== "unknown" - - onClicked: { - if (model.currentlyRecordingResources) { - model.currentlyRecordingResources = false; - } else { - model.resourceAccessEventText = ""; - model.currentlyRecordingResources = true; - root.actions["forward"](resource, comboBox.currentText, resourceObjectId); - } - sendToScript({ - method: "tester_updateResourceRecordingStatus", - objectId: resourceListModel.get(index).resourceObjectId, - status: model.currentlyRecordingResources - }); - } - - background: Rectangle { - radius: 4; - gradient: Gradient { - GradientStop { - position: 0.2 - color: { - if (!actionButton.enabled) { - hifi.buttons.disabledColorStart[actionButton.colorScheme] - } else if (actionButton.pressed) { - hifi.buttons.pressedColor[actionButton.color] - } else if (actionButton.hovered) { - hifi.buttons.hoveredColor[actionButton.color] - } else { - hifi.buttons.colorStart[actionButton.color] - } - } - } - GradientStop { - position: 1.0 - color: { - if (!actionButton.enabled) { - hifi.buttons.disabledColorFinish[actionButton.colorScheme] - } else if (actionButton.pressed) { - hifi.buttons.pressedColor[actionButton.color] - } else if (actionButton.hovered) { - hifi.buttons.hoveredColor[actionButton.color] - } else { - hifi.buttons.colorFinish[actionButton.color] - } - } - } - } - } - - contentItem: Item { - HifiStylesUit.HiFiGlyphs { - id: rezIcon; - text: model.currentlyRecordingResources ? hifi.glyphs.scriptStop : actionButton.glyphs[comboBox.model[comboBox.currentIndex]]; - anchors.fill: parent - size: 30; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - color: enabled ? hifi.buttons.textColor[actionButton.color] - : hifi.buttons.disabledTextColor[actionButton.colorScheme] - } - } - } - - Button { - id: trashButton - property int color: hifi.buttons.red; - property int colorScheme: hifi.colorSchemes.dark; - anchors.left: actionButton.right - anchors.verticalCenter: itemNameContainer.verticalCenter - anchors.leftMargin: 4 - width: parent.width * 0.10 - anchors.leftMargin - height: width - - onClicked: { - root.actions["trash"](resource, comboBox.currentText, resourceObjectId); - } - - background: Rectangle { - radius: 4; - gradient: Gradient { - GradientStop { - position: 0.2 - color: { - if (!trashButton.enabled) { - hifi.buttons.disabledColorStart[trashButton.colorScheme] - } else if (trashButton.pressed) { - hifi.buttons.pressedColor[trashButton.color] - } else if (trashButton.hovered) { - hifi.buttons.hoveredColor[trashButton.color] - } else { - hifi.buttons.colorStart[trashButton.color] - } - } - } - GradientStop { - position: 1.0 - color: { - if (!trashButton.enabled) { - hifi.buttons.disabledColorFinish[trashButton.colorScheme] - } else if (trashButton.pressed) { - hifi.buttons.pressedColor[trashButton.color] - } else if (trashButton.hovered) { - hifi.buttons.hoveredColor[trashButton.color] - } else { - hifi.buttons.colorFinish[trashButton.color] - } - } - } - } - } - - contentItem: Item { - HifiStylesUit.HiFiGlyphs { - id: trashIcon; - text: hifi.glyphs.trash - anchors.fill: parent - size: 22; - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - color: enabled ? hifi.buttons.textColor[trashButton.color] - : hifi.buttons.disabledTextColor[trashButton.colorScheme] - } - } - } - } - - Item { - id: detailsContainer - - width: parent.width - 16 - height: root.detailsExpanded ? 300 : 26 - anchors.top: itemHeaderContainer.bottom - anchors.topMargin: 12 - anchors.left: parent.left - anchors.leftMargin: 8 - - HifiStylesUit.HiFiGlyphs { - id: detailsToggle - anchors.left: parent.left - anchors.leftMargin: -4 - anchors.top: parent.top - anchors.topMargin: -2 - width: 22 - text: root.detailsExpanded ? hifi.glyphs.minimize : hifi.glyphs.maximize - color: hifi.colors.white - size: 22 - MouseArea { - anchors.fill: parent - onClicked: root.detailsExpanded = !root.detailsExpanded - } - } - - ScrollView { - id: detailsTextContainer - anchors.top: parent.top - anchors.left: detailsToggle.right - anchors.leftMargin: 4 - anchors.right: parent.right - height: detailsContainer.height - (root.detailsExpanded ? (copyToClipboardButton.height + copyToClipboardButton.anchors.topMargin) : 0) - clip: true - - TextArea { - id: detailsText - readOnly: true - color: hifi.colors.white - text: { - var numUniqueResources = (model.resourceAccessEventText.split("\n").length - 1); - if (root.detailsExpanded && numUniqueResources > 0) { - return model.resourceAccessEventText - } else { - return numUniqueResources.toString() + " unique source/resource url pair" + (numUniqueResources === 1 ? "" : "s") + " recorded" - } - } - font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal }) - wrapMode: TextEdit.NoWrap - - background: Rectangle { - anchors.fill: parent; - color: hifi.colors.baseGrayShadow; - border.width: 0; - } - } - - MouseArea { - anchors.fill: parent - onClicked: { - if (root.detailsExpanded) { - detailsText.selectAll(); - } else { - root.detailsExpanded = true; - } - } - } - } - - HifiControlsUit.Button { - id: copyToClipboardButton; - visible: root.detailsExpanded - color: hifi.buttons.noneBorderlessWhite - colorScheme: hifi.colorSchemes.dark - - anchors.top: detailsTextContainer.bottom - anchors.topMargin: 8 - anchors.right: parent.right - width: 160 - height: 30 - text: "Copy to Clipboard" - - onClicked: { - Window.copyToClipboard(detailsText.text); - } - } - } -} diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml deleted file mode 100644 index a37a0ac756e..00000000000 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ /dev/null @@ -1,278 +0,0 @@ -// -// marketplaceItemTester -// qml/hifi/commerce/marketplaceItemTester -// -// Load items not in the marketplace for testing purposes -// -// Created by Kerry Ivan Kurian on 2018-09-05 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.10 -import QtQuick.Layouts 1.1 -import QtQuick.Controls 2.3 -import Hifi 1.0 as Hifi -import stylesUit 1.0 as HifiStylesUit -import controlsUit 1.0 as HifiControlsUit - - - - -Rectangle { - id: root - - property string installedApps - property var nextResourceObjectId: 0 - - HifiStylesUit.HifiConstants { id: hifi } - ListModel { id: resourceListModel } - - color: hifi.colors.darkGray - - // - // TITLE BAR START - // - Item { - id: titleBarContainer - // Size - width: root.width - height: 50 - // Anchors - anchors.left: parent.left - anchors.top: parent.top - - // Title bar text - HifiStylesUit.RalewaySemiBold { - id: titleBarText - text: "Marketplace Item Tester" - // Text size - size: 24 - // Anchors - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.leftMargin: 16 - width: paintedWidth - // Style - color: hifi.colors.lightGrayText - // Alignment - horizontalAlignment: Text.AlignHLeft - verticalAlignment: Text.AlignVCenter - } - - // Separator - HifiControlsUit.Separator { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.bottomMargin: 1 - } - } - // - // TITLE BAR END - // - - Rectangle { - id: spinner - z: 999 - anchors.top: titleBarContainer.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: buttonContainer.top - color: hifi.colors.darkGray - - AnimatedImage { - source: "spinner.gif" - width: 74 - height: width - anchors.centerIn: parent - } - } - - Rectangle { - id: instructionsContainer - z: 998 - color: hifi.colors.darkGray - visible: resourceListModel.count === 0 && !spinner.visible - anchors.top: titleBarContainer.bottom - anchors.topMargin: 20 - anchors.left: parent.left - anchors.leftMargin: 20 - anchors.right: parent.right - anchors.rightMargin: 20 - anchors.bottom: buttonContainer.top - anchors.bottomMargin: 20 - - HifiStylesUit.RalewayRegular { - text: "Use Marketplace Item Tester to test out your items before submitting them to the Marketplace." + - "\n\nUse one of the buttons below to load your item." - // Text size - size: 20 - // Anchors - anchors.fill: parent - // Style - color: hifi.colors.lightGrayText - wrapMode: Text.Wrap - // Alignment - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - } - - ListView { - id: itemList - visible: !instructionsContainer.visible - anchors.top: titleBarContainer.bottom - anchors.topMargin: 20 - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: buttonContainer.top - anchors.bottomMargin: 20 - ScrollBar.vertical: ScrollBar { - visible: !instructionsContainer.visible - policy: ScrollBar.AlwaysOn - parent: itemList.parent - anchors.top: itemList.top - anchors.right: itemList.right - anchors.bottom: itemList.bottom - width: 16 - } - clip: true - model: resourceListModel - spacing: 8 - - delegate: ItemUnderTest { } - } - - Item { - id: buttonContainer - - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - height: 40 - - property string currentAction - property var actions: { - "Load File": function() { - buttonContainer.currentAction = "load file"; - Window.browseChanged.connect(onResourceSelected); - Window.browseAsync("Please select a file (*.app.json *.json *.fst *.json.gz)", "", "Assets (*.app.json *.json *.fst *.json.gz)"); - }, - "Load URL": function() { - buttonContainer.currentAction = "load url"; - Window.promptTextChanged.connect(onResourceSelected); - Window.promptAsync("Please enter a URL", ""); - } - } - - function onResourceSelected(resource) { - // It is possible that we received the present signal - // from something other than our browserAsync window. - // Alas, there is nothing we can do about that so charge - // ahead as though we are sure the present signal is one - // we expect. - print("!!!! resource selected"); - switch(currentAction) { - case "load file": - Window.browseChanged.disconnect(onResourceSelected); - break - case "load url": - Window.promptTextChanged.disconnect(onResourceSelected); - break; - } - if (resource) { - print("!!!! building resource object"); - var resourceObj = buildResourceObj(resource); - print("!!!! notifying script of resource object"); - sendToScript({ - method: 'tester_newResourceObject', - resourceObject: resourceObj - }); - } - } - - HifiControlsUit.Button { - enabled: !spinner.visible - anchors.right: parent.horizontalCenter - anchors.rightMargin: width/4 - anchors.verticalCenter: parent.verticalCenter - color: hifi.buttons.blue - fontSize: 20 - text: "Load File" - width: parent.width / 3 - height: parent.height - onClicked: buttonContainer.actions[text]() - } - - HifiControlsUit.Button { - enabled: !spinner.visible - anchors.left: parent.horizontalCenter - anchors.leftMargin: width/4 - anchors.verticalCenter: parent.verticalCenter - color: hifi.buttons.blue - fontSize: 20 - text: "Load URL" - width: parent.width / 3 - height: parent.height - onClicked: buttonContainer.actions[text]() - } - } - - function fromScript(message) { - switch (message.method) { - case "newResourceObjectInTest": - var resourceObject = message.resourceObject; - resourceListModel.clear(); // REMOVE THIS once we support specific referrers - resourceListModel.append(resourceObject); - spinner.visible = false; - break; - case "nextObjectIdInTest": - print("!!!! message from script! " + JSON.stringify(message)); - nextResourceObjectId = message.id; - spinner.visible = false; - break; - case "resourceRequestEvent": - // When we support multiple items under test simultaneously, - // we'll have to replace "0" with the correct index. - resourceListModel.setProperty(0, "resourceAccessEventText", message.resourceAccessEventText); - break; - } - } - - function buildResourceObj(resource) { - resource = resource.trim(); - var assetType = (resource.match(/\.app\.json$/) ? "application" : - resource.match(/\.fst$/) ? "avatar" : - resource.match(/\.json\.gz$/) ? "content set" : - resource.match(/\.json$/) ? "entity or wearable" : - "unknown"); - // Uncomment this once we support more than one item in test at the same time - //nextResourceObjectId++; - return { "resourceObjectId": nextResourceObjectId, - "resource": resource, - "assetType": assetType }; - } - - function toUrl(resource) { - var httpPattern = /^http/i; - return httpPattern.test(resource) ? resource : "file:///" + resource; - } - - function rezEntity(resource, entityType, resourceObjectId) { - print("!!!! tester_rezClicked"); - sendToScript({ - method: 'tester_rezClicked', - itemHref: toUrl(resource), - itemType: entityType, - itemId: resourceObjectId }); - } - - signal sendToScript(var message) -} diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/spinner.gif b/interface/resources/qml/hifi/commerce/marketplaceItemTester/spinner.gif deleted file mode 100644 index 0536bd1884f..00000000000 Binary files a/interface/resources/qml/hifi/commerce/marketplaceItemTester/spinner.gif and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml deleted file mode 100644 index 1dbcd34cce4..00000000000 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ /dev/null @@ -1,883 +0,0 @@ -// -// PurchasedItem.qml -// qml/hifi/commerce/purchases -// -// PurchasedItem -// -// Created by Zach Fox on 2017-08-25 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../wallet" as HifiWallet -import TabletScriptingInterface 1.0 - -Item { - HifiConstants { id: hifi; } - - id: root; - property string purchaseStatus; - property string itemName; - property string itemId; - property string updateItemId; - property string itemPreviewImageUrl; - property string itemHref; - property string certificateId; - property int displayedItemCount; - property int itemEdition; - property int numberSold; - property int limitedRun; - property string itemType; - property var itemTypesArray: ["entity", "wearable", "contentSet", "app", "avatar"]; - property var buttonTextNormal: ["REZ", "WEAR", "REPLACE", "INSTALL", "WEAR"]; - property var buttonTextClicked: ["REZZED", "WORN", "REPLACED", "INSTALLED", "WORN"] - property var buttonGlyph: [hifi.glyphs.wand, hifi.glyphs.hat, hifi.glyphs.globe, hifi.glyphs.install, hifi.glyphs.avatar]; - property bool showConfirmation: false; - property bool hasPermissionToRezThis; - property bool cardBackVisible; - property bool isInstalled; - property string wornEntityID; - property string updatedItemId; - property string upgradeTitle; - property bool updateAvailable: root.updateItemId !== ""; - property bool valid; - property bool standaloneOptimized; - property bool standaloneIncompatible; - - property string originalStatusText; - property string originalStatusColor; - - height: 102; - width: parent.width; - - Connections { - target: Commerce; - - onContentSetChanged: { - if (contentSetHref === root.itemHref) { - showConfirmation = true; - } - } - - onAppInstalled: { - if (appID === root.itemId) { - root.isInstalled = true; - } - } - - onAppUninstalled: { - if (appID === root.itemId) { - root.isInstalled = false; - } - } - } - - Connections { - target: MyAvatar; - - onSkeletonModelURLChanged: { - if (skeletonModelURL === root.itemHref) { - showConfirmation = true; - } - } - } - - onItemTypeChanged: { - if ((itemType === "entity" && (!Entities.canRezCertified() && !Entities.canRezTmpCertified())) || - (itemType === "contentSet" && !Entities.canReplaceContent())) { - root.hasPermissionToRezThis = false; - } else { - root.hasPermissionToRezThis = true; - } - } - - onShowConfirmationChanged: { - if (root.showConfirmation) { - rezzedNotifContainer.visible = true; - rezzedNotifContainerTimer.start(); - UserActivityLogger.commerceEntityRezzed(root.itemId, "purchases", root.itemType); - root.showConfirmation = false; - } - } - - Rectangle { - id: background; - z: 10; - color: Qt.rgba(0, 0, 0, 0.25); - anchors.fill: parent; - } - - Flipable { - id: flipable; - z: 50; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: parent.top; - height: root.height - 2; - - front: mainContainer; - back: Rectangle { - anchors.fill: parent; - color: hifi.colors.white; - - Item { - id: closeContextMenuContainer; - anchors.right: parent.right; - anchors.rightMargin: 8; - anchors.top: parent.top; - anchors.topMargin: 8; - width: 30; - height: width; - - HiFiGlyphs { - id: closeContextMenuGlyph; - text: hifi.glyphs.close; - anchors.fill: parent; - size: 26; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - color: hifi.colors.black; - } - - MouseArea { - anchors.fill: parent; - hoverEnabled: enabled; - onClicked: { - root.sendToPurchases({ method: 'flipCard', closeAll: true }); - } - onEntered: { - closeContextMenuGlyph.text = hifi.glyphs.closeInverted; - } - onExited: { - closeContextMenuGlyph.text = hifi.glyphs.close; - } - } - } - - Rectangle { - id: contextCard; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.right: closeContextMenuContainer.left; - anchors.rightMargin: 8; - color: hifi.colors.white; - - Component { - id: contextCardButton; - - Item { - property alias buttonGlyphText: buttonGlyph.text; - property alias itemButtonText: buttonText.text; - property alias glyphSize: buttonGlyph.size; - property string buttonColor: hifi.colors.black; - property string buttonColor_hover: hifi.colors.blueHighlight; - property alias enabled: buttonMouseArea.enabled; - property var buttonClicked; - - HiFiGlyphs { - id: buttonGlyph; - anchors.top: parent.top; - anchors.topMargin: 4; - anchors.horizontalCenter: parent.horizontalCenter; - anchors.bottom: buttonText.visible ? parent.verticalCenter : parent.bottom; - anchors.bottomMargin: buttonText.visible ? 0 : 4; - width: parent.width; - size: 40; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - color: buttonMouseArea.enabled ? buttonColor : hifi.colors.lightGrayText; - } - - RalewayRegular { - id: buttonText; - visible: text !== ""; - anchors.top: parent.verticalCenter; - anchors.topMargin: 4; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 12; - anchors.horizontalCenter: parent.horizontalCenter; - width: parent.width; - color: buttonMouseArea.enabled ? buttonColor : hifi.colors.lightGrayText; - size: 16; - wrapMode: Text.Wrap; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - MouseArea { - id: buttonMouseArea; - anchors.fill: parent; - hoverEnabled: enabled; - onClicked: { - parent.buttonClicked(); - } - onEntered: { - buttonGlyph.color = buttonColor_hover; - buttonText.color = buttonColor_hover; - } - onExited: { - buttonGlyph.color = buttonColor; - buttonText.color = buttonColor; - } - } - } - } - - Loader { - id: giftButton; - visible: root.itemEdition > 0; - sourceComponent: contextCardButton; - anchors.right: parent.right; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - width: 62; - - onLoaded: { - item.enabled = root.valid; - item.buttonGlyphText = hifi.glyphs.gift; - item.itemButtonText = "Gift"; - item.buttonClicked = function() { - sendToPurchases({ method: 'flipCard', closeAll: true }); - sendToPurchases({ - method: 'giftAsset', - itemName: root.itemName, - certId: root.certificateId, - itemType: root.itemType, - itemHref: root.itemHref, - isInstalled: root.isInstalled, - wornEntityID: root.wornEntityID, - effectImage: root.itemPreviewImageUrl - }); - } - } - } - - Loader { - id: marketplaceButton; - sourceComponent: contextCardButton; - anchors.right: giftButton.visible ? giftButton.left : parent.right; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - width: 100; - - onLoaded: { - item.buttonGlyphText = hifi.glyphs.market; - item.itemButtonText = "View in Marketplace"; - item.buttonClicked = function() { - sendToPurchases({ method: 'flipCard', closeAll: true }); - sendToPurchases({method: 'purchases_itemInfoClicked', itemId: root.itemId}); - } - } - } - - Loader { - id: certificateButton; - sourceComponent: contextCardButton; - anchors.right: marketplaceButton.left; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - width: 100; - - onLoaded: { - item.buttonGlyphText = hifi.glyphs.certificate; - item.itemButtonText = "View Certificate"; - item.buttonClicked = function() { - sendToPurchases({ method: 'flipCard', closeAll: true }); - sendToPurchases({method: 'purchases_itemCertificateClicked', itemCertificateId: root.certificateId}); - } - } - } - - Loader { - id: uninstallButton; - visible: root.isInstalled; - sourceComponent: contextCardButton; - anchors.right: certificateButton.left; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - width: 72; - - onLoaded: { - item.buttonGlyphText = hifi.glyphs.uninstall; - item.itemButtonText = "Uninstall"; - item.buttonClicked = function() { - sendToPurchases({ method: 'flipCard', closeAll: true }); - Commerce.uninstallApp(root.itemHref); - } - } - - onVisibleChanged: { - trashButton.updateProperties(); - } - } - - Loader { - id: updateButton; - visible: root.updateAvailable; - sourceComponent: contextCardButton; - anchors.right: uninstallButton.visible ? uninstallButton.left : certificateButton.left; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - width: 78; - - onLoaded: { - item.buttonGlyphText = hifi.glyphs.update; - item.itemButtonText = "Update"; - item.buttonColor = "#E2334D"; - item.buttonClicked = function() { - sendToPurchases({ method: 'flipCard', closeAll: true }); - sendToPurchases({ - method: 'updateItemClicked', - itemId: root.updateAvailable ? root.updateItemId : root.itemId, - itemEdition: root.itemEdition, - itemHref: root.itemHref, - itemType: root.itemType, - isInstalled: root.isInstalled, - wornEntityID: root.wornEntityID - }); - } - } - - onVisibleChanged: { - trashButton.updateProperties(); - } - } - - Loader { - id: trashButton; - visible: root.itemEdition > 0; - sourceComponent: contextCardButton; - anchors.right: updateButton.visible ? updateButton.left : (uninstallButton.visible ? uninstallButton.left : certificateButton.left); - anchors.top: parent.top; - anchors.bottom: parent.bottom; - width: (updateButton.visible && uninstallButton.visible) ? 15 : 78; - - onLoaded: { - item.buttonGlyphText = hifi.glyphs.trash; - updateProperties(); - item.buttonClicked = function() { - sendToPurchases({method: 'showTrashLightbox', - isInstalled: root.isInstalled, - itemHref: root.itemHref, - itemName: root.itemName, - certID: root.certificateId, - itemType: root.itemType, - wornEntityID: root.wornEntityID - }); - } - } - - function updateProperties() { - if (updateButton.visible && uninstallButton.visible) { - item.itemButtonText = ""; - item.glyphSize = 20; - } else if (item) { - item.itemButtonText = "Send to Trash"; - item.glyphSize = 30; - } - } - } - } - - Rectangle { - id: permissionExplanationCard; - visible: false; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.right: closeContextMenuContainer.left; - anchors.rightMargin: 8; - color: hifi.colors.white; - - RalewayRegular { - id: permissionExplanationText; - anchors.fill: parent; - text: { - if (root.standaloneIncompatible) { - "This item is incompatible with stand-alone devices. Learn more"; - } else if (root.itemType === "contentSet") { - "You do not have 'Replace Content' permissions in this domain. Learn more"; - } else if (root.itemType === "entity") { - "You do not have 'Rez Certified' permissions in this domain. Learn more"; - } else { - "Hey! You're not supposed to see this. How is it even possible that you're here? Are you a developer???" - } - } - size: 16; - color: hifi.colors.baseGray; - wrapMode: Text.Wrap; - verticalAlignment: Text.AlignVCenter; - - onLinkActivated: { - if (link === "#standaloneIncompatible") { - sendToPurchases({method: 'showStandaloneIncompatibleExplanation'}); - } else { - sendToPurchases({method: 'showPermissionsExplanation', itemType: root.itemType}); - } - } - } - } - } - - transform: Rotation { - id: rotation; - origin.x: flipable.width/2; - origin.y: flipable.height/2; - axis.x: 1; - axis.y: 0; - axis.z: 0; - angle: 0; - } - - states: State { - name: "back"; - PropertyChanges { - target: rotation; - angle: 180; - } - when: root.cardBackVisible; - } - - transitions: Transition { - SmoothedAnimation { - target: rotation; - property: "angle"; - velocity: 600; - } - } - } - - Rectangle { - id: mainContainer; - z: 51; - // Style - color: hifi.colors.white; - // Size - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: parent.top; - height: root.height - 2; - - Image { - id: itemPreviewImage; - source: root.itemPreviewImageUrl; - anchors.left: parent.left; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - width: height * 1.78; - fillMode: Image.PreserveAspectCrop; - mipmap: true; - - MouseArea { - anchors.fill: parent; - onClicked: { - sendToPurchases({method: 'purchases_itemInfoClicked', itemId: root.itemId}); - } - } - } - - RalewayRegular { - id: itemName; - anchors.top: parent.top; - anchors.topMargin: 4; - anchors.left: itemPreviewImage.right; - anchors.leftMargin: 10; - anchors.right: contextMenuButtonContainer.left; - anchors.rightMargin: 4; - height: paintedHeight; - // Text size - size: 20; - // Style - color: hifi.colors.black; - text: root.itemName; - elide: Text.ElideRight; - // Alignment - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignVCenter; - } - - RalewayRegular { - id: editionNumberText; - visible: root.displayedItemCount > 1 && !statusContainer.visible; - anchors.left: itemName.left; - anchors.right: itemName.right; - anchors.top: itemName.bottom; - anchors.topMargin: 4; - anchors.bottom: buttonContainer.top; - anchors.bottomMargin: 4; - width: itemName.width; - text: "Edition #" + root.itemEdition; - size: 13; - color: hifi.colors.black; - verticalAlignment: Text.AlignVCenter; - } - - Item { - id: statusContainer; - visible: root.purchaseStatus === "pending" || !root.valid || root.numberSold > -1; - anchors.left: itemName.left; - anchors.right: itemName.right; - anchors.top: itemName.bottom; - anchors.topMargin: 4; - anchors.bottom: buttonContainer.top; - anchors.bottomMargin: 4; - - RalewayRegular { - id: statusText; - anchors.left: parent.left; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - width: paintedWidth; - text: { - if (root.purchaseStatus === "pending") { - "PENDING..." - } else if (!root.valid) { - "INVALIDATED" - } else if (root.numberSold > -1) { - ("Sales: " + root.numberSold + "/" + (root.limitedRun === -1 ? "\u221e" : root.limitedRun)) - } else { - "" - } - } - size: 13; - color: { - if (root.purchaseStatus === "pending") { - hifi.colors.blueAccent - } else if (!root.valid) { - hifi.colors.redAccent - } else { - hifi.colors.baseGray - } - } - verticalAlignment: Text.AlignTop; - } - - HiFiGlyphs { - id: statusIcon; - text: { - if (root.purchaseStatus === "pending") { - hifi.glyphs.question - } else if (!root.valid) { - hifi.glyphs.question - } else { - "" - } - } - // Size - size: 34; - // Anchors - anchors.top: parent.top; - anchors.topMargin: -10; - anchors.left: statusText.right; - anchors.bottom: parent.bottom; - // Style - color: { - if (root.purchaseStatus === "pending") { - hifi.colors.blueAccent - } else if (!root.valid) { - hifi.colors.redAccent - } else { - hifi.colors.baseGray - } - } - verticalAlignment: Text.AlignTop; - } - - MouseArea { - anchors.fill: parent; - hoverEnabled: enabled; - onClicked: { - if (root.purchaseStatus === "pending") { - sendToPurchases({method: 'showPendingLightbox'}); - } else if (!root.valid) { - sendToPurchases({method: 'showInvalidatedLightbox'}); - } - } - onEntered: { - if (root.purchaseStatus === "pending") { - statusText.color = hifi.colors.blueHighlight; - statusIcon.color = hifi.colors.blueHighlight; - } else if (!root.valid) { - statusText.color = hifi.colors.redAccent; - statusIcon.color = hifi.colors.redAccent; - } - } - onExited: { - if (root.purchaseStatus === "pending") { - statusText.color = hifi.colors.blueAccent; - statusIcon.color = hifi.colors.blueAccent; - } else if (!root.valid) { - statusText.color = hifi.colors.redHighlight; - statusIcon.color = hifi.colors.redHighlight; - } - } - } - } - - Item { - id: contextMenuButtonContainer; - anchors.right: parent.right; - anchors.rightMargin: 8; - anchors.top: parent.top; - anchors.topMargin: 8; - width: 30; - height: width; - - Rectangle { - visible: root.updateAvailable; - anchors.fill: parent; - radius: height; - border.width: 1; - border.color: "#E2334D"; - } - - HiFiGlyphs { - id: contextMenuGlyph; - text: hifi.glyphs.verticalEllipsis; - anchors.fill: parent; - size: 46; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - color: root.updateAvailable ? "#E2334D" : hifi.colors.black; - } - - MouseArea { - anchors.fill: parent; - hoverEnabled: enabled; - onClicked: { - contextCard.visible = true; - permissionExplanationCard.visible = false; - root.sendToPurchases({ method: 'flipCard' }); - } - onEntered: { - contextMenuGlyph.color = root.updateAvailable ? hifi.colors.redHighlight : hifi.colors.blueHighlight; - } - onExited: { - contextMenuGlyph.color = root.updateAvailable ? "#E2334D" : hifi.colors.black; - } - } - } - - Rectangle { - id: rezzedNotifContainer; - z: 998; - visible: false; - color: "#1FC6A6"; - anchors.fill: buttonContainer; - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - RalewayBold { - anchors.fill: parent; - text: (root.buttonTextClicked)[itemTypesArray.indexOf(root.itemType)]; - size: 15; - color: hifi.colors.white; - verticalAlignment: Text.AlignVCenter; - horizontalAlignment: Text.AlignHCenter; - } - - Timer { - id: rezzedNotifContainerTimer; - interval: 2000; - onTriggered: rezzedNotifContainer.visible = false - } - } - Button { - id: buttonContainer; - property int color: hifi.buttons.blue; - property int colorScheme: hifi.colorSchemes.light; - - anchors.left: itemName.left; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 8; - width: 160; - height: 40; - enabled: !root.standaloneIncompatible && - root.hasPermissionToRezThis && - MyAvatar.skeletonModelURL !== root.itemHref && - !root.wornEntityID && - root.valid; - - onHoveredChanged: { - if (hovered) { - Tablet.playSound(TabletEnums.ButtonHover); - } - } - - onFocusChanged: { - if (focus) { - Tablet.playSound(TabletEnums.ButtonHover); - } - } - - onClicked: { - Tablet.playSound(TabletEnums.ButtonClick); - if (root.itemType === "contentSet") { - sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref, certID: root.certificateId, itemName: root.itemName}); - } else if (root.itemType === "avatar") { - sendToPurchases({method: 'showChangeAvatarLightbox', itemName: root.itemName, itemHref: root.itemHref}); - } else if (root.itemType === "app") { - if (root.isInstalled) { - Commerce.openApp(root.itemHref); - } else { - // "Run" and "Uninstall" buttons are separate. - Commerce.installApp(root.itemHref); - } - } else { - sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, itemType: root.itemType}); - root.showConfirmation = true; - } - } - - style: ButtonStyle { - background: Rectangle { - radius: 4; - gradient: Gradient { - GradientStop { - position: 0.2 - color: { - if (!control.enabled) { - hifi.buttons.disabledColorStart[control.colorScheme] - } else if (control.pressed) { - hifi.buttons.pressedColor[control.color] - } else if (control.hovered) { - hifi.buttons.hoveredColor[control.color] - } else { - hifi.buttons.colorStart[control.color] - } - } - } - GradientStop { - position: 1.0 - color: { - if (!control.enabled) { - hifi.buttons.disabledColorFinish[control.colorScheme] - } else if (control.pressed) { - hifi.buttons.pressedColor[control.color] - } else if (control.hovered) { - hifi.buttons.hoveredColor[control.color] - } else { - hifi.buttons.colorFinish[control.color] - } - } - } - } - } - - label: Item { - TextMetrics { - id: rezIconTextMetrics; - font: rezIcon.font; - text: rezIcon.text; - } - HiFiGlyphs { - id: rezIcon; - text: root.isInstalled ? "" : (root.buttonGlyph)[itemTypesArray.indexOf(root.itemType)]; - anchors.right: rezIconLabel.left; - anchors.rightMargin: 2; - anchors.verticalCenter: parent.verticalCenter; - size: 36; - horizontalAlignment: Text.AlignHCenter; - color: enabled ? hifi.buttons.textColor[control.color] - : hifi.buttons.disabledTextColor[control.colorScheme] - } - TextMetrics { - id: rezIconLabelTextMetrics; - font: rezIconLabel.font; - text: rezIconLabel.text; - } - RalewayBold { - id: rezIconLabel; - text: root.isInstalled ? "OPEN" : (MyAvatar.skeletonModelURL === root.itemHref ? "CURRENT" : (root.buttonTextNormal)[itemTypesArray.indexOf(root.itemType)]); - anchors.verticalCenter: parent.verticalCenter; - width: rezIconLabelTextMetrics.width; - x: parent.width/2 - rezIconLabelTextMetrics.width/2 + rezIconTextMetrics.width/2; - size: 15; - font.capitalization: Font.AllUppercase; - verticalAlignment: Text.AlignVCenter; - horizontalAlignment: Text.AlignHCenter; - color: enabled ? hifi.buttons.textColor[control.color] - : hifi.buttons.disabledTextColor[control.colorScheme] - } - } - } - } - HiFiGlyphs { - id: noPermissionGlyph; - visible: !root.hasPermissionToRezThis; - anchors.verticalCenter: buttonContainer.verticalCenter; - anchors.left: buttonContainer.left; - anchors.right: buttonContainer.right; - anchors.rightMargin: -40; - text: hifi.glyphs.info; - // Size - size: 44; - // Style - color: hifi.colors.redAccent; - horizontalAlignment: Text.AlignRight; - - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - - onEntered: { - noPermissionGlyph.color = hifi.colors.redHighlight; - } - onExited: { - noPermissionGlyph.color = hifi.colors.redAccent; - } - onClicked: { - contextCard.visible = false; - permissionExplanationCard.visible = true; - root.sendToPurchases({ method: 'flipCard' }); - } - } - } - Image { - id: standaloneOptomizedBadge - - anchors { - right: parent.right - bottom: parent.bottom - rightMargin: 15 - bottomMargin:12 - } - height: root.standaloneOptimized ? 36 : 0 - width: 36 - - visible: root.standaloneOptimized - fillMode: Image.PreserveAspectFit - source: "../../../../icons/standalone-optimized.svg" - } - ColorOverlay { - anchors.fill: standaloneOptomizedBadge - source: standaloneOptomizedBadge - color: hifi.colors.blueHighlight - visible: root.standaloneOptimized - } - } - - // - // FUNCTION DEFINITIONS START - // - signal sendToPurchases(var msg); - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml deleted file mode 100644 index 8ccfceb03cf..00000000000 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ /dev/null @@ -1,1086 +0,0 @@ -// -// Purchases.qml -// qml/hifi/commerce/purchases -// -// Purchases -// -// Created by Zach Fox on 2017-08-25 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.9 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. -import "../wallet" as HifiWallet -import "../common" as HifiCommerceCommon -import "../common/sendAsset" as HifiSendAsset -import "../.." as HifiCommon - -// references XXX from root context - -Rectangle { - HifiConstants { id: hifi; } - - id: root; - property string activeView: "initialize"; - property bool securityImageResultReceived: false; - property bool purchasesReceived: false; - property bool punctuationMode: false; - property bool isDebuggingFirstUseTutorial: false; - property bool isStandalone: false; - property string installedApps; - property bool keyboardRaised: false; - property int numUpdatesAvailable: 0; - // Style - color: hifi.colors.white; - function getPurchases() { - root.activeView = "purchasesMain"; - root.installedApps = Commerce.getInstalledApps(); - purchasesModel.getFirstPage(); - Commerce.getAvailableUpdates(); - } - - Connections { - target: Commerce; - - onWalletStatusResult: { - if (walletStatus === 0) { - if (root.activeView !== "needsLogIn") { - root.activeView = "needsLogIn"; - } - } else if ((walletStatus === 1) || (walletStatus === 2) || (walletStatus === 3)) { - if (root.activeView !== "notSetUp") { - root.activeView = "notSetUp"; - notSetUpTimer.start(); - } - } else if (walletStatus === 4) { - if (root.activeView !== "passphraseModal") { - root.activeView = "passphraseModal"; - UserActivityLogger.commercePassphraseEntry("marketplace purchases"); - } - } else if (walletStatus === 5) { - if ((Settings.getValue("isFirstUseOfPurchases", true) || root.isDebuggingFirstUseTutorial) && root.activeView !== "firstUseTutorial") { - root.activeView = "firstUseTutorial"; - } else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") { - getPurchases(); - } - } else { - console.log("ERROR in Purchases.qml: Unknown wallet status: " + walletStatus); - } - } - - onLoginStatusResult: { - if (!isLoggedIn && root.activeView !== "needsLogIn") { - root.activeView = "needsLogIn"; - } else { - Commerce.getWalletStatus(); - } - } - - onInventoryResult: { - purchasesModel.handlePage(result.status !== "success" && result.message, result); - } - - onAvailableUpdatesResult: { - if (result.status !== 'success') { - console.log("Failed to get Available Updates", result.data.message); - } else { - root.numUpdatesAvailable = result.total_entries; - } - } - - onAppInstalled: { - root.installedApps = Commerce.getInstalledApps(appID); - } - - onAppUninstalled: { - root.installedApps = Commerce.getInstalledApps(); - } - } - - Timer { - id: notSetUpTimer; - interval: 200; - onTriggered: { - sendToScript({method: 'purchases_walletNotSetUp'}); - } - } - - Component.onCompleted: { - isStandalone = PlatformInfo.isStandalone(); - } - - HifiCommerceCommon.CommerceLightbox { - id: lightboxPopup; - z: 999; - visible: false; - anchors.fill: parent; - - Connections { - onSendToParent: { - if (msg.method === 'commerceLightboxLinkClicked') { - Qt.openUrlExternally(msg.linkUrl); - } else { - sendToScript(msg); - } - } - } - } - - HifiCommon.RootHttpRequest { - id: http; - } - - HifiSendAsset.SendAsset { - id: sendAsset; - http: http; - listModelName: "Gift Connections"; - z: 998; - visible: root.activeView === "giftAsset"; - keyboardContainer: root; - anchors.fill: parent; - parentAppTitleBarHeight: 70; - parentAppNavBarHeight: 0; - - Connections { - onSendSignalToParent: { - if (msg.method === 'sendAssetHome_back' || msg.method === 'closeSendAsset') { - getPurchases(); - } else { - sendToScript(msg); - } - } - } - } - - Rectangle { - id: initialize; - visible: root.activeView === "initialize"; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - color: hifi.colors.white; - - Component.onCompleted: { - securityImageResultReceived = false; - purchasesReceived = false; - Commerce.getWalletStatus(); - } - } - - Item { - id: installedAppsContainer; - z: 998; - visible: false; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: parent.width; - - RalewayRegular { - id: installedAppsHeader; - anchors.top: parent.top; - anchors.topMargin: 10; - anchors.left: parent.left; - anchors.leftMargin: 12; - height: 80; - width: paintedWidth; - text: "All Installed Marketplace Apps"; - color: hifi.colors.black; - size: 22; - } - - ListView { - id: installedAppsList; - clip: true; - model: installedAppsModel; - snapMode: ListView.SnapToItem; - // Anchors - anchors.top: installedAppsHeader.bottom; - anchors.left: parent.left; - anchors.bottom: sideloadAppButton.top; - width: parent.width; - delegate: Item { - width: parent.width; - height: 40; - - RalewayRegular { - text: model.appUrl; - // Text size - size: 16; - // Anchors - anchors.left: parent.left; - anchors.leftMargin: 12; - height: parent.height; - anchors.right: sideloadAppOpenButton.left; - anchors.rightMargin: 8; - elide: Text.ElideRight; - // Style - color: hifi.colors.black; - // Alignment - verticalAlignment: Text.AlignVCenter; - - MouseArea { - anchors.fill: parent; - onClicked: { - Window.copyToClipboard((model.appUrl).slice(0, -9)); - } - } - } - - HifiControlsUit.Button { - id: sideloadAppOpenButton; - text: "OPEN"; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.topMargin: 2; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 2; - anchors.right: uninstallGlyph.left; - anchors.rightMargin: 8; - width: 80; - onClicked: { - Commerce.openApp(model.appUrl); - } - } - - HiFiGlyphs { - id: uninstallGlyph; - text: hifi.glyphs.close; - color: hifi.colors.black; - size: 22; - anchors.top: parent.top; - anchors.right: parent.right; - anchors.rightMargin: 6; - width: 35; - height: parent.height; - horizontalAlignment: Text.AlignHCenter; - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - onEntered: { - parent.text = hifi.glyphs.closeInverted; - } - onExited: { - parent.text = hifi.glyphs.close; - } - onClicked: { - Commerce.uninstallApp(model.appUrl); - } - } - } - } - } - HifiControlsUit.Button { - id: sideloadAppButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 8; - anchors.left: parent.left; - anchors.leftMargin: 8; - anchors.right: closeAppListButton.left; - anchors.rightMargin: 8; - height: 40; - text: "SIDELOAD APP FROM LOCAL DISK"; - onClicked: { - Window.browseChanged.connect(onFileOpenChanged); - Window.browseAsync("Locate your app's .app.json file", "", "*.app.json"); - } - } - HifiControlsUit.Button { - id: closeAppListButton; - color: hifi.buttons.white; - colorScheme: hifi.colorSchemes.dark; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 8; - anchors.right: parent.right; - anchors.rightMargin: 8; - width: 100; - height: 40; - text: "BACK"; - onClicked: { - installedAppsContainer.visible = false; - } - } - } - - HifiWallet.NeedsLogIn { - id: needsLogIn; - visible: root.activeView === "needsLogIn"; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - - Connections { - onSendSignalToWallet: { - sendToScript(msg); - } - } - } - Connections { - target: GlobalServices - onMyUsernameChanged: { - Commerce.getLoginStatus(); - } - } - - HifiWallet.PassphraseModal { - id: passphraseModal; - visible: root.activeView === "passphraseModal"; - anchors.fill: parent; - titleBarText: "Purchases"; - titleBarIcon: hifi.glyphs.wallet; - - Connections { - onSendSignalToParent: { - if (msg.method === "authSuccess") { - root.activeView = "initialize"; - Commerce.getWalletStatus(); - } else { - sendToScript(msg); - } - } - } - } - - HifiCommerceCommon.FirstUseTutorial { - id: firstUseTutorial; - z: 999; - visible: root.activeView === "firstUseTutorial"; - anchors.fill: parent; - - Connections { - onSendSignalToParent: { - switch (message.method) { - case 'tutorial_skipClicked': - case 'tutorial_finished': - Settings.setValue("isFirstUseOfPurchases", false); - getPurchases(); - break; - } - } - } - } - - // - // PURCHASES CONTENTS START - // - Item { - id: purchasesContentsContainer; - visible: root.activeView === "purchasesMain" && !installedAppsList.visible; - // Anchors - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: parent.top; - anchors.topMargin: 8; - anchors.bottom: parent.bottom; - - // - // FILTER BAR START - // - Item { - z: 996; - id: filterBarContainer; - // Size - height: 40; - // Anchors - anchors.left: parent.left; - anchors.leftMargin: 8; - anchors.right: parent.right; - anchors.rightMargin: 8; - anchors.top: parent.top; - anchors.topMargin: 4; - - RalewayRegular { - id: myText; - anchors.top: parent.top; - anchors.topMargin: 10; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 10; - anchors.left: parent.left; - anchors.leftMargin: 16; - width: paintedWidth; - text: "Items"; - color: hifi.colors.black; - size: 22; - } - - HifiControlsUit.FilterBar { - id: filterBar; - property string previousText: ""; - property string previousPrimaryFilter: ""; - colorScheme: hifi.colorSchemes.faintGray; - anchors.top: parent.top; - anchors.right: parent.right; - anchors.rightMargin: 8; - anchors.left: myText.right; - anchors.leftMargin: 16; - textFieldHeight: 39; - height: textFieldHeight + dropdownHeight; - placeholderText: "filter items"; - - Component.onCompleted: { - var choices = [ - { - "displayName": "App", - "filterName": "app" - }, - { - "displayName": "Avatar", - "filterName": "avatar" - }, - { - "displayName": "Content Set", - "filterName": "content_set" - }, - { - "displayName": "Entity", - "filterName": "entity" - }, - { - "displayName": "Wearable", - "filterName": "wearable" - }, - { - "separator" : true, - "displayName": "Updatable", - "filterName": "updated" - }, - { - "displayName": "My Submissions", - "filterName": "proofs" - } - ] - filterBar.primaryFilterChoices.clear(); - filterBar.primaryFilterChoices.append(choices); - } - - onPrimaryFilter_displayNameChanged: { - purchasesModel.tagsFilter = filterBar.primaryFilter_filterName; - filterBar.previousPrimaryFilter = filterBar.primaryFilter_displayName; - } - - onTextChanged: { - purchasesModel.searchFilter = filterBar.text; - filterBar.previousText = filterBar.text; - - } - } - } - // - // FILTER BAR END - // - - HifiControlsUit.Separator { - z: 995; - id: separator; - colorScheme: 2; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: filterBarContainer.bottom; - anchors.topMargin: 16; - } - - HifiModels.PSFListModel { - id: purchasesModel; - itemsPerPage: 7; - listModelName: 'purchases'; - listView: purchasesContentsList; - getPage: function () { - console.debug('getPage', purchasesModel.listModelName, filterBar.primaryFilter_filterName, purchasesModel.currentPageToRetrieve, purchasesModel.itemsPerPage); - var editionFilter = ""; - var primaryFilter = ""; - - if (filterBar.primaryFilter_filterName === "proofs") { - editionFilter = "proofs"; - } else { - primaryFilter = filterBar.primaryFilter_filterName; - } - Commerce.inventory( - editionFilter, - primaryFilter, - filterBar.text, - purchasesModel.currentPageToRetrieve, - purchasesModel.itemsPerPage - ); - } - processPage: function(data) { - purchasesReceived = true; // HRS FIXME? - data.assets.forEach(function (item) { - if (item.status.length > 1) { console.warn("Unrecognized inventory status", item); } - item.status = item.status[0]; - item.categories = item.categories.join(';'); - item.cardBackVisible = false; - item.isInstalled = root.installedApps.indexOf(item.id) > -1; - item.wornEntityID = ''; - item.upgrade_id = item.upgrade_id ? item.upgrade_id : ""; - }); - sendToScript({ method: 'purchases_updateWearables' }); - return data.assets; - } - } - - ListView { - id: purchasesContentsList; - visible: purchasesModel.count !== 0; - interactive: !lightboxPopup.visible; - clip: true; - model: purchasesModel; - snapMode: ListView.NoSnap; - // Anchors - anchors.top: separator.bottom; - anchors.left: parent.left; - anchors.bottom: updatesAvailableBanner.visible ? updatesAvailableBanner.top : parent.bottom; - width: parent.width; - delegate: PurchasedItem { - itemName: title; - itemId: id; - updateItemId: model.upgrade_id - itemPreviewImageUrl: preview; - itemHref: download_url; - certificateId: certificate_id; - purchaseStatus: status; - itemEdition: model.edition_number; - numberSold: model.number_sold; - limitedRun: model.limited_run; - displayedItemCount: 999; // For now (and maybe longer), we're going to display all the edition numbers. - cardBackVisible: model.cardBackVisible || false; - isInstalled: model.isInstalled || false; - wornEntityID: model.wornEntityID; - upgradeTitle: model.upgrade_title; - itemType: model.item_type; - valid: model.valid; - standaloneOptimized: model.standalone_optimized - standaloneIncompatible: root.isStandalone && model.standalone_incompatible - anchors.topMargin: 10; - anchors.bottomMargin: 10; - - Connections { - onSendToPurchases: { - if (msg.method === 'purchases_itemInfoClicked') { - sendToScript({method: 'purchases_itemInfoClicked', itemId: itemId}); - } else if (msg.method === "purchases_rezClicked") { - sendToScript({method: 'purchases_rezClicked', itemHref: itemHref, itemType: itemType}); - - // Race condition - Wearable might not be rezzed by the time the "currently worn wearbles" model is created - if (itemType === "wearable") { - sendToScript({ method: 'purchases_updateWearables' }); - } - } else if (msg.method === 'purchases_itemCertificateClicked') { - sendToScript(msg); - } else if (msg.method === "showInvalidatedLightbox") { - lightboxPopup.titleText = "Item Invalidated"; - lightboxPopup.bodyText = 'This item has been invalidated and is no longer available.
' + - 'If you have questions, please contact marketplace@highfidelity.com.
' + - 'Thank you!'; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } else if (msg.method === "showPendingLightbox") { - lightboxPopup.titleText = "Item Pending"; - lightboxPopup.bodyText = 'Your item is marked "pending" while the transfer is being confirmed. ' + - "Usually, purchases take about 90 seconds to confirm."; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } else if (msg.method === "showReplaceContentLightbox") { - lightboxPopup.titleText = "Replace Content"; - lightboxPopup.bodyText = "Rezzing this content set will replace the existing environment and all of the items in this domain. " + - "If you want to save the state of the content in this domain, create a backup before proceeding.

" + - "For more information about backing up and restoring content, " + - "" + - "click here to open info on your desktop browser."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - Commerce.replaceContentSet(msg.itemHref, msg.certID, msg.itemName); - lightboxPopup.visible = false; - }; - lightboxPopup.visible = true; - } else if (msg.method === "showTrashLightbox") { - lightboxPopup.titleText = "Send \"" + msg.itemName + "\" to Trash"; - lightboxPopup.bodyText = "Sending this item to the Trash means you will no longer own this item " + - "and it will be inaccessible to you from Inventory.\n\nThis action cannot be undone."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - if (msg.isInstalled) { - Commerce.uninstallApp(msg.itemHref); - } - - if (MyAvatar.skeletonModelURL === msg.itemHref) { - MyAvatar.useFullAvatarURL(''); - } - - if (msg.itemType === "wearable" && msg.wornEntityID !== '') { - Entities.deleteEntity(msg.wornEntityID); - purchasesModel.setProperty(index, 'wornEntityID', ''); - } - - Commerce.transferAssetToUsername("trashbot", msg.certID, 1, "Sent " + msg.itemName + " to trash."); - - lightboxPopup.titleText = '"' + msg.itemName + '" Sent to Trash'; - lightboxPopup.button1text = "OK"; - lightboxPopup.button1method = function() { - root.purchasesReceived = false; - lightboxPopup.visible = false; - getPurchases(); - } - lightboxPopup.button2text = ""; - lightboxPopup.bodyText = ""; - }; - lightboxPopup.visible = true; - } else if (msg.method === "showChangeAvatarLightbox") { - lightboxPopup.titleText = "Change Avatar"; - lightboxPopup.bodyText = "This will change your current avatar to " + msg.itemName + " while retaining your wearables."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - MyAvatar.useFullAvatarURL(msg.itemHref); - lightboxPopup.visible = false; - }; - lightboxPopup.visible = true; - } else if (msg.method === "showPermissionsExplanation") { - if (msg.itemType === "entity") { - lightboxPopup.titleText = "Rez Certified Permission"; - lightboxPopup.bodyText = "You don't have permission to rez certified items in this domain.

" + - "Use the GOTO app to visit another domain or go to your own sandbox."; - lightboxPopup.button2text = "OPEN GOTO"; - lightboxPopup.button2method = function() { - sendToScript({method: 'purchases_openGoTo'}); - lightboxPopup.visible = false; - }; - } else if (msg.itemType === "contentSet") { - lightboxPopup.titleText = "Replace Content Permission"; - lightboxPopup.bodyText = "You do not have the permission 'Replace Content' in this domain's server settings. The domain owner " + - "must enable it for you before you can replace content sets in this domain."; - } - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } else if (msg.method === "showStandaloneIncompatibleExplanation") { - lightboxPopup.titleText = "Stand-alone Incompatible"; - lightboxPopup.bodyText = "The item is incompatible with stand-alone devices."; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } else if (msg.method === "setFilterText") { - filterBar.text = msg.filterText; - } else if (msg.method === "flipCard") { - for (var i = 0; i < purchasesModel.count; i++) { - if (i !== index || msg.closeAll) { - purchasesModel.setProperty(i, "cardBackVisible", false); - } else { - purchasesModel.setProperty(i, "cardBackVisible", true); - } - } - } else if (msg.method === "updateItemClicked") { - // These three cases are very similar to the conditionals below, under - // "if msg.method === "giftAsset". They differ in their popup's wording - // and the actions to take when continuing. - // I could see an argument for DRYing up this code, but I think the - // actions are different enough now and potentially moving forward such that I'm - // OK with "somewhat repeating myself". - if (msg.itemType === "app" && msg.isInstalled) { - lightboxPopup.titleText = "Uninstall App"; - lightboxPopup.bodyText = "The app that you are trying to update is installed.

" + - "If you proceed, the current version of the app will be uninstalled."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - Commerce.uninstallApp(msg.itemHref); - sendToScript(msg); - }; - lightboxPopup.visible = true; - } else if (msg.itemType === "wearable" && msg.wornEntityID !== '') { - lightboxPopup.titleText = "Remove Wearable"; - lightboxPopup.bodyText = "You are currently wearing the wearable that you are trying to update.

" + - "If you proceed, this wearable will be removed."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - Entities.deleteEntity(msg.wornEntityID); - purchasesModel.setProperty(index, 'wornEntityID', ''); - sendToScript(msg); - }; - lightboxPopup.visible = true; - } else if (msg.itemType === "avatar" && MyAvatar.skeletonModelURL === msg.itemHref) { - lightboxPopup.titleText = "Change Avatar to Default"; - lightboxPopup.bodyText = "You are currently wearing the avatar that you are trying to update.

" + - "If you proceed, your avatar will be changed to the default avatar."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - MyAvatar.useFullAvatarURL(''); - sendToScript(msg); - }; - lightboxPopup.visible = true; - } else { - sendToScript(msg); - } - } else if (msg.method === "giftAsset") { - sendAsset.assetName = msg.itemName; - sendAsset.assetCertID = msg.certId; - sendAsset.sendingPubliclyEffectImage = msg.effectImage; - - if (msg.itemType === "avatar" && MyAvatar.skeletonModelURL === msg.itemHref) { - lightboxPopup.titleText = "Change Avatar to Default"; - lightboxPopup.bodyText = "You are currently wearing the avatar that you are trying to gift.

" + - "If you proceed, your avatar will be changed to the default avatar."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - MyAvatar.useFullAvatarURL(''); - root.activeView = "giftAsset"; - lightboxPopup.visible = false; - }; - lightboxPopup.visible = true; - } else if (msg.itemType === "app" && msg.isInstalled) { - lightboxPopup.titleText = "Uninstall App"; - lightboxPopup.bodyText = "You are currently using the app that you are trying to gift.

" + - "If you proceed, the app will be uninstalled."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - Commerce.uninstallApp(msg.itemHref); - root.activeView = "giftAsset"; - lightboxPopup.visible = false; - }; - lightboxPopup.visible = true; - } else if (msg.itemType === "wearable" && msg.wornEntityID !== '') { - lightboxPopup.titleText = "Remove Wearable"; - lightboxPopup.bodyText = "You are currently wearing the wearable that you are trying to send.

" + - "If you proceed, this wearable will be removed."; - lightboxPopup.button1text = "CANCEL"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = function() { - Entities.deleteEntity(msg.wornEntityID); - purchasesModel.setProperty(index, 'wornEntityID', ''); - root.activeView = "giftAsset"; - lightboxPopup.visible = false; - }; - lightboxPopup.visible = true; - } else { - root.activeView = "giftAsset"; - } - } - } - } - } - } - - Rectangle { - id: updatesAvailableBanner; - visible: root.numUpdatesAvailable > 0 && - filterBar.primaryFilter_filterName !== "proofs"; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - height: 75; - color: "#B5EAFF"; - - Rectangle { - id: updatesAvailableGlyph; - anchors.verticalCenter: parent.verticalCenter; - anchors.left: parent.left; - anchors.leftMargin: 16; - // Size - width: 10; - height: width; - radius: width/2; - // Style - color: "red"; - } - - RalewaySemiBold { - text: "You have " + root.numUpdatesAvailable + " item updates available."; - // Text size - size: 18; - // Anchors - anchors.left: updatesAvailableGlyph.right; - anchors.leftMargin: 12; - height: parent.height; - width: paintedWidth; - // Style - color: hifi.colors.black; - // Alignment - verticalAlignment: Text.AlignVCenter; - } - - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - propagateComposedEvents: false; - } - - HifiControlsUit.Button { - color: hifi.buttons.white; - colorScheme: hifi.colorSchemes.dark; - anchors.verticalCenter: parent.verticalCenter; - anchors.right: parent.right; - anchors.rightMargin: 12; - width: 100; - height: 40; - text: "SHOW ME"; - onClicked: { - filterBar.text = ""; - filterBar.changeFilterByDisplayName("Updatable"); - } - } - } - - Item { - id: noItemsAlertContainer; - visible: !purchasesContentsList.visible && - root.purchasesReceived && - filterBar.text === "" && - filterBar.primaryFilter_filterName === "proofs"; - anchors.top: filterBarContainer.bottom; - anchors.topMargin: 12; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: parent.width; - - // Explanitory text - RalewayRegular { - id: noItemsYet; - text: "You haven't submitted anything to the Marketplace yet!

Submit an item to the Marketplace to add it to My Submissions."; - // Text size - size: 22; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 150; - anchors.left: parent.left; - anchors.leftMargin: 24; - anchors.right: parent.right; - anchors.rightMargin: 24; - height: paintedHeight; - // Style - color: hifi.colors.baseGray; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - } - - // "Go To Marketplace" button - HifiControlsUit.Button { - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: noItemsYet.bottom; - anchors.topMargin: 20; - anchors.horizontalCenter: parent.horizontalCenter; - width: parent.width * 2 / 3; - height: 50; - text: "Visit Marketplace"; - onClicked: { - sendToScript({method: 'purchases_goToMarketplaceClicked'}); - } - } - } - - Item { - id: noPurchasesAlertContainer; - visible: !purchasesContentsList.visible && - root.purchasesReceived && - filterBar.text === "" && - filterBar.primaryFilter_displayName === ""; - anchors.top: filterBarContainer.bottom; - anchors.topMargin: 12; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: parent.width; - - // Explanitory text - RalewayRegular { - id: haventPurchasedYet; - text: "You haven't gotten anything yet!

Get an item from Marketplace to add it to your Inventory."; - // Text size - size: 22; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 150; - anchors.left: parent.left; - anchors.leftMargin: 24; - anchors.right: parent.right; - anchors.rightMargin: 24; - height: paintedHeight; - // Style - color: hifi.colors.baseGray; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - } - - // "Go To Marketplace" button - HifiControlsUit.Button { - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: haventPurchasedYet.bottom; - anchors.topMargin: 20; - anchors.horizontalCenter: parent.horizontalCenter; - width: parent.width * 2 / 3; - height: 50; - text: "Visit Marketplace"; - onClicked: { - sendToScript({method: 'purchases_goToMarketplaceClicked'}); - } - } - } - } - // - // PURCHASES CONTENTS END - // - - HifiControlsUit.Keyboard { - id: keyboard; - z: 999; - raised: HMD.mounted && parent.keyboardRaised; - numeric: parent.punctuationMode; - anchors { - bottom: parent.bottom; - left: parent.left; - right: parent.right; - } - } - - // - // FUNCTION DEFINITIONS START - // - - function updateCurrentlyWornWearables(wearables) { - for (var i = 0; i < purchasesModel.count; i++) { - for (var j = 0; j < wearables.length; j++) { - if (purchasesModel.get(i).item_type === "wearable" && - wearables[j].entityCertID === purchasesModel.get(i).certificate_id && - wearables[j].entityEdition.toString() === purchasesModel.get(i).edition_number) { - purchasesModel.setProperty(i, 'wornEntityID', wearables[j].entityID); - break; - } - } - } - } - - Keys.onPressed: { - if ((event.key == Qt.Key_F) && (event.modifiers & Qt.ControlModifier)) { - installedAppsContainer.visible = !installedAppsContainer.visible; - console.log("User changed visibility of installedAppsContainer to " + installedAppsContainer.visible); - } - } - function onFileOpenChanged(filename) { - // disconnect the event, otherwise the requests will stack up - try { // Not all calls to onFileOpenChanged() connect an event. - Window.browseChanged.disconnect(onFileOpenChanged); - } catch (e) { - console.log('Purchases.qml ignoring', e); - } - if (filename) { - Commerce.installApp(filename); - } - } - ListModel { - id: installedAppsModel; - } - onInstalledAppsChanged: { - installedAppsModel.clear(); - var installedAppsArray = root.installedApps.split(","); - var installedAppsObject = []; - // "- 1" because the last app string ends with "," - for (var i = 0; i < installedAppsArray.length - 1; i++) { - installedAppsObject[i] = { - "appUrl": installedAppsArray[i] - } - } - installedAppsModel.append(installedAppsObject); - } - - // - // Function Name: fromScript() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the JavaScript, in this case the Marketplaces JavaScript. - // Messages are in format "{method, params}", like json-rpc. - // - // Description: - // Called when a message is received from a script. - // - function fromScript(message) { - switch (message.method) { - case 'updatePurchases': - filterBar.text = message.filterText ? message.filterText : ""; - break; - case 'purchases_showMyItems': - filterBar.primaryFilter_filterName = "proofs"; - filterBar.primaryFilter_displayName = "Proofs"; - filterBar.primaryFilter_index = 6; - break; - case 'updateConnections': - sendAsset.updateConnections(message.connections); - break; - case 'selectRecipient': - case 'updateSelectedRecipientUsername': - sendAsset.fromScript(message); - break; - case 'updateWearables': - updateCurrentlyWornWearables(message.wornWearables); - break; - case 'http.response': - http.handleHttpResponse(message); - break; - default: - console.log('Purchases.qml: Unrecognized message from marketplaces.js'); - } - } - signal sendToScript(var message); - - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml deleted file mode 100644 index dbdefc4c799..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/Help.qml +++ /dev/null @@ -1,268 +0,0 @@ -// -// Help.qml -// qml/hifi/commerce/wallet -// -// Help -// -// Created by Zach Fox on 2017-08-18 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls - -// references XXX from root context - -Item { - HifiConstants { id: hifi; } - - id: root; - property string keyFilePath; - - Connections { - target: Commerce; - - onKeyFilePathIfExistsResult: { - root.keyFilePath = path; - } - } - - onVisibleChanged: { - if (visible) { - Commerce.getKeyFilePathIfExists(); - } - } - - RalewaySemiBold { - id: helpTitleText; - text: "Help Topics"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: paintedWidth; - height: 30; - // Text size - size: 18; - // Style - color: hifi.colors.blueHighlight; - } - - ListModel { - id: helpModel; - - ListElement { - isExpanded: false; - question: "How can I get HFC?"; - answer: "High Fidelity commerce is in open beta right now. Want more HFC? \ -Get it by going to
BankOfHighFidelity and meeting with the banker!"; - } - ListElement { - isExpanded: false; - question: "How do I send HFC to other people?"; - answer: "You can send HFC to a High Fidelity connection (someone you've shaken hands with in-world) or somebody Nearby (currently in the same domain as you). \ -In your Wallet's Send Money tab, choose from your list of connections, or choose Nearby and select the glowing sphere of the person's avatar."; - } - ListElement { - isExpanded: false; - question: "What is a Security Pic?" - answer: "Your Security Pic acts as an extra layer of Wallet security. \ -When you see your Security Pic, you know that your actions and data are securely making use of your account."; - } - ListElement { - isExpanded: false; - question: "Why does my HFC balance not update instantly?"; - answer: "HFC transations sometimes takes a few seconds to update as they are backed by a blockchain. \ -

Tap here to learn more about the blockchain."; - } - ListElement { - isExpanded: false; - question: "Do I get charged money if a transaction fails?"; - answer: "No. Your HFC balance only changes after a transaction is confirmed."; - } - ListElement { - isExpanded: false; - question: "How do I convert HFC to other currencies?" - answer: "We are hard at work building the tools needed to support a vibrant economy in High Fidelity. \ -At the moment, there is currently no way to convert HFC to other currencies. Stay tuned..."; - } - ListElement { - isExpanded: false; - question: "Who can I reach out to with questions?"; - answer: "Please email us if you have any issues or questions: \ -support@highfidelity.com"; - } - } - - ListView { - id: helpListView; - ScrollBar.vertical: ScrollBar { - policy: helpListView.contentHeight > helpListView.height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded; - parent: helpListView.parent; - anchors.top: helpListView.top; - anchors.right: helpListView.right; - anchors.bottom: helpListView.bottom; - width: 20; - } - anchors.top: helpTitleText.bottom; - anchors.topMargin: 30; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right - clip: true; - model: helpModel; - delegate: Item { - width: parent.width; - height: model.isExpanded ? questionContainer.height + answerContainer.height : questionContainer.height; - - HifiControlsUit.Separator { - colorScheme: 1; - visible: index === 0; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: parent.top; - } - - Item { - id: questionContainer; - anchors.top: parent.top; - anchors.left: parent.left; - width: parent.width; - height: questionText.paintedHeight + 50; - - RalewaySemiBold { - id: plusMinusButton; - text: model.isExpanded ? "-" : "+"; - // Anchors - anchors.top: parent.top; - anchors.topMargin: model.isExpanded ? -9 : 0; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - width: 60; - // Text size - size: 60; - // Style - color: hifi.colors.white; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - RalewaySemiBold { - id: questionText; - text: model.question; - size: 18; - anchors.verticalCenter: parent.verticalCenter; - anchors.left: plusMinusButton.right; - anchors.leftMargin: 4; - anchors.right: parent.right; - anchors.rightMargin: 10; - wrapMode: Text.WordWrap; - height: paintedHeight; - color: hifi.colors.white; - verticalAlignment: Text.AlignVCenter; - } - - MouseArea { - id: securityTabMouseArea; - anchors.fill: parent; - onClicked: { - model.isExpanded = !model.isExpanded; - if (model.isExpanded) { - collapseAllOtherHelpItems(index); - } - } - } - } - - Rectangle { - id: answerContainer; - visible: model.isExpanded; - color: Qt.rgba(0, 0, 0, 0.5); - anchors.top: questionContainer.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - height: answerText.paintedHeight + 50; - - RalewayRegular { - id: answerText; - text: model.answer; - size: 18; - anchors.verticalCenter: parent.verticalCenter; - anchors.left: parent.left; - anchors.leftMargin: 32; - anchors.right: parent.right; - anchors.rightMargin: 32; - wrapMode: Text.WordWrap; - height: paintedHeight; - color: hifi.colors.white; - - onLinkActivated: { - if (link === "#privateKeyPath") { - Qt.openUrlExternally("file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/'))); - } else if (link === "#blockchain") { - Qt.openUrlExternally("https://docs.vircadia.dev/explore/shop.html"); - } else if (link === "#bank") { - if ((Account.metaverseServerURL).toString().indexOf("staging") >= 0) { - Qt.openUrlExternally("hifi://hifiqa-master-metaverse-staging"); // So that we can test in staging. - } else { - Qt.openUrlExternally("hifi://BankOfHighFidelity"); - } - } else if (link === "#support") { - Qt.openUrlExternally("mailto:support@highfidelity.com"); - } - } - } - } - - HifiControlsUit.Separator { - colorScheme: 1; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - } - } - } - - - // - // FUNCTION DEFINITIONS START - // - // - // Function Name: fromScript() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the JavaScript. - // Messages are in format "{method, params}", like json-rpc. - // - // Description: - // Called when a message is received from a script. - // - function fromScript(message) { - switch (message.method) { - default: - console.log('Help.qml: Unrecognized message from wallet.js'); - } - } - signal sendSignalToWallet(var msg); - - function collapseAllOtherHelpItems(thisIndex) { - for (var i = 0; i < helpModel.count; i++) { - if (i !== thisIndex) { - helpModel.setProperty(i, "isExpanded", false); - } - } - } - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml deleted file mode 100644 index e17196b492b..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml +++ /dev/null @@ -1,193 +0,0 @@ -// -// NeedsLogIn.qml -// qml/hifi/commerce/wallet -// -// NeedsLogIn -// -// Created by Zach Fox on 2017-08-18 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls - -// references XXX from root context - -Item { - HifiConstants { id: hifi; } - - id: root; - - Image { - anchors.fill: parent; - source: "images/wallet-bg.jpg"; - } - - Connections { - target: Commerce; - } - - // - // LOGIN PAGE START - // - Item { - id: loginPageContainer; - // Anchors - anchors.fill: parent; - - Item { - id: loginTitle; - // Size - width: parent.width; - height: 50; - // Anchors - anchors.left: parent.left; - anchors.top: parent.top; - - // Title Bar text - RalewaySemiBold { - text: "Log in to continue"; - // Text size - size: hifi.fontSizes.overlayTitle; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.bottom: parent.bottom; - width: paintedWidth; - // Style - color: hifi.colors.faintGray; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - } - - // Text below title bar - RalewaySemiBold { - id: loginTitleHelper; - text: "Please Log In to High Fidelity"; - // Text size - size: 24; - // Anchors - anchors.top: loginTitle.bottom; - anchors.topMargin: 100; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: 50; - // Style - color: hifi.colors.faintGray; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - // Text below helper text - RalewayRegular { - id: loginDetailText; - text: "To get items on the Marketplace, or to use your Assets, you must first log in to High Fidelity."; - // Text size - size: 18; - // Anchors - anchors.top: loginTitleHelper.bottom; - anchors.topMargin: 25; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: 50; - // Style - color: hifi.colors.faintGray; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - - - Item { - // Size - width: root.width; - height: 70; - // Anchors - anchors.top: loginDetailText.bottom; - anchors.topMargin: 40; - anchors.left: parent.left; - - // "Cancel" button - HifiControlsUit.Button { - id: cancelButton; - color: hifi.buttons.black; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.topMargin: 3; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 3; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: parent.width/2 - anchors.leftMargin*2; - text: "Cancel" - onClicked: { - sendToScript({method: 'passphrasePopup_cancelClicked'}); - } - } - - // "Set Up" button - HifiControlsUit.Button { - id: setUpButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.topMargin: 3; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 3; - anchors.right: parent.right; - anchors.rightMargin: 20; - width: parent.width/2 - anchors.rightMargin*2; - text: "Log In" - onClicked: { - sendToScript({method: 'marketplace_loginClicked'}); - } - } - } - } - // - // LOGIN PAGE END - // - - // - // FUNCTION DEFINITIONS START - // - // - // Function Name: fromScript() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the JavaScript. - // Messages are in format "{method, params}", like json-rpc. - // - // Description: - // Called when a message is received from a script. - // - function fromScript(message) { - switch (message.method) { - default: - console.log('NeedsLogIn.qml: Unrecognized message from wallet.js'); - } - } - signal sendSignalToWallet(var msg); - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml deleted file mode 100644 index 6ddfe0da1ce..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml +++ /dev/null @@ -1,170 +0,0 @@ -// -// PassphraseChange.qml -// qml/hifi/commerce/wallet -// -// PassphraseChange -// -// Created by Zach Fox on 2017-08-18 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls - -// references XXX from root context - -Item { - HifiConstants { id: hifi; } - - id: root; - - // This will cause a bug -- if you bring up passphrase selection in HUD mode while - // in HMD while having HMD preview enabled, then move, then finish passphrase selection, - // HMD preview will stay off. - // TODO: Fix this unlikely bug - onVisibleChanged: { - if (visible) { - sendSignalToWallet({method: 'disableHmdPreview'}); - } else { - sendSignalToWallet({method: 'maybeEnableHmdPreview'}); - } - } - - // Username Text - RalewayRegular { - id: usernameText; - text: Account.username; - // Text size - size: 24; - // Style - color: hifi.colors.white; - elide: Text.ElideRight; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: parent.width/2; - height: 80; - } - - // - // SECURE PASSPHRASE SELECTION START - // - Item { - id: choosePassphraseContainer; - // Anchors - anchors.top: usernameText.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - - // "Change Passphrase" text - RalewaySemiBold { - id: passphraseTitle; - text: "Change Passphrase:"; - // Text size - size: 18; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - height: 30; - // Style - color: hifi.colors.blueHighlight; - } - - PassphraseSelection { - id: passphraseSelection; - isChangingPassphrase: true; - anchors.top: passphraseTitle.bottom; - anchors.topMargin: 8; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: passphraseNavBar.top; - - Connections { - onSendMessageToLightbox: { - if (msg.method === 'statusResult') { - if (msg.status) { - // Success submitting new passphrase - sendSignalToWallet({method: "walletSecurity_changePassphraseSuccess"}); - } else { - // Error submitting new passphrase - resetSubmitButton(); - passphraseSelection.setErrorText("Current passphrase incorrect - try again"); - } - } else { - sendSignalToWallet(msg); - } - } - } - } - - // Navigation Bar - Item { - id: passphraseNavBar; - // Size - width: parent.width; - height: 40; - // Anchors: - anchors.left: parent.left; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 30; - - // "Cancel" button - HifiControlsUit.Button { - color: hifi.buttons.noneBorderlessWhite; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: 150; - text: "Cancel" - onClicked: { - sendSignalToWallet({method: "walletSecurity_changePassphraseCancelled"}); - } - } - - // "Submit" button - HifiControlsUit.Button { - id: passphraseSubmitButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.right: parent.right; - anchors.rightMargin: 20; - width: 150; - text: "Submit"; - onClicked: { - passphraseSubmitButton.text = "Submitting..."; - passphraseSubmitButton.enabled = false; - if (!passphraseSelection.validateAndSubmitPassphrase()) { - resetSubmitButton(); - } - } - } - } - } - // - // SECURE PASSPHRASE SELECTION END - // - - signal sendSignalToWallet(var msg); - - function resetSubmitButton() { - passphraseSubmitButton.enabled = true; - passphraseSubmitButton.text = "Submit"; - } - - function clearPassphraseFields() { - passphraseSelection.clearPassphraseFields(); - } -} diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml deleted file mode 100644 index 86d50e87ec8..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ /dev/null @@ -1,394 +0,0 @@ -// -// PassphraseModal.qml -// qml/hifi/commerce/wallet -// -// PassphraseModal -// -// Created by Zach Fox on 2017-08-31 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../common" as HifiCommerceCommon - -// references XXX from root context - -Item { - HifiConstants { id: hifi; } - - id: root; - z: 997; - property bool keyboardRaised: false; - property bool isPasswordField: false; - property string titleBarIcon: ""; - property string titleBarText: ""; - - Image { - anchors.fill: parent; - source: "images/wallet-bg.jpg"; - } - - Connections { - target: Commerce; - - onSecurityImageResult: { - titleBarSecurityImage.source = ""; - titleBarSecurityImage.source = "image://security/securityImage"; - passphraseModalSecurityImage.source = ""; - passphraseModalSecurityImage.source = "image://security/securityImage"; - } - - onWalletAuthenticatedStatusResult: { - submitPassphraseInputButton.enabled = true; - - // It's not possible to auth with a blank passphrase, - // so bail early if we get this signal without anything in the passphrase field - if (passphraseField.text === "") { - return; - } - - if (!isAuthenticated) { - errorText.text = "Authentication failed - please try again."; - passphraseField.error = true; - UserActivityLogger.commercePassphraseAuthenticationStatus("auth failure"); - } else { - sendSignalToParent({method: 'authSuccess'}); - passphraseField.error = false; - UserActivityLogger.commercePassphraseAuthenticationStatus("auth success"); - } - } - } - - // This object is always used in a popup. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - // This will cause a bug -- if you bring up passphrase selection in HUD mode while - // in HMD while having HMD preview enabled, then move, then finish passphrase selection, - // HMD preview will stay off. - // TODO: Fix this unlikely bug - onVisibleChanged: { - if (visible) { - sendSignalToParent({method: 'disableHmdPreview'}); - } else { - sendSignalToParent({method: 'maybeEnableHmdPreview'}); - } - } - - HifiCommerceCommon.CommerceLightbox { - id: lightboxPopup; - visible: false; - anchors.fill: parent; - } - - Item { - id: titleBar; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - height: 50; - - // Wallet icon - HiFiGlyphs { - id: titleBarIcon; - text: root.titleBarIcon; - // Size - size: parent.height * 0.8; - // Anchors - anchors.left: parent.left; - anchors.leftMargin: 8; - anchors.verticalCenter: parent.verticalCenter; - // Style - color: hifi.colors.blueHighlight; - } - - RalewaySemiBold { - id: titleBarText; - text: root.titleBarText; - anchors.top: parent.top; - anchors.left: titleBarIcon.right; - anchors.leftMargin: 4; - anchors.bottom: parent.bottom; - anchors.right: parent.right; - size: 20; - color: hifi.colors.white; - verticalAlignment: Text.AlignVCenter; - } - - Image { - id: titleBarSecurityImage; - source: ""; - visible: titleBarSecurityImage.source !== ""; - anchors.right: parent.right; - anchors.rightMargin: 6; - anchors.top: parent.top; - anchors.topMargin: 6; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 6; - width: height; - fillMode: Image.PreserveAspectFit; - mipmap: true; - cache: false; - - MouseArea { - enabled: titleBarSecurityImage.visible; - anchors.fill: parent; - onClicked: { - lightboxPopup.titleText = "Your Security Pic"; - lightboxPopup.bodyImageSource = titleBarSecurityImage.source; - lightboxPopup.bodyText = lightboxPopup.securityPicBodyText; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } - } - } - } - - Item { - id: passphraseContainer; - anchors.top: titleBar.bottom; - anchors.left: parent.left; - anchors.leftMargin: 8; - anchors.right: parent.right; - anchors.rightMargin: 8; - height: 250; - - RalewaySemiBold { - id: instructionsText; - text: "Please Enter Your Passphrase"; - size: 24; - anchors.top: parent.top; - anchors.topMargin: 30; - anchors.left: parent.left; - anchors.leftMargin: 16; - width: passphraseField.width; - height: paintedHeight; - // Style - color: hifi.colors.white; - // Alignment - horizontalAlignment: Text.AlignLeft; - } - - // Error text above buttons - RalewaySemiBold { - id: errorText; - text: ""; - // Text size - size: 15; - // Anchors - anchors.bottom: passphraseField.top; - anchors.bottomMargin: 4; - anchors.left: passphraseField.left; - anchors.right: parent.right; - height: 20; - // Style - color: hifi.colors.redHighlight; - } - - HifiControlsUit.TextField { - id: passphraseField; - colorScheme: hifi.colorSchemes.dark; - anchors.top: instructionsText.bottom; - anchors.topMargin: 40; - anchors.left: instructionsText.left; - width: 260; - height: 50; - echoMode: TextInput.Password; - placeholderText: "passphrase"; - activeFocusOnPress: true; - activeFocusOnTab: true; - - onVisibleChanged: { - if (visible) { - error = false; - focus = true; - forceActiveFocus(); - } else { - showPassphrase.checked = false; - passphraseField.text = ""; - error = false; - } - } - - onFocusChanged: { - root.keyboardRaised = focus; - root.isPasswordField = (focus && passphraseField.echoMode === TextInput.Password); - } - - onAccepted: { - submitPassphraseInputButton.enabled = false; - Commerce.setPassphrase(passphraseField.text); - } - } - - // Show passphrase text - HifiControlsUit.CheckBox { - id: showPassphrase; - colorScheme: hifi.colorSchemes.dark; - anchors.left: passphraseField.left; - anchors.top: passphraseField.bottom; - anchors.topMargin: 8; - height: 30; - text: "Show passphrase"; - boxSize: 24; - onClicked: { - passphraseField.echoMode = checked ? TextInput.Normal : TextInput.Password; - } - } - - // Security Image - Item { - id: securityImageContainer; - // Anchors - anchors.top: passphraseField.top; - anchors.left: passphraseField.right; - anchors.leftMargin: 8; - anchors.right: parent.right; - anchors.rightMargin: 8; - height: 145; - Image { - id: passphraseModalSecurityImage; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: iconAndTextContainer.top; - fillMode: Image.PreserveAspectFit; - mipmap: true; - source: "image://security/securityImage"; - cache: false; - onVisibleChanged: { - Commerce.getSecurityImage(); - } - } - Item { - id: iconAndTextContainer; - anchors.left: passphraseModalSecurityImage.left; - anchors.right: passphraseModalSecurityImage.right; - anchors.bottom: parent.bottom; - height: 24; - // Lock icon - HiFiGlyphs { - id: lockIcon; - text: hifi.glyphs.lock; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.leftMargin: 30; - size: 20; - width: height; - verticalAlignment: Text.AlignBottom; - color: hifi.colors.white; - } - // "Security image" text below pic - RalewayRegular { - id: securityImageText; - text: "SECURITY PIC"; - // Text size - size: 12; - // Anchors - anchors.bottom: parent.bottom; - anchors.right: parent.right; - anchors.rightMargin: lockIcon.anchors.leftMargin; - width: paintedWidth; - height: 22; - // Style - color: hifi.colors.white; - // Alignment - horizontalAlignment: Text.AlignRight; - verticalAlignment: Text.AlignBottom; - } - } - } - - // - // ACTION BUTTONS START - // - Item { - id: passphrasePopupActionButtonsContainer; - // Anchors - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - - // "Submit" button - HifiControlsUit.Button { - id: submitPassphraseInputButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.topMargin: 20; - height: 40; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - width: parent.width/2 -4; - text: "Submit" - onClicked: { - submitPassphraseInputButton.enabled = false; - Commerce.setPassphrase(passphraseField.text); - } - } - - // "Cancel" button - HifiControlsUit.Button { - id: cancelPassphraseInputButton; - color: hifi.buttons.noneBorderlessWhite; - colorScheme: hifi.colorSchemes.dark; - anchors.top: submitPassphraseInputButton.bottom; - anchors.topMargin: 20; - height: 40; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - width: parent.width/2 - 4; - text: "Cancel" - onClicked: { - sendSignalToParent({method: 'passphrasePopup_cancelClicked'}); - UserActivityLogger.commercePassphraseAuthenticationStatus("passphrase modal cancelled"); - } - } - } - } - - Item { - id: keyboardContainer; - z: 998; - visible: keyboard.raised; - property bool punctuationMode: false; - anchors { - bottom: parent.bottom; - left: parent.left; - right: parent.right; - } - - HifiControlsUit.Keyboard { - id: keyboard; - raised: HMD.mounted && root.keyboardRaised; - numeric: parent.punctuationMode; - password: root.isPasswordField; - anchors { - bottom: parent.bottom; - left: parent.left; - right: parent.right; - } - } - } - - signal sendSignalToParent(var msg); -} diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml deleted file mode 100644 index 179ffcf7070..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ /dev/null @@ -1,311 +0,0 @@ -// -// PassphraseSelection.qml -// qml/hifi/commerce/wallet -// -// PassphraseSelection -// -// Created by Zach Fox on 2017-08-18 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls - -// references XXX from root context - -Item { - HifiConstants { id: hifi; } - - id: root; - property bool isChangingPassphrase: false; - property bool isShowingTip: false; - property bool shouldImmediatelyFocus: true; - - // This object is always used in a popup. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - Connections { - target: Commerce; - onSecurityImageResult: { - passphrasePageSecurityImage.source = ""; - passphrasePageSecurityImage.source = "image://security/securityImage"; - } - - onChangePassphraseStatusResult: { - sendMessageToLightbox({method: 'statusResult', status: changeSuccess}); - } - } - - // This will cause a bug -- if you bring up passphrase selection in HUD mode while - // in HMD while having HMD preview enabled, then move, then finish passphrase selection, - // HMD preview will stay off. - // TODO: Fix this unlikely bug - onVisibleChanged: { - if (visible) { - passphraseField.error = false; - passphraseFieldAgain.error = false; - currentPassphraseField.error = false; - if (root.shouldImmediatelyFocus) { - focusFirstTextField(); - } - } - } - - - HifiControlsUit.TextField { - id: currentPassphraseField; - colorScheme: hifi.colorSchemes.dark; - visible: root.isChangingPassphrase; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: passphraseField.right; - height: 50; - echoMode: TextInput.Password; - placeholderText: "enter current passphrase"; - activeFocusOnPress: true; - activeFocusOnTab: true; - - onFocusChanged: { - if (focus) { - var hidePassword = (currentPassphraseField.echoMode === TextInput.Password); - sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); - } - } - - onAccepted: { - passphraseField.focus = true; - } - } - - HifiControlsUit.TextField { - id: passphraseField; - colorScheme: hifi.colorSchemes.dark; - anchors.top: root.isChangingPassphrase ? currentPassphraseField.bottom : parent.top; - anchors.topMargin: root.isChangingPassphrase ? 40 : 0; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: 285; - height: 50; - echoMode: TextInput.Password; - placeholderText: root.isShowingTip ? "" : "enter new passphrase"; - activeFocusOnPress: true; - activeFocusOnTab: true; - - onFocusChanged: { - if (focus) { - var hidePassword = (passphraseField.echoMode === TextInput.Password); - sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); - } - } - - onAccepted: { - passphraseFieldAgain.focus = true; - } - } - - HifiControlsUit.TextField { - id: passphraseFieldAgain; - colorScheme: hifi.colorSchemes.dark; - anchors.top: passphraseField.bottom; - anchors.topMargin: root.isChangingPassphrase ? 20 : 40; - anchors.left: passphraseField.left; - anchors.right: passphraseField.right; - height: 50; - echoMode: TextInput.Password; - placeholderText: root.isShowingTip ? "" : "re-enter new passphrase"; - activeFocusOnPress: true; - activeFocusOnTab: true; - - onFocusChanged: { - if (focus) { - var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password); - sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword}); - } - } - - onAccepted: { - focus = false; - } - } - - // Security Image - Item { - id: securityImageContainer; - // Anchors - anchors.top: root.isChangingPassphrase ? currentPassphraseField.top : passphraseField.top; - anchors.left: passphraseField.right; - anchors.right: parent.right; - anchors.bottom: root.isChangingPassphrase ? passphraseField.bottom : passphraseFieldAgain.bottom; - Image { - id: passphrasePageSecurityImage; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: iconAndTextContainer.top; - fillMode: Image.PreserveAspectFit; - mipmap: true; - source: "image://security/securityImage"; - cache: false; - onVisibleChanged: { - Commerce.getSecurityImage(); - } - } - Item { - id: iconAndTextContainer; - anchors.left: passphrasePageSecurityImage.left; - anchors.right: passphrasePageSecurityImage.right; - anchors.bottom: parent.bottom; - height: 22; - // Lock icon - HiFiGlyphs { - id: lockIcon; - text: hifi.glyphs.lock; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.leftMargin: 35; - size: 20; - width: height; - verticalAlignment: Text.AlignBottom; - color: hifi.colors.white; - } - // "Security image" text below pic - RalewayRegular { - id: securityImageText; - text: "SECURITY PIC"; - // Text size - size: 12; - // Anchors - anchors.bottom: parent.bottom; - anchors.right: parent.right; - anchors.rightMargin: lockIcon.anchors.leftMargin; - width: paintedWidth; - height: 22; - // Style - color: hifi.colors.white; - // Alignment - horizontalAlignment: Text.AlignRight; - verticalAlignment: Text.AlignBottom; - } - } - } - - // Error text above TextFields - RalewaySemiBold { - id: errorText; - text: ""; - // Text size - size: 15; - // Anchors - anchors.bottom: passphraseField.top; - anchors.bottomMargin: 4; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: securityImageContainer.left; - anchors.rightMargin: 4; - height: 30; - // Style - color: hifi.colors.redHighlight; - // Alignment - verticalAlignment: Text.AlignVCenter; - } - - // Show passphrase text - HifiControlsUit.CheckBox { - id: showPassphrase; - visible: !root.isShowingTip; - colorScheme: hifi.colorSchemes.dark; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.top: passphraseFieldAgain.bottom; - anchors.topMargin: 16; - height: 30; - text: "Show passphrase"; - boxSize: 24; - onClicked: { - passphraseField.echoMode = checked ? TextInput.Normal : TextInput.Password; - passphraseFieldAgain.echoMode = checked ? TextInput.Normal : TextInput.Password; - if (root.isChangingPassphrase) { - currentPassphraseField.echoMode = checked ? TextInput.Normal : TextInput.Password; - } - } - } - - // Text below checkbox - RalewayRegular { - visible: !root.isShowingTip; - text: "Your passphrase is used to encrypt your private keys. Only you have it.

Please write it down.

If it is lost, you will not be able to recover it."; - // Text size - size: 18; - // Anchors - anchors.top: showPassphrase.bottom; - anchors.topMargin: 16; - anchors.left: parent.left; - anchors.leftMargin: 24; - anchors.right: parent.right; - anchors.rightMargin: 24; - height: paintedHeight; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - function validateAndSubmitPassphrase() { - if (passphraseField.text.length < 3) { - setErrorText("Passphrase must be at least 3 characters."); - passphraseField.error = true; - passphraseFieldAgain.error = true; - currentPassphraseField.error = true; - return false; - } else if (passphraseField.text !== passphraseFieldAgain.text) { - setErrorText("Passphrases don't match."); - passphraseField.error = true; - passphraseFieldAgain.error = true; - currentPassphraseField.error = true; - return false; - } else { - passphraseField.error = false; - passphraseFieldAgain.error = false; - currentPassphraseField.error = false; - setErrorText(""); - Commerce.changePassphrase(currentPassphraseField.text, passphraseField.text); - return true; - } - } - - function setErrorText(text) { - errorText.text = text; - } - - function clearPassphraseFields() { - currentPassphraseField.text = ""; - passphraseField.text = ""; - passphraseFieldAgain.text = ""; - setErrorText(""); - } - - function focusFirstTextField() { - if (root.isChangingPassphrase) { - currentPassphraseField.focus = true; - } else { - passphraseField.focus = true; - } - } - - signal sendMessageToLightbox(var msg); -} diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml deleted file mode 100644 index 7c2b86ef993..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ /dev/null @@ -1,865 +0,0 @@ -// -// Wallet.qml -// qml/hifi/commerce/wallet -// -// Wallet -// -// Created by Zach Fox on 2017-08-17 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../common" as HifiCommerceCommon -import "../common/sendAsset" -import "../.." as HifiCommon -import "../purchases" as HifiPurchases -import "../inspectionCertificate" as HifiInspectionCertificate - -Rectangle { - HifiConstants { id: hifi; } - - id: root; - - property string activeView: "initialize"; - property string initialActiveViewAfterStatus5: "walletInventory"; - property bool keyboardRaised: false; - property bool isPassword: false; - property bool has3DHTML: PlatformInfo.has3DHTML(); - - anchors.fill: (typeof parent === undefined) ? undefined : parent; - - Image { - anchors.fill: parent; - source: "images/wallet-bg.jpg"; - } - - Connections { - target: Commerce; - - onWalletStatusResult: { - if (walletStatus === 0) { - if (root.activeView !== "needsLogIn") { - root.activeView = "needsLogIn"; - } - } else if (walletStatus === 1) { - if (root.activeView !== "walletSetup") { - walletResetSetup(); - } - } else if (walletStatus === 2) { - if (root.activeView != "preexisting") { - root.activeView = "preexisting"; - } - } else if (walletStatus === 3) { - if (root.activeView != "conflicting") { - root.activeView = "conflicting"; - } - } else if (walletStatus === 4) { - if (root.activeView !== "passphraseModal") { - root.activeView = "passphraseModal"; - UserActivityLogger.commercePassphraseEntry("wallet app"); - } - } else if (walletStatus === 5) { - if (root.activeView !== "walletSetup") { - root.activeView = root.initialActiveViewAfterStatus5; - Commerce.getAvailableUpdates(); - Commerce.getSecurityImage(); - } - } else { - console.log("ERROR in Wallet.qml: Unknown wallet status: " + walletStatus); - } - } - - onLoginStatusResult: { - if (!isLoggedIn && root.activeView !== "needsLogIn") { - root.activeView = "needsLogIn"; - } else if (isLoggedIn) { - Commerce.getWalletStatus(); - } - } - - onSecurityImageResult: { - if (exists) { - titleBarSecurityImage.source = ""; - titleBarSecurityImage.source = "image://security/securityImage"; - } - } - - onAvailableUpdatesResult: { - if (result.status !== 'success') { - console.log("Failed to get Available Updates", result.data.message); - } else { - exchangeMoneyButtonContainer.messagesWaiting = result.data.updates.length > 0; - if (!exchangeMoneyButtonContainer.messagesWaiting) { - sendToScript({method: 'clearShouldShowDotUpdates'}); - } - } - } - } - - onActiveViewChanged: { - if (activeView === "walletHome") { - walletHomeButtonContainer.messagesWaiting = false; - sendToScript({method: 'clearShouldShowDotHistory'}); - } - } - - HifiCommerceCommon.CommerceLightbox { - id: lightboxPopup; - visible: false; - anchors.fill: parent; - } - - // - // TITLE BAR START - // - Item { - id: titleBarContainer; - visible: !needsLogIn.visible; - // Size - width: parent.width; - height: 50; - // Anchors - anchors.left: parent.left; - anchors.top: parent.top; - - // Wallet icon - Image { - id: walletIcon; - source: "../../../../icons/tablet-icons/inventory-a.svg"; - height: parent.height * 0.5; - width: walletIcon.height; - anchors.left: parent.left; - anchors.leftMargin: 8; - anchors.verticalCenter: parent.verticalCenter; - visible: false; // When we use a white .svg instead of a glyph with color property, we set to invisible and use the following ColorOverlay. - } - ColorOverlay { - anchors.fill: walletIcon; - source: walletIcon; - color: hifi.colors.blueHighlight; - } - - // Title Bar text - RalewaySemiBold { - id: titleBarText; - text: "INVENTORY"; - // Text size - size: hifi.fontSizes.overlayTitle; - // Anchors - anchors.top: parent.top; - anchors.left: walletIcon.right; - anchors.leftMargin: 6; - anchors.bottom: parent.bottom; - width: paintedWidth; - // Style - color: hifi.colors.white; - // Alignment - verticalAlignment: Text.AlignVCenter; - } - - Image { - id: titleBarSecurityImage; - source: ""; - visible: titleBarSecurityImage.source !== ""; - anchors.right: parent.right; - anchors.rightMargin: 6; - anchors.top: parent.top; - anchors.topMargin: 6; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 6; - width: height; - mipmap: true; - cache: false; - - MouseArea { - enabled: titleBarSecurityImage.visible; - anchors.fill: parent; - onClicked: { - lightboxPopup.titleText = "Your Security Pic"; - lightboxPopup.bodyImageSource = titleBarSecurityImage.source; - lightboxPopup.bodyText = lightboxPopup.securityPicBodyText; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } - } - } - } - // - // TITLE BAR END - // - - WalletChoice { - id: walletChoice; - proceedFunction: function (isReset) { - console.log("WalletChoice", isReset ? "Reset wallet." : "Trying again with new wallet."); - Commerce.setSoftReset(); - if (isReset) { - walletResetSetup(); - } else { - Commerce.clearWallet(); - var msg = { referrer: walletChoice.referrer } - followReferrer(msg); - } - } - copyFunction: Commerce.copyKeyFileFrom; - z: 997; - visible: (root.activeView === "preexisting") || (root.activeView === "conflicting"); - activeView: root.activeView; - anchors.fill: parent; - } - - WalletSetup { - id: walletSetup; - visible: root.activeView === "walletSetup"; - z: 997; - anchors.fill: parent; - - Connections { - onSendSignalToWallet: { - if (msg.method === 'walletSetup_finished') { - followReferrer(msg); - } else if (msg.method === 'walletSetup_raiseKeyboard') { - root.keyboardRaised = true; - root.isPassword = msg.isPasswordField; - } else if (msg.method === 'walletSetup_lowerKeyboard') { - root.keyboardRaised = false; - root.isPassword = msg.isPasswordField; - } else { - sendToScript(msg); - } - } - } - } - PassphraseChange { - id: passphraseChange; - visible: root.activeView === "passphraseChange"; - z: 997; - anchors.top: titleBarContainer.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - - Connections { - onSendSignalToWallet: { - if (passphraseChange.visible) { - if (msg.method === 'walletSetup_raiseKeyboard') { - root.keyboardRaised = true; - root.isPassword = msg.isPasswordField; - } else if (msg.method === 'walletSetup_lowerKeyboard') { - root.keyboardRaised = false; - } else { - sendToScript(msg); - } - } else { - sendToScript(msg); - } - } - } - } - - // - // TAB CONTENTS START - // - - Rectangle { - id: initialize; - visible: root.activeView === "initialize"; - anchors.top: titleBarContainer.bottom; - anchors.bottom: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - color: hifi.colors.baseGray; - - Component.onCompleted: { - Commerce.getWalletStatus(); - } - } - - NeedsLogIn { - id: needsLogIn; - visible: root.activeView === "needsLogIn"; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - - Connections { - onSendSignalToWallet: { - sendToScript(msg); - } - } - } - Connections { - target: GlobalServices - onMyUsernameChanged: { - Commerce.getLoginStatus(); - } - } - - PassphraseModal { - id: passphraseModal; - visible: root.activeView === "passphraseModal"; - anchors.fill: parent; - titleBarText: "Wallet"; - titleBarIcon: hifi.glyphs.wallet; - - Connections { - onSendSignalToParent: { - if (msg.method === "authSuccess") { - Commerce.getWalletStatus(); - } else { - sendToScript(msg); - } - } - } - } - - WalletHome { - id: walletHome; - visible: root.activeView === "walletHome"; - anchors.top: titleBarContainer.bottom; - anchors.bottom: tabButtonsContainer.top; - anchors.left: parent.left; - anchors.right: parent.right; - - Connections { - onSendSignalToWallet: { - if (msg.method === 'transactionHistory_usernameLinkClicked') { - if (has3DHTML) { - userInfoViewer.url = msg.usernameLink; - userInfoViewer.visible = true; - } - } else { - sendToScript(msg); - } - } - } - } - - HifiInspectionCertificate.InspectionCertificate { - id: inspectionCertificate; - z: 998; - visible: false; - anchors.fill: parent; - - Connections { - onSendToScript: { - sendToScript(message); - } - } - } - - HifiPurchases.Purchases { - id: walletInventory; - visible: root.activeView === "walletInventory"; - anchors.top: titleBarContainer.bottom; - anchors.bottom: !WalletScriptingInterface.limitedCommerce ? tabButtonsContainer.top : parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - Connections { - onSendToScript: { - if (message.method === 'purchases_itemCertificateClicked') { - inspectionCertificate.visible = true; - inspectionCertificate.isLightbox = true; - sendToScript(message); - } else { - sendToScript(message); - } - } - } - } - - HifiCommon.RootHttpRequest { - id: http; - } - - SendAsset { - id: sendMoney; - http: http; - listModelName: "Send Money Connections"; - z: 997; - visible: root.activeView === "sendMoney"; - keyboardContainer: root; - anchors.fill: parent; - parentAppTitleBarHeight: titleBarContainer.height; - parentAppNavBarHeight: tabButtonsContainer.height; - - Connections { - onSendSignalToParent: { - sendToScript(msg); - } - } - } - - Help { - id: help; - visible: root.activeView === "help"; - anchors.top: titleBarContainer.bottom; - anchors.bottom: tabButtonsContainer.top; - anchors.left: parent.left; - anchors.right: parent.right; - - } - - - // - // TAB CONTENTS END - // - - // - // TAB BUTTONS START - // - Item { - id: tabButtonsContainer; - visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && sendMoney.currentActiveView !== "sendAssetStep" && !WalletScriptingInterface.limitedCommerce; - property int numTabs: 4; - // Size - width: root.width; - height: 90; - // Anchors - anchors.left: parent.left; - anchors.bottom: parent.bottom; - - // Separator - HifiControlsUit.Separator { - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: parent.top; - } - - // "WALLET HOME" tab button - Rectangle { - id: walletHomeButtonContainer; - property bool messagesWaiting: false; - visible: !walletSetup.visible; - color: root.activeView === "walletHome" ? hifi.colors.blueAccent : hifi.colors.black; - anchors.top: parent.top; - anchors.left: exchangeMoneyButtonContainer.right; - anchors.bottom: parent.bottom; - width: parent.width / tabButtonsContainer.numTabs; - - HiFiGlyphs { - id: homeTabIcon; - text: hifi.glyphs.leftRightArrows; - // Size - size: 50; - // Anchors - anchors.horizontalCenter: parent.horizontalCenter; - anchors.top: parent.top; - anchors.topMargin: -2; - // Style - color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); - } - - Rectangle { - id: recentActivityMessagesWaitingLight; - visible: parent.messagesWaiting; - anchors.right: homeTabIcon.left; - anchors.rightMargin: -4; - anchors.top: homeTabIcon.top; - anchors.topMargin: 16; - height: 10; - width: height; - radius: height/2; - color: "red"; - } - - RalewaySemiBold { - text: "RECENT ACTIVITY"; - // Text size - size: 16; - // Anchors - anchors.bottom: parent.bottom; - height: parent.height/2; - anchors.left: parent.left; - anchors.leftMargin: 4; - anchors.right: parent.right; - anchors.rightMargin: 4; - // Style - color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignTop; - } - MouseArea { - id: walletHomeTabMouseArea; - anchors.fill: parent; - enabled: !WalletScriptingInterface.limitedCommerce; - hoverEnabled: enabled; - onClicked: { - root.activeView = "walletHome"; - tabButtonsContainer.resetTabButtonColors(); - } - onEntered: parent.color = hifi.colors.blueHighlight; - onExited: parent.color = root.activeView === "walletHome" ? hifi.colors.blueAccent : hifi.colors.black; - } - } - - // "EXCHANGE MONEY" tab button - Rectangle { - id: exchangeMoneyButtonContainer; - property bool messagesWaiting: false; - - visible: !walletSetup.visible; - color: root.activeView === "walletInventory" ? hifi.colors.blueAccent : hifi.colors.black; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: parent.width / tabButtonsContainer.numTabs; - - Image { - id: exchangeMoneyTabIcon; - source: "images/items-tab-a.svg"; - height: 25; - width: exchangeMoneyTabIcon.height; - anchors.horizontalCenter: parent.horizontalCenter; - anchors.top: parent.top; - anchors.topMargin: 10; - visible: false; // When we use a white .svg instead of a glyph with color property, we set to invisible and use the following ColorOverlay. - } - ColorOverlay { - anchors.fill: exchangeMoneyTabIcon; - source: exchangeMoneyTabIcon; - color: root.activeView === "walletInventory" || inventoryTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight; - } - - Rectangle { - id: exchangeMoneyMessagesWaitingLight; - visible: parent.messagesWaiting; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.top: exchangeMoneyTabIcon.top; - anchors.topMargin: 4; - height: 10; - width: height; - radius: height/2; - color: "red"; - } - - RalewaySemiBold { - text: "ITEMS"; - // Text size - size: 16; - // Anchors - anchors.bottom: parent.bottom; - height: parent.height/2; - anchors.left: parent.left; - anchors.leftMargin: 4; - anchors.right: parent.right; - anchors.rightMargin: 4; - // Style - color: root.activeView === "walletInventory" || inventoryTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignTop; - } - - MouseArea { - id: inventoryTabMouseArea; - anchors.fill: parent; - hoverEnabled: enabled; - onClicked: { - root.activeView = "walletInventory"; - tabButtonsContainer.resetTabButtonColors(); - } - onEntered: parent.color = hifi.colors.blueHighlight; - onExited: parent.color = root.activeView === "walletInventory" ? hifi.colors.blueAccent : hifi.colors.black; - } - } - - - // "SEND MONEY" tab button - Rectangle { - id: sendMoneyButtonContainer; - visible: !walletSetup.visible; - color: root.activeView === "sendMoney" ? hifi.colors.blueAccent : hifi.colors.black; - anchors.top: parent.top; - anchors.left: walletHomeButtonContainer.right; - anchors.bottom: parent.bottom; - width: parent.width / tabButtonsContainer.numTabs; - - HiFiGlyphs { - id: sendMoneyTabIcon; - text: hifi.glyphs.paperPlane; - // Size - size: 46; - // Anchors - anchors.horizontalCenter: parent.horizontalCenter; - anchors.top: parent.top; - anchors.topMargin: -2; - // Style - color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); - } - - RalewaySemiBold { - text: "SEND MONEY"; - // Text size - size: 16; - // Anchors - anchors.bottom: parent.bottom; - height: parent.height/2; - anchors.left: parent.left; - anchors.leftMargin: 4; - anchors.right: parent.right; - anchors.rightMargin: 4; - // Style - color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignTop; - } - - MouseArea { - id: sendMoneyTabMouseArea; - anchors.fill: parent; - enabled: !WalletScriptingInterface.limitedCommerce; - hoverEnabled: enabled; - onClicked: { - root.activeView = "sendMoney"; - tabButtonsContainer.resetTabButtonColors(); - } - onEntered: parent.color = hifi.colors.blueHighlight; - onExited: parent.color = root.activeView === "sendMoney" ? hifi.colors.blueAccent : hifi.colors.black; - } - } - - // "HELP" tab button - Rectangle { - id: helpButtonContainer; - visible: !walletSetup.visible; - color: root.activeView === "help" ? hifi.colors.blueAccent : hifi.colors.black; - anchors.top: parent.top; - anchors.left: sendMoneyButtonContainer.right; - anchors.bottom: parent.bottom; - width: parent.width / tabButtonsContainer.numTabs; - - HiFiGlyphs { - id: helpTabIcon; - text: hifi.glyphs.question; - // Size - size: 55; - // Anchors - anchors.horizontalCenter: parent.horizontalCenter; - anchors.top: parent.top; - anchors.topMargin: -6; - // Style - color: root.activeView === "help" || helpTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight; - } - - RalewaySemiBold { - text: "HELP"; - // Text size - size: 16; - // Anchors - anchors.bottom: parent.bottom; - height: parent.height/2; - anchors.left: parent.left; - anchors.leftMargin: 4; - anchors.right: parent.right; - anchors.rightMargin: 4; - // Style - color: root.activeView === "help" || helpTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignTop; - } - MouseArea { - id: helpTabMouseArea; - anchors.fill: parent; - hoverEnabled: enabled; - onClicked: { - root.activeView = "help"; - tabButtonsContainer.resetTabButtonColors(); - } - onEntered: parent.color = hifi.colors.blueHighlight; - onExited: parent.color = root.activeView === "help" ? hifi.colors.blueAccent : hifi.colors.black; - } - } - - - function resetTabButtonColors() { - walletHomeButtonContainer.color = hifi.colors.black; - sendMoneyButtonContainer.color = hifi.colors.black; - helpButtonContainer.color = hifi.colors.black; - exchangeMoneyButtonContainer.color = hifi.colors.black; - if (root.activeView === "walletHome") { - walletHomeButtonContainer.color = hifi.colors.blueAccent; - } else if (root.activeView === "sendMoney") { - sendMoneyButtonContainer.color = hifi.colors.blueAccent; - } else if (root.activeView === "help") { - helpButtonContainer.color = hifi.colors.blueAccent; - } else if (root.activeView == "walletInventory") { - exchangeMoneyButtonContainer.color = hifi.colors.blueAccent; - } - } - } - // - // TAB BUTTONS END - // - - HifiControls.TabletWebView { - id: userInfoViewer; - z: 998; - anchors.fill: parent; - visible: false; - } - - Item { - id: keyboardContainer; - z: 999; - visible: keyboard.raised; - property bool punctuationMode: false; - anchors { - bottom: parent.bottom; - left: parent.left; - right: parent.right; - } - - HifiControlsUit.Keyboard { - id: keyboard; - raised: HMD.mounted && root.keyboardRaised; - numeric: parent.punctuationMode; - password: root.isPassword; - anchors { - bottom: parent.bottom; - left: parent.left; - right: parent.right; - } - } - } - - // - // FUNCTION DEFINITIONS START - // - // - // Function Name: fromScript() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the JavaScript. - // Messages are in format "{method, params}", like json-rpc. - // - // Description: - // Called when a message is received from a script. - // - function fromScript(message) { - switch (message.method) { - case 'updateWalletReferrer': - walletSetup.referrer = message.referrer; - walletChoice.referrer = message.referrer; - break; - case 'inspectionCertificate_resetCert': - // NOP - break; - case 'updateConnections': - sendMoney.updateConnections(message.connections); - walletInventory.fromScript(message); - break; - case 'selectRecipient': - case 'updateSelectedRecipientUsername': - sendMoney.fromScript(message); - walletInventory.fromScript(message); - break; - case 'http.response': - http.handleHttpResponse(message); - // Duplicate handler is required because we don't track referrer for `http` - walletInventory.fromScript(message); - break; - case 'palIsStale': - case 'avatarDisconnected': - // Because we don't have "channels" for sending messages to a specific QML object, the messages are broadcast to all QML Items. If an Item of yours happens to be visible when some script sends a message with a method you don't expect, you'll get "Unrecognized message..." logs. - break; - case 'inspectionCertificate_setCertificateId': - inspectionCertificate.fromScript(message); - break; - case 'updatePurchases': - case 'purchases_showMyItems': - case 'updateWearables': - walletInventory.fromScript(message); - break; - case 'updateRecentActivityMessageLight': - walletHomeButtonContainer.messagesWaiting = message.messagesWaiting; - break; - case 'checkout_openRecentActivity': - if (root.activeView === "initialize") { - root.initialActiveViewAfterStatus5 = "walletHome"; - } else { - root.activeView = "walletHome"; - } - break; - default: - console.log('Wallet.qml: Unrecognized message from wallet.js'); - } - } - signal sendToScript(var message); - - // generateUUID() taken from: - // https://stackoverflow.com/a/8809472 - function generateUUID() { // Public Domain/MIT - var d = new Date().getTime(); - if (typeof performance !== 'undefined' && typeof performance.now === 'function'){ - d += performance.now(); //use high-precision timer if available - } - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = (d + Math.random() * 16) % 16 | 0; - d = Math.floor(d / 16); - return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); - }); - } - - function walletResetSetup() { - /* Bypass all this and do it automatically - root.activeView = "walletSetup"; - var timestamp = new Date(); - walletSetup.startingTimestamp = timestamp; - walletSetup.setupAttemptID = generateUUID(); - UserActivityLogger.commerceWalletSetupStarted(timestamp, walletSetup.setupAttemptID, walletSetup.setupFlowVersion, walletSetup.referrer ? walletSetup.referrer : "wallet app", - (AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : '')); - */ - - var randomNumber = Math.floor(Math.random() * 34) + 1; - var securityImagePath = "images/" + addLeadingZero(randomNumber) + ".jpg"; - Commerce.getWalletAuthenticatedStatus(); // before writing security image, ensures that salt/account password is set. - Commerce.chooseSecurityImage(securityImagePath); - Commerce.generateKeyPair(); - followReferrer({ referrer: walletSetup.referrer }); - } - - function addLeadingZero(n) { - return n < 10 ? '0' + n : '' + n; - } - - function followReferrer(msg) { - if (msg.referrer === '') { - root.activeView = "initialize"; - Commerce.getWalletStatus(); - } else if (msg.referrer === 'purchases') { - root.activeView = "walletInventory"; - tabButtonsContainer.resetTabButtonColors(); - } else if (msg.referrer === 'marketplace cta' || msg.referrer === 'mainPage') { - sendToScript({method: 'goToMarketplaceMainPage', itemId: msg.referrer}); - } else { - sendToScript({method: 'goToMarketplaceItemPage', itemId: msg.referrer}); - } - } - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml b/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml deleted file mode 100644 index e7163a3641c..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml +++ /dev/null @@ -1,306 +0,0 @@ -// -// WalletChoice.qml -// qml/hifi/commerce/wallet -// -// WalletChoice -// -// Created by Howard Stearns -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import "../common" as HifiCommerceCommon -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit - - -Item { - HifiConstants { id: hifi; } - - id: root; - property string activeView: "conflict"; - property var proceedFunction: nil; - property var copyFunction: nil; - property string referrer: ""; - - Image { - anchors.fill: parent; - source: "images/wallet-bg.jpg"; - } - - HifiCommerceCommon.CommerceLightbox { - id: lightboxPopup; - visible: false; - anchors.fill: parent; - } - - // This object is always used in a popup. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - // - // TITLE BAR START - // - Item { - id: titleBarContainer; - // Size - height: 50; - // Anchors - anchors.left: parent.left; - anchors.top: parent.top; - anchors.right: parent.right; - - // Wallet icon - HiFiGlyphs { - id: walletIcon; - text: hifi.glyphs.wallet; - // Size - size: parent.height * 0.8; - // Anchors - anchors.left: parent.left; - anchors.leftMargin: 8; - anchors.verticalCenter: parent.verticalCenter; - // Style - color: hifi.colors.blueHighlight; - } - - // Title Bar text - RalewayRegular { - id: titleBarText; - text: "Wallet Setup"; - // Text size - size: hifi.fontSizes.overlayTitle; - // Anchors - anchors.top: parent.top; - anchors.left: walletIcon.right; - anchors.leftMargin: 8; - anchors.bottom: parent.bottom; - width: paintedWidth; - // Style - color: hifi.colors.white; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - } - // - // TITLE BAR END - // - - // - // MAIN PAGE START - // - Item { - id: preexistingContainer; - // Anchors - anchors.top: titleBarContainer.bottom; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - - HiFiGlyphs { - id: bigKeyIcon; - text: hifi.glyphs.walletKey; - // Size - size: 180; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 40; - anchors.horizontalCenter: parent.horizontalCenter; - // Style - color: hifi.colors.white; - } - - RalewayRegular { - id: text01; - text: root.activeView === "preexisting" ? - "Where are your private keys?" : - "Hmm, your keys are different" - // Text size - size: 26; - // Anchors - anchors.top: bigKeyIcon.bottom; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: paintedHeight; - width: paintedWidth; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - RalewayRegular { - id: text02; - text: root.activeView === "preexisting" ? - "Our records indicate that you created a wallet, but the private keys are not in the folder where we checked." : - "Our records indicate that you created a wallet with different keys than the keys you're providing." - // Text size - size: 18; - // Anchors - anchors.top: text01.bottom; - anchors.topMargin: 40; - anchors.left: parent.left; - anchors.leftMargin: 65; - anchors.right: parent.right; - anchors.rightMargin: 65; - height: paintedHeight; - width: paintedWidth; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - // "Locate" button - HifiControlsUit.Button { - id: locateButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: text02.bottom; - anchors.topMargin: 40; - anchors.horizontalCenter: parent.horizontalCenter; - width: parent.width/2; - height: 50; - text: root.activeView === "preexisting" ? - "LOCATE MY KEYS" : - "LOCATE OTHER KEYS" - onClicked: { - walletChooser(); - } - } - - // "Create New" OR "Continue" button - HifiControlsUit.Button { - id: button02; - color: hifi.buttons.none; - colorScheme: hifi.colorSchemes.dark; - anchors.top: locateButton.bottom; - anchors.topMargin: 20; - anchors.horizontalCenter: parent.horizontalCenter; - width: parent.width/2; - height: 50; - text: root.activeView === "preexisting" ? - "CREATE NEW WALLET" : - "CONTINUE WITH THESE KEYS" - onClicked: { - lightboxPopup.titleText = "Are you sure?"; - lightboxPopup.bodyText = "Taking this step will abandon your old wallet and you will no " + - "longer be able to access your money and your past purchases.

" + - "This step should only be used if you cannot find your keys.

" + - "This step cannot be undone."; - lightboxPopup.button1color = hifi.buttons.red; - lightboxPopup.button1text = "YES, CREATE NEW WALLET"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - proceed(true); - } - lightboxPopup.button2text = "CANCEL"; - lightboxPopup.button2method = function() { - lightboxPopup.visible = false; - }; - lightboxPopup.buttonLayout = "topbottom"; - lightboxPopup.visible = true; - } - } - - // "What's This?" link - RalewayRegular { - id: whatsThisLink; - text: 'What\'s this?'; - // Anchors - anchors.bottom: parent.bottom; - anchors.bottomMargin: 48; - anchors.horizontalCenter: parent.horizontalCenter; - width: paintedWidth; - height: paintedHeight; - // Text size - size: 18; - // Style - color: hifi.colors.white; - - MouseArea { - anchors.fill: parent; - - onClicked: { - if (root.activeView === "preexisting") { - lightboxPopup.titleText = "Your wallet's private keys are not in the folder we expected"; - lightboxPopup.bodyText = "We see that you have created a wallet but the private keys " + - "for it seem to have been moved to a different folder.

" + - "To tell us where the keys are, click 'Locate My Keys'.

" + - "If you'd prefer to create a new wallet (not recommended - you will lose your money and past " + - "purchases), click 'Create New Wallet'."; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } else { - lightboxPopup.titleText = "You may have set up more than one wallet"; - lightboxPopup.bodyText = "We see that the private keys stored on your computer are different " + - "from the ones you used last time. This may mean that you set up more than one wallet. " + - "If you would like to use these keys, click 'Continue With These Keys'.

" + - "If you would prefer to use another wallet, click 'Locate Other Keys' to show us where " + - "you've stored the private keys for that wallet."; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } - } - } - } - } - // - // MAIN PAGE END - // - - // - // FUNCTION DEFINITIONS START - // - function onFileOpenChanged(filename) { - // disconnect the event, otherwise the requests will stack up - try { // Not all calls to onFileOpenChanged() connect an event. - Window.browseChanged.disconnect(onFileOpenChanged); - } catch (e) { - console.log('WalletChoice.qml ignoring', e); - } - if (filename) { - if (copyFunction && copyFunction(filename)) { - proceed(false); - } else { - console.log("WalletChoice.qml copyFunction", copyFunction, "failed."); - } - } // Else we're still at WalletChoice - } - function walletChooser() { - Window.browseChanged.connect(onFileOpenChanged); - Window.browseAsync("Locate your .hifikey file", "", "*.hifikey"); - } - function proceed(isReset) { - if (!proceedFunction) { - console.log("Provide a function of no arguments to WalletChoice.qml."); - } else { - proceedFunction(isReset); - } - } - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml deleted file mode 100644 index 06d07a28c9e..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ /dev/null @@ -1,454 +0,0 @@ -// -// WalletHome.qml -// qml/hifi/commerce/wallet -// -// WalletHome -// -// Created by Zach Fox on 2017-08-18 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import QtQuick.Controls 2.2 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. - -Item { - HifiConstants { id: hifi; } - - id: root; - - property bool has3DHTML: PlatformInfo.has3DHTML(); - - onVisibleChanged: { - if (visible) { - Commerce.balance(); - transactionHistoryModel.getFirstPage(); - } else { - refreshTimer.stop(); - } - } - - Connections { - target: Commerce; - - onBalanceResult : { - balanceText.text = result.data.balance; - } - - onHistoryResult : { - transactionHistoryModel.handlePage(null, result); - } - } - - Connections { - target: GlobalServices - onMyUsernameChanged: { - transactionHistoryModel.resetModel(); - usernameText.text = Account.username; - } - } - - // Username Text - RalewayRegular { - id: usernameText; - text: Account.username; - // Text size - size: 24; - // Style - color: hifi.colors.white; - elide: Text.ElideRight; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: parent.width/2 - anchors.leftMargin; - height: 80; - } - - // HFC Balance Container - Item { - id: hfcBalanceContainer; - // Anchors - anchors.top: parent.top; - anchors.right: parent.right; - anchors.leftMargin: 20; - width: parent.width/2; - height: 80; - - // "HFC" balance label - HiFiGlyphs { - id: balanceLabel; - text: hifi.glyphs.hfc; - // Size - size: 40; - // Anchors - anchors.left: parent.left; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - // Style - color: hifi.colors.white; - } - - // Balance Text - FiraSansRegular { - id: balanceText; - text: "--"; - // Text size - size: 28; - // Anchors - anchors.top: balanceLabel.top; - anchors.bottom: balanceLabel.bottom; - anchors.left: balanceLabel.right; - anchors.leftMargin: 10; - anchors.right: parent.right; - anchors.rightMargin: 4; - // Style - color: hifi.colors.white; - // Alignment - verticalAlignment: Text.AlignVCenter; - } - - // "balance" text below field - RalewayRegular { - text: "BALANCE (HFC)"; - // Text size - size: 14; - // Anchors - anchors.top: balanceLabel.top; - anchors.topMargin: balanceText.paintedHeight + 20; - anchors.bottom: balanceLabel.bottom; - anchors.left: balanceText.left; - anchors.right: balanceText.right; - height: paintedHeight; - // Style - color: hifi.colors.white; - } - } - - Timer { - id: refreshTimer; - interval: 6000; - onTriggered: { - if (transactionHistory.atYBeginning) { - console.log("Refreshing 1st Page of Recent Activity..."); - Commerce.balance(); - transactionHistoryModel.getFirstPage("delayedClear"); - } - } - } - - // Recent Activity - Rectangle { - id: recentActivityContainer; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - height: 440; - - - LinearGradient { - anchors.fill: parent; - start: Qt.point(0, 0); - end: Qt.point(0, height); - gradient: Gradient { - GradientStop { position: 0.0; color: hifi.colors.white } - GradientStop { position: 1.0; color: hifi.colors.faintGray } - } - } - - RalewaySemiBold { - id: recentActivityText; - text: "Recent Activity"; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 26; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: paintedWidth; - height: 30; - // Text size - size: 22; - // Style - color: hifi.colors.baseGrayHighlight; - } - - HifiModels.PSFListModel { - id: transactionHistoryModel; - property int lastPendingCount: 0; - listModelName: "transaction history"; // For debugging. Alternatively, we could specify endpoint for that purpose, even though it's not used directly. - listView: transactionHistory; - itemsPerPage: 6; - getPage: function () { - console.debug('getPage', transactionHistoryModel.listModelName, transactionHistoryModel.currentPageToRetrieve); - Commerce.history(transactionHistoryModel.currentPageToRetrieve, transactionHistoryModel.itemsPerPage); - } - processPage: function (data) { - console.debug('processPage', transactionHistoryModel.listModelName, JSON.stringify(data)); - var result, pending; // Set up or get the accumulator for pending. - if (transactionHistoryModel.currentPageToRetrieve === 1) { - // The initial data elements inside the ListModel MUST contain all keys - // that will be used in future data. - pending = { - transaction_type: "pendingCount", - count: 0, - created_at: 0, - hfc_text: "", - id: "", - message: "", - place_name: "", - received_certs: 0, - received_money: 0, - recipient_name: "", - sender_name: "", - sent_certs: 0, - sent_money: 0, - status: "", - transaction_text: "" - }; - result = [pending]; - } else { - pending = transactionHistoryModel.get(0); - result = []; - } - - // Either add to pending, or to result. - // Note that you only see a page of pending stuff until you scroll... - data.history.forEach(function (item) { - if (item.status === 'pending') { - pending.count++; - } else { - result = result.concat(item); - } - }); - - if (lastPendingCount === 0) { - lastPendingCount = pending.count; - } else { - if (lastPendingCount !== pending.count) { - transactionHistoryModel.getNextPageIfNotEnoughVerticalResults(); - } - lastPendingCount = pending.count; - } - - // Only auto-refresh if the user hasn't scrolled - // and there is more data to grab - if (transactionHistory.atYBeginning && data.history.length) { - refreshTimer.start(); - } - return result; - } - } - Item { - anchors.top: recentActivityText.bottom; - anchors.topMargin: 26; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - - ListView { - id: transactionHistory; - ScrollBar.vertical: ScrollBar { - policy: transactionHistory.contentHeight > parent.parent.height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded; - parent: transactionHistory.parent; - anchors.top: transactionHistory.top; - anchors.left: transactionHistory.right; - anchors.leftMargin: 4; - anchors.bottom: transactionHistory.bottom; - width: 20; - } - anchors.centerIn: parent; - width: parent.width - 12; - height: parent.height; - visible: transactionHistoryModel.count !== 0; - clip: true; - model: transactionHistoryModel; - delegate: Item { - width: parent.width; - height: (model.transaction_type === "pendingCount" && model.count !== 0) ? 40 : - (transactionContainer.visible ? transactionText.height + 30 : 0); - - Item { - id: pendingCountContainer; - visible: model.transaction_type === "pendingCount" && model.count !== 0; - anchors.top: parent.top; - anchors.left: parent.left; - width: parent.width; - height: visible ? parent.height : 0; - - AnonymousProRegular { - id: pendingCountText; - anchors.fill: parent; - text: model.count + ' Transaction' + (model.count > 1 ? 's' : '') + ' Pending'; - size: 18; - color: hifi.colors.blueAccent; - verticalAlignment: Text.AlignVCenter; - horizontalAlignment: Text.AlignHCenter; - } - } - - Item { - id: transactionContainer; - visible: model.transaction_type !== "pendingCount" && - (model.status === "confirmed" || model.status === "invalidated"); - anchors.top: parent.top; - anchors.left: parent.left; - width: parent.width; - height: visible ? parent.height : 0; - - AnonymousProRegular { - id: hfcText; - text: model.hfc_text || ''; - // Style - size: 18; - anchors.left: parent.left; - anchors.top: parent.top; - anchors.topMargin: 15; - width: 118; - height: paintedHeight; - wrapMode: Text.Wrap; - // Alignment - horizontalAlignment: Text.AlignRight; - } - - AnonymousProRegular { - id: transactionText; - text: model.transaction_text ? (model.status === "invalidated" ? ("INVALIDATED: " + model.transaction_text) : model.transaction_text) : ""; - size: 18; - anchors.top: parent.top; - anchors.topMargin: 15; - anchors.left: hfcText.right; - anchors.leftMargin: 20; - anchors.right: parent.right; - height: paintedHeight; - color: model.status === "invalidated" ? hifi.colors.redAccent : hifi.colors.baseGrayHighlight; - linkColor: hifi.colors.blueAccent; - wrapMode: Text.Wrap; - font.strikeout: model.status === "invalidated"; - - onLinkActivated: { - if (link.indexOf("users/") !== -1) { - if (has3DHTML) { - sendSignalToWallet({method: 'transactionHistory_usernameLinkClicked', usernameLink: link}); - } - } else { - sendSignalToWallet({method: 'transactionHistory_linkClicked', itemId: model.marketplace_item}); - } - } - } - - HifiControlsUit.Separator { - colorScheme: 1; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - } - } - } - } - - Item { - // On empty history. We don't want to flash and then replace, so don't show until we know we should. - // The history is empty when it contains 1 item (the pending item count) AND there are no pending items. - visible: transactionHistoryModel.count === 1 && - transactionHistoryModel.retrievedAtLeastOnePage && - transactionHistoryModel.get(0).count === 0; - anchors.centerIn: parent; - width: parent.width - 12; - height: parent.height; - - HifiControlsUit.Separator { - colorScheme: 1; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: parent.top; - } - - RalewayRegular { - id: noActivityText; - text: "Congrats! Your wallet is all set!

" + - "Where's my HFC?
" + - "High Fidelity commerce is in open beta right now. Want more HFC? Get it by meeting with a banker at " + - "BankOfHighFidelity!" - // Text size - size: 22; - // Style - color: hifi.colors.blueAccent; - anchors.top: parent.top; - anchors.topMargin: 36; - anchors.left: parent.left; - anchors.leftMargin: 12; - anchors.right: parent.right; - anchors.rightMargin: 12; - height: paintedHeight; - wrapMode: Text.WordWrap; - horizontalAlignment: Text.AlignHCenter; - - onLinkActivated: { - sendSignalToWallet({ method: "transactionHistory_goToBank" }); - } - } - - HifiControlsUit.Button { - id: bankButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: noActivityText.bottom; - anchors.topMargin: 30; - anchors.horizontalCenter: parent.horizontalCenter; - width: parent.width/2; - height: 50; - text: "VISIT BANK OF HIGH FIDELITY"; - onClicked: { - sendSignalToWallet({ method: "transactionHistory_goToBank" }); - } - } - } - } - } - - // - // FUNCTION DEFINITIONS START - // - - function getFormattedDate(timestamp) { - function addLeadingZero(n) { - return n < 10 ? '0' + n : '' + n; - } - - var a = new Date(timestamp); - var year = a.getFullYear(); - var month = addLeadingZero(a.getMonth() + 1); - var day = addLeadingZero(a.getDate()); - var hour = a.getHours(); - var drawnHour = hour; - if (hour === 0) { - drawnHour = 12; - } else if (hour > 12) { - drawnHour -= 12; - } - drawnHour = addLeadingZero(drawnHour); - - var amOrPm = "AM"; - if (hour >= 12) { - amOrPm = "PM"; - } - - var min = addLeadingZero(a.getMinutes()); - var sec = addLeadingZero(a.getSeconds()); - return year + '-' + month + '-' + day + '
' + drawnHour + ':' + min + amOrPm; - } - - signal sendSignalToWallet(var msg); - - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml deleted file mode 100644 index 1cecebc41bc..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml +++ /dev/null @@ -1,653 +0,0 @@ -// -// modalContainer.qml -// qml/hifi/commerce/wallet -// -// modalContainer -// -// Created by Zach Fox on 2017-08-17 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit -import "../../../controls" as HifiControls -import "../common" as HifiCommerceCommon - -// references XXX from root context - -Item { - HifiConstants { id: hifi; } - - id: root; - property string activeView: "step_1"; - property string lastPage; - property bool hasShownSecurityImageTip: false; - property string referrer: ''; - property string keyFilePath; - property date startingTimestamp; - property string setupAttemptID; - readonly property int setupFlowVersion: 1; - readonly property var setupStepNames: [ "Setup Prompt", "Security Image Selection", "Passphrase Selection", "Private Keys Ready" ]; - - Image { - anchors.fill: parent; - source: "images/wallet-bg.jpg"; - } - - Connections { - target: Commerce; - - onSecurityImageResult: { - if (!exists && root.lastPage === "step_2") { - // ERROR! Invalid security image. - root.activeView = "step_2"; - } else if (exists) { - titleBarSecurityImage.source = ""; - titleBarSecurityImage.source = "image://security/securityImage"; - } - } - - onWalletAuthenticatedStatusResult: { - if (isAuthenticated) { - root.activeView = "step_4"; - } - } - - onKeyFilePathIfExistsResult: { - root.keyFilePath = path; - } - } - - HifiCommerceCommon.CommerceLightbox { - id: lightboxPopup; - visible: false; - anchors.fill: parent; - } - - onActiveViewChanged: { - var timestamp = new Date(); - var currentStepNumber = root.activeView.substring(5); - UserActivityLogger.commerceWalletSetupProgress(timestamp, root.setupAttemptID, - Math.round((timestamp - root.startingTimestamp)/1000), currentStepNumber, root.setupStepNames[currentStepNumber - 1]); - - if (root.activeView === "step_3") { - sendSignalToWallet({method: 'disableHmdPreview'}); - } else { - sendSignalToWallet({method: 'maybeEnableHmdPreview'}); - } - } - - // - // TITLE BAR START - // - Item { - id: titleBarContainer; - // Size - height: 50; - // Anchors - anchors.left: parent.left; - anchors.top: parent.top; - anchors.right: parent.right; - - // Wallet icon - HiFiGlyphs { - id: walletIcon; - text: hifi.glyphs.wallet; - // Size - size: parent.height * 0.8; - // Anchors - anchors.left: parent.left; - anchors.leftMargin: 8; - anchors.verticalCenter: parent.verticalCenter; - // Style - color: hifi.colors.blueHighlight; - } - - // Title Bar text - RalewayRegular { - id: titleBarText; - text: "Wallet Setup" + (securityImageTip.visible ? "" : " - Step " + root.activeView.split("_")[1] + " of 4"); - // Text size - size: hifi.fontSizes.overlayTitle; - // Anchors - anchors.top: parent.top; - anchors.left: walletIcon.right; - anchors.leftMargin: 8; - anchors.bottom: parent.bottom; - width: paintedWidth; - // Style - color: hifi.colors.white; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - - Image { - id: titleBarSecurityImage; - source: ""; - visible: !securityImageTip.visible && titleBarSecurityImage.source !== "" && root.activeView !== "step_1" && root.activeView !== "step_2"; - anchors.right: parent.right; - anchors.rightMargin: 6; - anchors.top: parent.top; - anchors.topMargin: 6; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 6; - width: height; - mipmap: true; - cache: false; - - MouseArea { - enabled: titleBarSecurityImage.visible; - anchors.fill: parent; - onClicked: { - lightboxPopup.titleText = "Your Security Pic"; - lightboxPopup.bodyImageSource = titleBarSecurityImage.source; - lightboxPopup.bodyText = lightboxPopup.securityPicBodyText; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = function() { - lightboxPopup.visible = false; - } - lightboxPopup.visible = true; - } - } - } - } - // - // TITLE BAR END - // - - // - // FIRST PAGE START - // - Item { - id: firstPageContainer; - visible: root.activeView === "step_1"; - // Anchors - anchors.top: titleBarContainer.bottom; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - - HiFiGlyphs { - id: bigWalletIcon; - text: hifi.glyphs.wallet; - // Size - size: 180; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 40; - anchors.horizontalCenter: parent.horizontalCenter; - // Style - color: hifi.colors.white; - } - - RalewayRegular { - id: firstPage_text01; - text: "Let's set up your wallet!"; - // Text size - size: 26; - // Anchors - anchors.top: bigWalletIcon.bottom; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: paintedHeight; - width: paintedWidth; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - RalewayRegular { - id: firstPage_text02; - text: "Set up your wallet to claim your free High Fidelity Coin (HFC) and get items from the Marketplace.

" + - "No credit card is required."; - // Text size - size: 18; - // Anchors - anchors.top: firstPage_text01.bottom; - anchors.topMargin: 40; - anchors.left: parent.left; - anchors.leftMargin: 65; - anchors.right: parent.right; - anchors.rightMargin: 65; - height: paintedHeight; - width: paintedWidth; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - // "Set Up" button - HifiControlsUit.Button { - id: firstPage_setUpButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: firstPage_text02.bottom; - anchors.topMargin: 40; - anchors.horizontalCenter: parent.horizontalCenter; - width: parent.width/2; - height: 50; - text: "Set Up Wallet"; - onClicked: { - root.activeView = "step_2"; - } - } - - // "Cancel" button - HifiControlsUit.Button { - color: hifi.buttons.none; - colorScheme: hifi.colorSchemes.dark; - anchors.top: firstPage_setUpButton.bottom; - anchors.topMargin: 20; - anchors.horizontalCenter: parent.horizontalCenter; - width: parent.width/2; - height: 50; - text: "Cancel"; - onClicked: { - sendSignalToWallet({method: 'walletSetup_cancelClicked', referrer: root.referrer }); - } - } - } - // - // FIRST PAGE END - // - - // - // SECURE PASSPHRASE SELECTION START - // - - Item { - id: securityImageTip; - visible: !root.hasShownSecurityImageTip && root.activeView === "step_3"; - z: 999; - anchors.fill: root; - - // This object is always used in a popup. - // This MouseArea is used to prevent a user from being - // able to click on a button/mouseArea underneath the popup. - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - hoverEnabled: true; - } - - Image { - source: "images/wallet-tip-bg.png"; - anchors.fill: parent; - } - - RalewayRegular { - id: tipText; - text: 'Tip:

When you see your security picture like this, you know ' + - "the page asking for your passphrase is legitimate."; - // Text size - size: 18; - // Anchors - anchors.bottom: parent.bottom; - anchors.bottomMargin: 230; - anchors.left: parent.left; - anchors.leftMargin: 60; - height: paintedHeight; - width: 210; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - } - - // "Got It" button - HifiControlsUit.Button { - id: tipGotItButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: tipText.bottom; - anchors.topMargin: 20; - anchors.horizontalCenter: tipText.horizontalCenter; - height: 50; - width: 150; - text: "Got It"; - onClicked: { - root.hasShownSecurityImageTip = true; - passphraseSelection.focusFirstTextField(); - } - } - } - Item { - id: choosePassphraseContainer; - visible: root.activeView === "step_3"; - // Anchors - anchors.top: titleBarContainer.bottom; - anchors.topMargin: 30; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - - onVisibleChanged: { - if (visible) { - Commerce.getWalletAuthenticatedStatus(); - } - } - - // Text below title bar - RalewayRegular { - id: passphraseTitleHelper; - text: "Set Your Passphrase:"; - // Text size - size: 24; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: 50; - // Style - color: hifi.colors.white; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - - PassphraseSelection { - id: passphraseSelection; - shouldImmediatelyFocus: root.hasShownSecurityImageTip; - isShowingTip: securityImageTip.visible; - anchors.top: passphraseTitleHelper.bottom; - anchors.topMargin: 30; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: passphraseNavBar.top; - - Connections { - onSendMessageToLightbox: { - if (msg.method === 'statusResult') { - } else { - sendSignalToWallet(msg); - } - } - } - } - - // Navigation Bar - Item { - id: passphraseNavBar; - visible: !securityImageTip.visible; - // Size - width: parent.width; - height: 50; - // Anchors: - anchors.left: parent.left; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 50; - - // "Back" button - HifiControlsUit.Button { - color: hifi.buttons.noneBorderlessWhite; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: 200; - text: "Back" - onClicked: { - root.lastPage = "step_3"; - root.activeView = "step_2"; - } - } - - // "Next" button - HifiControlsUit.Button { - id: passphrasePageNextButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.right: parent.right; - anchors.rightMargin: 20; - width: 200; - text: "Next"; - onClicked: { - if (passphraseSelection.validateAndSubmitPassphrase()) { - root.lastPage = "step_3"; - Commerce.generateKeyPair(); - root.activeView = "step_4"; - } - } - } - } - } - // - // SECURE PASSPHRASE SELECTION END - // - - // - // PRIVATE KEYS READY START - // - Item { - id: privateKeysReadyContainer; - visible: root.activeView === "step_4"; - // Anchors - anchors.top: titleBarContainer.bottom; - anchors.topMargin: 30; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - - // Text below title bar - RalewayRegular { - id: keysReadyTitleHelper; - text: "Back Up Your Private Keys"; - // Text size - size: 24; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: 50; - // Style - color: hifi.colors.white; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - - RalewayRegular { - id: explanationText; - text: "To protect your privacy, you control your private keys. High Fidelity has no access to your private keys and cannot " + - "recover them for you.

If they are lost, you will not be able to access your money or purchases."; - // Text size - size: 20; - // Anchors - anchors.top: keysReadyTitleHelper.bottom; - anchors.topMargin: 24; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: paintedHeight; - // Style - color: hifi.colors.white; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - - Rectangle { - id: pathAndInstructionsContainer; - anchors.top: explanationText.bottom; - anchors.topMargin: 24; - anchors.left: parent.left; - anchors.right: parent.right; - height: 240; - color: Qt.rgba(0, 0, 0, 0.5); - - Item { - id: instructions01Container; - anchors.fill: parent; - - RalewaySemiBold { - id: keyFilePathHelperText; - text: "Private Key File Location:"; - size: 18; - anchors.top: parent.top; - anchors.topMargin: 40; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.right: parent.right; - anchors.rightMargin: 30; - height: paintedHeight; - color: hifi.colors.white; - } - - HifiControlsUit.Button { - id: clipboardButton; - color: hifi.buttons.black; - colorScheme: hifi.colorSchemes.dark; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.top: keyFilePathHelperText.bottom; - anchors.topMargin: 8; - height: 24; - width: height; - HiFiGlyphs { - text: hifi.glyphs.folderLg; - // Size - size: parent.height; - // Anchors - anchors.fill: parent; - // Style - horizontalAlignment: Text.AlignHCenter; - color: enabled ? hifi.colors.blueHighlight : hifi.colors.faintGray; - } - - onClicked: { - Qt.openUrlExternally("file:///" + keyFilePath.substring(0, keyFilePath.lastIndexOf('/'))); - } - } - RalewayRegular { - id: keyFilePathText; - text: root.keyFilePath; - size: 18; - anchors.top: clipboardButton.top; - anchors.left: clipboardButton.right; - anchors.leftMargin: 8; - anchors.right: parent.right; - anchors.rightMargin: 30; - height: paintedHeight; - wrapMode: Text.WordWrap; - color: hifi.colors.blueHighlight; - - onVisibleChanged: { - if (visible) { - Commerce.getKeyFilePathIfExists(); - } - } - } - - // "Open Instructions" button - HifiControlsUit.Button { - id: openInstructionsButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: keyFilePathText.bottom; - anchors.topMargin: 30; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.right: parent.right; - anchors.rightMargin: 30; - height: 40; - text: "Open Backup Instructions for Later"; - onClicked: { - instructions01Container.visible = false; - instructions02Container.visible = true; - keysReadyPageFinishButton.visible = true; - var keyPath = "file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/')); - Qt.openUrlExternally(keyPath + "/backup_instructions.html"); - Qt.openUrlExternally(keyPath); - } - } - } - - Item { - id: instructions02Container; - anchors.fill: parent; - visible: false; - - RalewayRegular { - text: "All set!
Instructions for backing up your keys have been opened on your desktop. " + - "Be sure to look them over after your session."; - size: 22; - anchors.fill: parent; - anchors.leftMargin: 30; - anchors.rightMargin: 30; - wrapMode: Text.WordWrap; - color: hifi.colors.white; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - } - } - - // Navigation Bar - Item { - // Size - width: parent.width; - height: 50; - // Anchors: - anchors.left: parent.left; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 50; - // "Finish" button - HifiControlsUit.Button { - id: keysReadyPageFinishButton; - visible: false; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.right: parent.right; - anchors.rightMargin: 20; - width: 200; - text: "Finish"; - onClicked: { - root.visible = false; - root.hasShownSecurityImageTip = false; - sendSignalToWallet({method: 'walletSetup_finished', referrer: root.referrer ? root.referrer : ""}); - - var timestamp = new Date(); - UserActivityLogger.commerceWalletSetupFinished(timestamp, setupAttemptID, Math.round((timestamp - root.startingTimestamp)/1000)); - } - } - } - } - // - // PRIVATE KEYS READY END - // - - // - // FUNCTION DEFINITIONS START - // - signal sendSignalToWallet(var msg); - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/commerce/wallet/images/items-tab-a.svg b/interface/resources/qml/hifi/commerce/wallet/images/items-tab-a.svg deleted file mode 100644 index 7474f4ed571..00000000000 --- a/interface/resources/qml/hifi/commerce/wallet/images/items-tab-a.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/interface/resources/qml/hifi/commerce/wallet/images/lowerKeyboard.png b/interface/resources/qml/hifi/commerce/wallet/images/lowerKeyboard.png deleted file mode 100644 index c14409d45c8..00000000000 Binary files a/interface/resources/qml/hifi/commerce/wallet/images/lowerKeyboard.png and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/wallet-bg.jpg b/interface/resources/qml/hifi/commerce/wallet/images/wallet-bg.jpg deleted file mode 100644 index 46f22b4bc77..00000000000 Binary files a/interface/resources/qml/hifi/commerce/wallet/images/wallet-bg.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/wallet-tip-bg.png b/interface/resources/qml/hifi/commerce/wallet/images/wallet-tip-bg.png deleted file mode 100644 index 34f0f7d76da..00000000000 Binary files a/interface/resources/qml/hifi/commerce/wallet/images/wallet-tip-bg.png and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/Security.qml b/interface/resources/qml/hifi/dialogs/security/Security.qml index b1f62633e72..4941330d0cd 100644 --- a/interface/resources/qml/hifi/dialogs/security/Security.qml +++ b/interface/resources/qml/hifi/dialogs/security/Security.qml @@ -17,7 +17,6 @@ import QtGraphicalEffects 1.0 import stylesUit 1.0 as HifiStylesUit import controlsUit 1.0 as HifiControlsUit import "qrc:////qml//controls" as HifiControls -import "qrc:////qml//hifi//commerce//common" as HifiCommerceCommon Rectangle { HifiStylesUit.HifiConstants { id: hifi; } @@ -26,7 +25,6 @@ Rectangle { color: hifi.colors.baseGray; property string title: "Security Settings"; - property bool walletSetUp; QtObject { id: margins @@ -39,53 +37,6 @@ Rectangle { property real sizeVR: root.width / 13.5 } - Connections { - target: Commerce; - - onWalletStatusResult: { - if (walletStatus === 5) { - Commerce.getSecurityImage(); - root.walletSetUp = true; - } else { - root.walletSetUp = false; - } - } - - onSecurityImageResult: { - if (exists) { - currentSecurityPicture.source = ""; - currentSecurityPicture.source = "image://security/securityImage"; - } - } - } - - Component.onCompleted: { - Commerce.getWalletStatus(); - } - - HifiCommerceCommon.CommerceLightbox { - z: 996; - id: lightboxPopup; - visible: false; - anchors.fill: parent; - } - - SecurityImageChange { - id: securityImageChange; - visible: false; - z: 997; - anchors.top: usernameText.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - - Connections { - onSendSignalToParent: { - securityImageChange.visible = false; - } - } - } - // Username Text HifiStylesUit.RalewayRegular { id: usernameText; @@ -325,107 +276,5 @@ Rectangle { } } } - - - Item { - id: walletContainer; - anchors.top: kpiContainer.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - height: childrenRect.height; - - Rectangle { - id: walletHeaderContainer; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - height: 55; - color: hifi.colors.baseGrayHighlight; - - HifiStylesUit.RalewaySemiBold { - text: "Secure Transactions"; - anchors.fill: parent; - anchors.leftMargin: 20; - color: hifi.colors.white; - size: 18; - } - } - - Item { - id: walletSecurityPictureContainer; - visible: root.walletSetUp; - anchors.top: walletHeaderContainer.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - height: 80; - - Image { - id: currentSecurityPicture; - source: ""; - visible: true; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.verticalCenter: parent.verticalCenter; - height: 40; - width: height; - mipmap: true; - cache: false; - } - - HifiStylesUit.RalewaySemiBold { - id: securityPictureText; - text: "Security Picture"; - // Anchors - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: currentSecurityPicture.right; - anchors.leftMargin: 12; - width: paintedWidth; - // Text size - size: 18; - // Style - color: hifi.colors.white; - } - - // "Change Security Pic" button - HifiControlsUit.Button { - id: changeSecurityImageButton; - color: hifi.buttons.white; - colorScheme: hifi.colorSchemes.dark; - anchors.left: securityPictureText.right; - anchors.leftMargin: 12; - anchors.verticalCenter: parent.verticalCenter; - width: 140; - height: 40; - text: "Change"; - onClicked: { - securityImageChange.visible = true; - securityImageChange.initModel(); - } - } - } - - Item { - id: walletNotSetUpContainer; - visible: !root.walletSetUp; - anchors.top: walletHeaderContainer.bottom; - anchors.left: parent.left; - anchors.right: parent.right; - height: 60; - - HifiStylesUit.RalewayRegular { - text: "Your wallet is not set up.\n" + - "Open the INVENTORY app to get started."; - // Anchors - anchors.fill: parent; - // Text size - size: 18; - // Style - color: hifi.colors.white; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - } - } } } diff --git a/interface/resources/qml/hifi/dialogs/security/SecurityImageChange.qml b/interface/resources/qml/hifi/dialogs/security/SecurityImageChange.qml deleted file mode 100644 index e563bd13ca8..00000000000 --- a/interface/resources/qml/hifi/dialogs/security/SecurityImageChange.qml +++ /dev/null @@ -1,200 +0,0 @@ -// -// SecurityImageChange.qml -// qml\hifi\dialogs\security -// -// Security -// -// Created by Zach Fox on 2018-10-31 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import stylesUit 1.0 as HifiStylesUit -import controlsUit 1.0 as HifiControlsUit -import "qrc:////qml//controls" as HifiControls - -// references XXX from root context - -Rectangle { - HifiStylesUit.HifiConstants { id: hifi; } - - id: root; - color: hifi.colors.baseGray; - property bool justSubmitted: false; - - Connections { - target: Commerce; - - onSecurityImageResult: { - securityImageChangePageSecurityImage.source = ""; - securityImageChangePageSecurityImage.source = "image://security/securityImage"; - if (exists) { // Success submitting new security image - if (root.justSubmitted) { - sendSignalToParent({method: "walletSecurity_changeSecurityImageSuccess"}); - root.justSubmitted = false; - } - } else if (root.justSubmitted) { - // Error submitting new security image. - root.justSubmitted = false; - } - } - } - - // Security Image - Item { - // Anchors - anchors.top: parent.top; - anchors.right: parent.right; - anchors.rightMargin: 25; - width: 130; - height: 150; - Image { - id: securityImageChangePageSecurityImage; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: iconAndTextContainer.top; - fillMode: Image.PreserveAspectFit; - mipmap: true; - source: "image://security/securityImage"; - cache: false; - onVisibleChanged: { - Commerce.getSecurityImage(); - } - } - Item { - id: iconAndTextContainer; - anchors.left: securityImageChangePageSecurityImage.left; - anchors.right: securityImageChangePageSecurityImage.right; - anchors.bottom: parent.bottom; - height: 22; - // Lock icon - HifiStylesUit.HiFiGlyphs { - id: lockIcon; - text: hifi.glyphs.lock; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.leftMargin: 10; - size: 20; - width: height; - verticalAlignment: Text.AlignBottom; - color: hifi.colors.white; - } - // "Security image" text below image - HifiStylesUit.RalewayRegular { - id: securityImageText; - text: "SECURITY PIC"; - // Text size - size: 12; - // Anchors - anchors.bottom: parent.bottom; - anchors.right: parent.right; - anchors.rightMargin: lockIcon.anchors.leftMargin; - width: paintedWidth; - height: 22; - // Style - color: hifi.colors.white; - // Alignment - horizontalAlignment: Text.AlignRight; - verticalAlignment: Text.AlignBottom; - } - } - } - - // - // SECURITY IMAGE SELECTION START - // - Item { - // Anchors - anchors.top: parent.top; - anchors.topMargin: 135; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - - // "Change Security Image" text - HifiStylesUit.RalewaySemiBold { - id: securityImageTitle; - text: "Change Security Image:"; - // Text size - size: 18; - anchors.top: parent.top; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - height: 30; - // Style - color: hifi.colors.blueHighlight; - } - - SecurityImageSelection { - id: securityImageSelection; - // Anchors - anchors.top: securityImageTitle.bottom; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: 300; - } - - // Navigation Bar - Item { - id: securityImageNavBar; - // Size - width: parent.width; - height: 40; - // Anchors: - anchors.left: parent.left; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 30; - - // "Cancel" button - HifiControlsUit.Button { - color: hifi.buttons.noneBorderlessWhite; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.leftMargin: 20; - width: 150; - text: "Cancel" - onClicked: { - sendSignalToParent({method: "walletSecurity_changeSecurityImageCancelled"}); - } - } - - // "Submit" button - HifiControlsUit.Button { - id: securityImageSubmitButton; - text: root.justSubmitted ? "Submitting..." : "Submit"; - enabled: securityImageSelection.currentIndex !== -1 && !root.justSubmitted; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.right: parent.right; - anchors.rightMargin: 20; - width: 150; - onClicked: { - root.justSubmitted = true; - var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex()) - Commerce.chooseSecurityImage(securityImagePath); - } - } - } - } - // - // SECURITY IMAGE SELECTION END - // - - signal sendSignalToParent(var msg); - - function initModel() { - securityImageSelection.initModel(); - } -} diff --git a/interface/resources/qml/hifi/dialogs/security/SecurityImageModel.qml b/interface/resources/qml/hifi/dialogs/security/SecurityImageModel.qml deleted file mode 100644 index 946f979c1a9..00000000000 --- a/interface/resources/qml/hifi/dialogs/security/SecurityImageModel.qml +++ /dev/null @@ -1,45 +0,0 @@ -// -// SecurityImageModel.qml -// qml\hifi\dialogs\security -// -// Security -// -// Created by Zach Fox on 2018-10-31 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 - -ListModel { - id: root; - - function initModel() { - var array = []; - while (array.length < 6) { - // We currently have 34 security images to choose from - var randomNumber = Math.floor(Math.random() * 34) + 1; - if (array.indexOf(randomNumber) > -1) { - continue; - } - array[array.length] = randomNumber; - } - - var modelElement; - - for (var i = 0; i < 6; i++) { - modelElement = { "sourcePath":"images/" + addLeadingZero(array[i]) + ".jpg", "securityImageEnumValue": (i + 1) } - root.insert(i, modelElement); - } - } - - function addLeadingZero(n) { - return n < 10 ? '0' + n : '' + n; - } - - function getImagePathFromImageID(imageID) { - return (imageID ? root.get(imageID - 1).sourcePath : ""); - } -} diff --git a/interface/resources/qml/hifi/dialogs/security/SecurityImageSelection.qml b/interface/resources/qml/hifi/dialogs/security/SecurityImageSelection.qml deleted file mode 100644 index 3451cbcf509..00000000000 --- a/interface/resources/qml/hifi/dialogs/security/SecurityImageSelection.qml +++ /dev/null @@ -1,95 +0,0 @@ -// -// SecurityImageSelection.qml -// qml\hifi\dialogs\security -// -// Security -// -// Created by Zach Fox on 2018-10-31 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import Hifi 1.0 as Hifi -import QtQuick 2.5 -import stylesUit 1.0 as HifiStylesUit -import controlsUit 1.0 as HifiControlsUit -import "qrc:////qml//controls" as HifiControls - -// references XXX from root context - -Item { - HifiStylesUit.HifiConstants { id: hifi; } - - id: root; - property alias currentIndex: securityImageGrid.currentIndex; - - SecurityImageModel { - id: gridModel; - } - - GridView { - id: securityImageGrid; - interactive: false; - clip: true; - // Anchors - anchors.fill: parent; - currentIndex: -1; - cellWidth: width / 3; - cellHeight: height / 2; - model: gridModel; - delegate: Item { - width: securityImageGrid.cellWidth; - height: securityImageGrid.cellHeight; - Item { - anchors.fill: parent; - Image { - width: parent.width - 12; - height: parent.height - 12; - source: sourcePath; - anchors.horizontalCenter: parent.horizontalCenter; - anchors.verticalCenter: parent.verticalCenter; - fillMode: Image.PreserveAspectFit; - mipmap: true; - cache: false; - } - } - MouseArea { - anchors.fill: parent; - propagateComposedEvents: false; - onClicked: { - securityImageGrid.currentIndex = index; - } - } - } - highlight: Rectangle { - width: securityImageGrid.cellWidth; - height: securityImageGrid.cellHeight; - color: hifi.colors.blueHighlight; - } - } - - // - // FUNCTION DEFINITIONS START - // - function getImagePathFromImageID(imageID) { - return (imageID ? gridModel.getImagePathFromImageID(imageID) : ""); - } - - function getSelectedImageIndex() { - return gridModel.get(securityImageGrid.currentIndex).securityImageEnumValue; - } - - function initModel() { - gridModel.initModel(); - securityImageGrid.currentIndex = -1; - } - - function resetSelection() { - securityImageGrid.currentIndex = -1; - } - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/hifi/dialogs/security/images/01.jpg b/interface/resources/qml/hifi/dialogs/security/images/01.jpg deleted file mode 100644 index 199920a32d7..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/01.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/02.jpg b/interface/resources/qml/hifi/dialogs/security/images/02.jpg deleted file mode 100644 index 821be6c584d..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/02.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/03.jpg b/interface/resources/qml/hifi/dialogs/security/images/03.jpg deleted file mode 100644 index 53b6f811d8f..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/03.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/04.jpg b/interface/resources/qml/hifi/dialogs/security/images/04.jpg deleted file mode 100644 index 1acedf8b107..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/04.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/05.jpg b/interface/resources/qml/hifi/dialogs/security/images/05.jpg deleted file mode 100644 index da73727dea4..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/05.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/06.jpg b/interface/resources/qml/hifi/dialogs/security/images/06.jpg deleted file mode 100644 index bbd0399d3f4..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/06.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/07.jpg b/interface/resources/qml/hifi/dialogs/security/images/07.jpg deleted file mode 100644 index e5f86a4a800..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/07.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/08.jpg b/interface/resources/qml/hifi/dialogs/security/images/08.jpg deleted file mode 100644 index 9d49866c91f..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/08.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/09.jpg b/interface/resources/qml/hifi/dialogs/security/images/09.jpg deleted file mode 100644 index a1c31bce7dc..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/09.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/10.jpg b/interface/resources/qml/hifi/dialogs/security/images/10.jpg deleted file mode 100644 index 1f6fc1de274..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/10.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/11.jpg b/interface/resources/qml/hifi/dialogs/security/images/11.jpg deleted file mode 100644 index 37c3b937a5a..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/11.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/12.jpg b/interface/resources/qml/hifi/dialogs/security/images/12.jpg deleted file mode 100644 index 39f653630cc..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/12.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/13.jpg b/interface/resources/qml/hifi/dialogs/security/images/13.jpg deleted file mode 100644 index 3ae86be465c..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/13.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/14.jpg b/interface/resources/qml/hifi/dialogs/security/images/14.jpg deleted file mode 100644 index 8de661e58ee..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/14.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/15.jpg b/interface/resources/qml/hifi/dialogs/security/images/15.jpg deleted file mode 100644 index f0ac801b89f..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/15.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/16.jpg b/interface/resources/qml/hifi/dialogs/security/images/16.jpg deleted file mode 100644 index f7c32a696ba..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/16.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/17.jpg b/interface/resources/qml/hifi/dialogs/security/images/17.jpg deleted file mode 100644 index 75e811ee36a..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/17.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/18.jpg b/interface/resources/qml/hifi/dialogs/security/images/18.jpg deleted file mode 100644 index e4ca0b6f288..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/18.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/19.jpg b/interface/resources/qml/hifi/dialogs/security/images/19.jpg deleted file mode 100644 index 4c25f3dda24..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/19.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/20.jpg b/interface/resources/qml/hifi/dialogs/security/images/20.jpg deleted file mode 100644 index a5a4565a876..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/20.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/21.jpg b/interface/resources/qml/hifi/dialogs/security/images/21.jpg deleted file mode 100644 index 3747c9558e9..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/21.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/22.jpg b/interface/resources/qml/hifi/dialogs/security/images/22.jpg deleted file mode 100644 index 66003db9c78..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/22.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/23.jpg b/interface/resources/qml/hifi/dialogs/security/images/23.jpg deleted file mode 100644 index 72e02c6db0d..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/23.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/24.jpg b/interface/resources/qml/hifi/dialogs/security/images/24.jpg deleted file mode 100644 index e481a587a5a..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/24.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/25.jpg b/interface/resources/qml/hifi/dialogs/security/images/25.jpg deleted file mode 100644 index 1300edf984d..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/25.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/26.jpg b/interface/resources/qml/hifi/dialogs/security/images/26.jpg deleted file mode 100644 index 9e3aaf93830..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/26.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/27.jpg b/interface/resources/qml/hifi/dialogs/security/images/27.jpg deleted file mode 100644 index f64c0c6a3da..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/27.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/28.jpg b/interface/resources/qml/hifi/dialogs/security/images/28.jpg deleted file mode 100644 index 8f1580ab218..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/28.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/29.jpg b/interface/resources/qml/hifi/dialogs/security/images/29.jpg deleted file mode 100644 index fdfb4438ecb..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/29.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/30.jpg b/interface/resources/qml/hifi/dialogs/security/images/30.jpg deleted file mode 100644 index 785ea5a999f..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/30.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/31.jpg b/interface/resources/qml/hifi/dialogs/security/images/31.jpg deleted file mode 100644 index 06dc95afabe..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/31.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/32.jpg b/interface/resources/qml/hifi/dialogs/security/images/32.jpg deleted file mode 100644 index b987c44e134..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/32.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/33.jpg b/interface/resources/qml/hifi/dialogs/security/images/33.jpg deleted file mode 100644 index 19b05a5f73e..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/33.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/dialogs/security/images/34.jpg b/interface/resources/qml/hifi/dialogs/security/images/34.jpg deleted file mode 100644 index 39f2a5f4ce1..00000000000 Binary files a/interface/resources/qml/hifi/dialogs/security/images/34.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/simplifiedUI/avatarApp/AvatarApp.qml b/interface/resources/qml/hifi/simplifiedUI/avatarApp/AvatarApp.qml index 5ca2227dfbc..817b26e2c15 100644 --- a/interface/resources/qml/hifi/simplifiedUI/avatarApp/AvatarApp.qml +++ b/interface/resources/qml/hifi/simplifiedUI/avatarApp/AvatarApp.qml @@ -54,44 +54,6 @@ Rectangle { } } - Connections { - target: Commerce - - onLoginStatusResult: { - if (isLoggedIn) { - Commerce.getWalletStatus(); - } else { - errorText.text = "There was a problem while retrieving your inventory. " + - "Please try closing and re-opening the Avatar app.\n\nLogin status result: " + isLoggedIn; - } - } - - onWalletStatusResult: { - if (walletStatus === 5) { - getInventory(); - } else { - errorText.text = "There was a problem while retrieving your inventory. " + - "Please try closing and re-opening the Avatar app.\n\nWallet status result: " + walletStatus; - } - } - - onInventoryResult: { - if (result.status !== "success") { - errorText.text = "There was a problem while retrieving your inventory. " + - "Please try closing and re-opening the Avatar app.\n\nInventory status: " + result.status + "\nMessage: " + result.message; - } else if (result.data && result.data.assets && result.data.assets.length === 0 && avatarAppInventoryModel.count === 0) { - emptyInventoryContainer.visible = true; - } - - if (Settings.getValue("simplifiedUI/debugFTUE", 0) === 4) { - emptyInventoryContainer.visible = true; - } - - avatarAppInventoryModel.handlePage(result.status !== "success" && result.message, result); - root.updatePreviewUrl(); - } - } - Image { id: accent source: "images/accent.svg" diff --git a/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml b/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml index 778c626048d..bb4077511c6 100644 --- a/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml +++ b/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml @@ -60,126 +60,6 @@ Rectangle { } } - Connections { - target: Commerce - - onLoginStatusResult: { - if (inventoryFullyReceived) { - return; - } - - if (isLoggedIn) { - Commerce.getWalletStatus(); - } else { - // Show some error to the user in the UI? - } - } - - onWalletStatusResult: { - if (inventoryFullyReceived) { - return; - } - - switch (walletStatus) { - case 1: - var randomNumber = Math.floor(Math.random() * 34) + 1; - var securityImagePath = "images/" + randomNumber.toString().padStart(2, '0') + ".jpg"; - Commerce.getWalletAuthenticatedStatus(); // before writing security image, ensures that salt/account password is set. - Commerce.chooseSecurityImage(securityImagePath); - Commerce.generateKeyPair() - Commerce.getWalletStatus(); - break; - case 5: - topBarInventoryModel.getFirstPage(); - break; - default: - console.log('WARNING: SimplifiedTopBar.qml walletStatusResult:', walletStatus); - } - } - - onInventoryResult: { - if (inventoryFullyReceived) { - return; - } - - topBarInventoryModel.handlePage(result.status !== "success" && result.message, result); - root.updatePreviewUrl(); - - // I _should_ be able to do `if (currentPageToRetrieve > -1)` here, but the - // inventory endpoint doesn't return `response.total_pages`, so the PSFListModel doesn't - // know when to automatically stop fetching new pages. - // This will result in fetching one extra page than is necessary, but that's not a big deal. - if (result.data.assets.length > 0) { - topBarInventoryModel.getNextPage(); - } else { - inventoryFullyReceived = true; - var scriptExecutionCount = Settings.getValue("simplifiedUI/SUIScriptExecutionCount"); - var currentAvatarURL = MyAvatar.skeletonModelURL; - var currentAvatarURLContainsDefaultAvatar = currentAvatarURL.indexOf("defaultAvatar") > -1; - var currentAvatarURLContainsFST = currentAvatarURL.indexOf("fst") > -1; - var currentAvatarURLContainsSimplifiedAvatar = currentAvatarURL.indexOf("simplifiedAvatar") > -1; - var alreadyAutoSelectedAvatarFromInventory = Settings.getValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", false); - var userHasValidAvatarInInventory = topBarInventoryModel.count > 0 && - topBarInventoryModel.get(0).download_url.indexOf(".fst") > -1; - var simplifiedAvatarPrefix = "https://content.highfidelity.com/Experiences/Releases/simplifiedUI/simplifiedFTUE/avatars/simplifiedAvatar_"; - var simplifiedAvatarColors = ["Blue", "Cyan", "Green", "Magenta", "Red"]; - var simplifiedAvatarSuffix = "/avatar.fst"; - - // Use `Settings.setValue("simplifiedUI/debugFTUE", 0);` to turn off FTUE Debug Mode. - // Use `Settings.setValue("simplifiedUI/debugFTUE", 1);` to debug FTUE Screen 1. - // Use `Settings.setValue("simplifiedUI/debugFTUE", 2);` to debug FTUE Screen 2. - // Use `Settings.setValue("simplifiedUI/debugFTUE", 3);` to debug FTUE Screen 3. - // Use `Settings.setValue("simplifiedUI/debugFTUE", 4);` to force the UI to show what would happen if the user had an empty Inventory. - - var debugFTUE = Settings.getValue("simplifiedUI/debugFTUE", 0); - if (debugFTUE === 1 || debugFTUE === 2) { - scriptExecutionCount = 1; - currentAvatarURLContainsDefaultAvatar = true; - if (debugFTUE === 1) { - userHasValidAvatarInInventory = false; - currentAvatarURLContainsSimplifiedAvatar = false; - } - } else if (debugFTUE === 3) { - scriptExecutionCount = 2; - currentAvatarURLContainsDefaultAvatar = false; - currentAvatarURLContainsSimplifiedAvatar = true; - } - - // If we have never auto-selected and the user is still using a default avatar or if the current avatar is not valid (fst), or if - // the current avatar is the old default (Woody), use top avatar from inventory or one of the new defaults. - - // If the current avatar URL is invalid, OR the user is using the "default avatar" (Woody)... - if (!currentAvatarURLContainsFST || currentAvatarURLContainsDefaultAvatar) { - // If the user has a valid avatar in their inventory... - if (userHasValidAvatarInInventory) { - // ...use the first avatar in the user's inventory. - MyAvatar.useFullAvatarURL(topBarInventoryModel.get(0).download_url); - Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", true); - // Else if the user isn't wearing a "Simplified Avatar" - } else if (!currentAvatarURLContainsSimplifiedAvatar) { - // ...assign to the user a new "Simplified Avatar" (i.e. a simple avatar of random color) - var avatarColor = simplifiedAvatarColors[Math.floor(Math.random() * simplifiedAvatarColors.length)]; - var simplifiedAvatarModelURL = simplifiedAvatarPrefix + avatarColor + simplifiedAvatarSuffix; - MyAvatar.useFullAvatarURL(simplifiedAvatarModelURL); - currentAvatarURLContainsSimplifiedAvatar = true; - } - } - - if (scriptExecutionCount === 1) { - sendToScript({ - "source": "SimplifiedTopBar.qml", - "method": "displayInitialLaunchWindow" - }); - } else if (scriptExecutionCount === 2 && currentAvatarURLContainsSimplifiedAvatar) { - sendToScript({ - "source": "SimplifiedTopBar.qml", - "method": "displaySecondLaunchWindow" - }); - } - } - } - } - HifiModels.PSFListModel { id: topBarInventoryModel itemsPerPage: 8 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe2077f7523..ed7ca71e873 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -85,7 +85,6 @@ #include #include #include -#include "ui/overlays/ContextOverlayInterface.h" #include #include #include @@ -197,7 +196,6 @@ #include "scripting/ControllerScriptingInterface.h" #include "scripting/RatesScriptingInterface.h" #include "scripting/SelectionScriptingInterface.h" -#include "scripting/WalletScriptingInterface.h" #include "scripting/TTSScriptingInterface.h" #include "scripting/KeyboardScriptingInterface.h" #include "scripting/PerformanceScriptingInterface.h" @@ -243,10 +241,6 @@ #include -#include "commerce/Ledger.h" -#include "commerce/Wallet.h" -#include "commerce/QmlCommerce.h" -#include "commerce/QmlMarketplace.h" #include "ResourceRequestObserver.h" #include "webbrowser/WebBrowserSuggestionsEngine.h" @@ -937,11 +931,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); - DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -1227,10 +1217,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qCDebug(interfaceapp) << "[VERSION] We will use DEVELOPMENT global services."; #endif - bool isStore = property(hifi::properties::OCULUS_STORE).toBool(); - // Or we could make it a separate arg, or if either arg is set, etc. And should this instead by a hifi::properties? - DependencyManager::get()->setLimitedCommerce(isStore || property(hifi::properties::STEAM).toBool()); - updateHeartbeat(); // setup a timer for domain-server check ins @@ -1468,10 +1454,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer << NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer << NodeType::EntityScriptServer); - // connect to the packet sent signal of the _entityEditSender - connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent); - connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, &Application::addingEntityWithCertificate); - QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads"); bool success; uint32_t concurrentDownloads = concurrentDownloadsStr.toUInt(&success); @@ -1562,7 +1544,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Overlays need to exist before we set the ContextOverlayInterface dependency _overlays.init(); // do this before scripts load - DependencyManager::set(); auto offscreenUi = getOffscreenUI(); connect(offscreenUi.data(), &OffscreenUi::desktopReady, []() { @@ -2833,11 +2814,7 @@ void Application::cleanupBeforeQuit() { _window->saveGeometry(); - // Destroy third party processes after scripts have finished using them. - DependencyManager::destroy(); // Must be destroyed before TabletScriptingInterface - // stop QML - DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); @@ -3231,54 +3208,11 @@ void Application::initializeUi() { LoginDialog::registerType(); Tooltip::registerType(); UpdateDialog::registerType(); - QmlContextCallback commerceCallback = [](QQmlContext* context) { - context->setContextProperty("Commerce", DependencyManager::get().data()); - }; - - OffscreenQmlSurface::addWhitelistContextHandler({ - QUrl{ "hifi/commerce/checkout/Checkout.qml" }, - QUrl{ "hifi/commerce/common/CommerceLightbox.qml" }, - QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, - QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" }, - QUrl{ "hifi/commerce/common/sendAsset/SendAsset.qml" }, - QUrl{ "hifi/commerce/common/SortableListModel.qml" }, - QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, - QUrl{ "hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml"}, - QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" }, - QUrl{ "hifi/commerce/purchases/Purchases.qml" }, - QUrl{ "hifi/commerce/wallet/Help.qml" }, - QUrl{ "hifi/commerce/wallet/NeedsLogIn.qml" }, - QUrl{ "hifi/commerce/wallet/PassphraseChange.qml" }, - QUrl{ "hifi/commerce/wallet/PassphraseModal.qml" }, - QUrl{ "hifi/commerce/wallet/PassphraseSelection.qml" }, - QUrl{ "hifi/commerce/wallet/Wallet.qml" }, - QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, - QUrl{ "hifi/commerce/wallet/WalletSetup.qml" }, - QUrl{ "hifi/dialogs/security/Security.qml" }, - QUrl{ "hifi/dialogs/security/SecurityImageChange.qml" }, - QUrl{ "hifi/dialogs/security/SecurityImageModel.qml" }, - QUrl{ "hifi/dialogs/security/SecurityImageSelection.qml" }, - QUrl{ "hifi/tablet/TabletMenu.qml" }, - QUrl{ "hifi/commerce/marketplace/Marketplace.qml" }, - QUrl{ "hifi/simplifiedUI/avatarApp/AvatarApp.qml" }, - QUrl{ "hifi/simplifiedUI/topBar/SimplifiedTopBar.qml" }, - }, commerceCallback); - - QmlContextCallback marketplaceCallback = [](QQmlContext* context) { - context->setContextProperty("MarketplaceScriptingInterface", new QmlMarketplace()); - }; - OffscreenQmlSurface::addWhitelistContextHandler({ - QUrl{ "hifi/commerce/marketplace/Marketplace.qml" }, - }, marketplaceCallback); QmlContextCallback platformInfoCallback = [](QQmlContext* context) { context->setContextProperty("PlatformInfo", new PlatformInfoScriptingInterface()); }; OffscreenQmlSurface::addWhitelistContextHandler({ - QUrl{ "hifi/commerce/marketplace/Marketplace.qml" }, - QUrl{ "hifi/commerce/purchases/Purchases.qml" }, - QUrl{ "hifi/commerce/wallet/Wallet.qml" }, - QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, QUrl{ "hifi/tablet/TabletAddressDialog.qml" }, QUrl{ "hifi/Card.qml" }, QUrl{ "hifi/Pal.qml" }, @@ -3510,8 +3444,6 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); surfaceContext->setContextProperty("Selection", DependencyManager::get().data()); - surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get().data()); - surfaceContext->setContextProperty("WalletScriptingInterface", DependencyManager::get().data()); surfaceContext->setContextProperty("About", AboutUtil::getInstance()); surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance()); // Deprecated surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get().data()); @@ -3626,7 +3558,6 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona surfaceContext->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface()); surfaceContext->setContextProperty("About", AboutUtil::getInstance()); surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance()); // Deprecated. - surfaceContext->setContextProperty("WalletScriptingInterface", DependencyManager::get().data()); surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get().data()); surfaceContext->setContextProperty("PlatformInfo", PlatformInfoScriptingInterface::getInstance()); // This `module` context property is blank for the QML scripting interface so that we don't get log errors when importing @@ -7358,14 +7289,6 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer return statsMessageLength; } -void Application::packetSent(quint64 length) { -} - -void Application::addingEntityWithCertificate(const QString& certificateID, const QString& placeName) { - auto ledger = DependencyManager::get(); - ledger->updateLocation(certificateID, placeName); -} - void Application::registerScriptEngineWithApplicationServices(const ScriptEnginePointer& scriptEngine) { scriptEngine->setEmitScriptUpdatesFunction([this]() { @@ -7523,8 +7446,6 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data()); scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance()); scriptEngine->registerGlobalObject("Selection", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("WalletScriptingInterface", DependencyManager::get().data()); scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get().data()); scriptEngine->registerGlobalObject("About", AboutUtil::getInstance()); scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance()); // Deprecated. diff --git a/interface/src/Application.h b/interface/src/Application.h index f42696cda00..c8349dc9897 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -516,8 +516,6 @@ private slots: void nodeAdded(SharedNodePointer node); void nodeActivated(SharedNodePointer node); void nodeKilled(SharedNodePointer node); - static void packetSent(quint64 length); - static void addingEntityWithCertificate(const QString& certificateID, const QString& placeName); void updateDisplayMode(); void setDisplayPlugin(DisplayPluginPointer newPlugin); void domainConnectionRefused(const QString& reasonMessage, int reason, const QString& extraInfo); diff --git a/interface/src/avatar/AvatarPackager.cpp b/interface/src/avatar/AvatarPackager.cpp index 90def7ad436..ce1b9ad59fa 100644 --- a/interface/src/avatar/AvatarPackager.cpp +++ b/interface/src/avatar/AvatarPackager.cpp @@ -19,7 +19,6 @@ #include #include "ModelSelector.h" -#include #include #include "ui/TabletScriptingInterface.h" @@ -28,7 +27,6 @@ std::once_flag setupQMLTypesFlag; AvatarPackager::AvatarPackager() { std::call_once(setupQMLTypesFlag, []() { qmlRegisterType(); - qmlRegisterType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); diff --git a/interface/src/avatar/AvatarProject.cpp b/interface/src/avatar/AvatarProject.cpp index 260ff33db7a..466db613f67 100644 --- a/interface/src/avatar/AvatarProject.cpp +++ b/interface/src/avatar/AvatarProject.cpp @@ -226,43 +226,6 @@ QStringList AvatarProject::getProjectFiles() const { return paths; } -MarketplaceItemUploader* AvatarProject::upload(bool updateExisting) { - QUuid itemID; - if (updateExisting) { - itemID = _fst->getMarketplaceID(); - } - auto uploader = new MarketplaceItemUploader(getProjectName(), "", QFileInfo(getFSTPath()).fileName(), - itemID, _projectFiles); - connect(uploader, &MarketplaceItemUploader::completed, this, [this, uploader]() { - if (uploader->getError() == MarketplaceItemUploader::Error::None) { - _fst->setMarketplaceID(uploader->getMarketplaceID()); - _fst->write(); - } - }); - - return uploader; -} - AvatarDoctor* AvatarProject::diagnose() { return new AvatarDoctor(QUrl(getFSTPath())); } - -void AvatarProject::openInInventory() const { - constexpr int TIME_TO_WAIT_FOR_INVENTORY_TO_OPEN_MS { 1000 }; - - auto tablet = dynamic_cast( - DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); - tablet->loadQMLSource("hifi/commerce/wallet/Wallet.qml"); - DependencyManager::get()->openTablet(); - - // I'm not a fan of this, but it's the only current option. - auto name = getProjectName(); - QTimer::singleShot(TIME_TO_WAIT_FOR_INVENTORY_TO_OPEN_MS, [name, tablet]() { - tablet->sendToQml(QVariantMap({ { "method", "updatePurchases" }, { "filterText", name } })); - }); - - QQuickItem* root = tablet->getTabletRoot(); - if (root) { - root->forceActiveFocus(); - } -} diff --git a/interface/src/avatar/AvatarProject.h b/interface/src/avatar/AvatarProject.h index 3e0d69f78b5..b241339793e 100644 --- a/interface/src/avatar/AvatarProject.h +++ b/interface/src/avatar/AvatarProject.h @@ -13,7 +13,6 @@ #ifndef hifi_AvatarProject_h #define hifi_AvatarProject_h -#include "MarketplaceItemUploader.h" #include "AvatarDoctor.h" #include "ProjectFile.h" #include "FST.h" @@ -57,8 +56,6 @@ class AvatarProject : public QObject { Q_PROPERTY(bool hasErrors READ getHasErrors WRITE setHasErrors NOTIFY hasErrorsChanged) public: - Q_INVOKABLE MarketplaceItemUploader* upload(bool updateExisting); - Q_INVOKABLE void openInInventory() const; Q_INVOKABLE QStringList getProjectFiles() const; Q_INVOKABLE AvatarDoctor* diagnose(); diff --git a/interface/src/avatar/MarketplaceItemUploader.cpp b/interface/src/avatar/MarketplaceItemUploader.cpp deleted file mode 100644 index 28b07780b03..00000000000 --- a/interface/src/avatar/MarketplaceItemUploader.cpp +++ /dev/null @@ -1,321 +0,0 @@ -// -// MarketplaceItemUploader.cpp -// -// -// Created by Ryan Huffman on 12/10/2018 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "MarketplaceItemUploader.h" - -#include -#include - -#ifndef Q_OS_ANDROID -#include -#include -#endif - -#include -#include - -#include -#include - -#include -#include -#include -#include - -MarketplaceItemUploader::MarketplaceItemUploader(QString title, - QString description, - QString rootFilename, - QUuid marketplaceID, - QList filePaths) : - _title(title), - _description(description), - _rootFilename(rootFilename), - _marketplaceID(marketplaceID), - _filePaths(filePaths) { -} - -void MarketplaceItemUploader::setState(State newState) { - Q_ASSERT(_state != State::Complete); - Q_ASSERT(_error == Error::None); - Q_ASSERT(newState != _state); - - _state = newState; - emit stateChanged(newState); - if (newState == State::Complete) { - emit completed(); - emit finishedChanged(); - } -} - -void MarketplaceItemUploader::setError(Error error) { - Q_ASSERT(_state != State::Complete); - Q_ASSERT(_error == Error::None); - - _error = error; - emit errorChanged(error); - emit finishedChanged(); -} - -void MarketplaceItemUploader::send() { - doGetCategories(); -} - -void MarketplaceItemUploader::doGetCategories() { - setState(State::GettingCategories); - - static const QString path = "/api/v1/marketplace/categories"; - - auto accountManager = DependencyManager::get(); - auto request = accountManager->createRequest(path, AccountManagerAuth::None); - - qWarning() << "Request url is: " << request.url(); - - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - - QNetworkReply* reply = networkAccessManager.get(request); - - connect(reply, &QNetworkReply::finished, this, [this, reply]() { - auto error = reply->error(); - if (error == QNetworkReply::NoError) { - auto doc = QJsonDocument::fromJson(reply->readAll()); - auto extractCategoryID = [&doc]() -> std::pair { - auto items = doc.object()["data"].toObject()["categories"]; - if (!items.isArray()) { - qWarning() << "Categories parse error: data.items is not an array"; - return { false, 0 }; - } - - auto itemsArray = items.toArray(); - for (const auto item : itemsArray) { - if (!item.isObject()) { - qWarning() << "Categories parse error: item is not an object"; - return { false, 0 }; - } - - auto itemObject = item.toObject(); - if (itemObject["name"].toString() == "Avatars") { - auto idValue = itemObject["id"]; - if (!idValue.isDouble()) { - qWarning() << "Categories parse error: id is not a number"; - return { false, 0 }; - } - return { true, (int)idValue.toDouble() }; - } - } - - qWarning() << "Categories parse error: could not find a category for 'Avatar'"; - return { false, 0 }; - }; - - bool success; - std::tie(success, _categoryID) = extractCategoryID(); - if (!success) { - qWarning() << "Failed to find marketplace category id"; - setError(Error::Unknown); - } else { - qDebug() << "Marketplace Avatar category ID is" << _categoryID; - doUploadAvatar(); - } - } else { - setError(Error::Unknown); - } - }); -} - -void MarketplaceItemUploader::doUploadAvatar() { -#ifdef Q_OS_ANDROID - qWarning() << "Marketplace uploading is not supported on Android"; - setError(Error::Unknown); - return; -#else - QBuffer buffer{ &_fileData }; - QuaZip zip{ &buffer }; - if (!zip.open(QuaZip::Mode::mdAdd)) { - qWarning() << "Failed to open zip"; - setError(Error::Unknown); - return; - } - - for (auto& filePath : _filePaths) { - qWarning() << "Zipping: " << filePath.absolutePath << filePath.relativePath; - QFileInfo fileInfo{ filePath.absolutePath }; - - QuaZipFile zipFile{ &zip }; - if (!zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(filePath.relativePath))) { - qWarning() << "Could not open zip file:" << zipFile.getZipError(); - setError(Error::Unknown); - return; - } - QFile file{ filePath.absolutePath }; - if (file.open(QIODevice::ReadOnly)) { - zipFile.write(file.readAll()); - } else { - qWarning() << "Failed to open: " << filePath.absolutePath; - } - 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(); - auto request = accountManager->createRequest(path, AccountManagerAuth::Required); - request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); - - // TODO(huffman) add JSON escaping - auto escapeJson = [](QString str) -> QString { return str; }; - - QString jsonString = "{\"marketplace_item\":{"; - jsonString += "\"title\":\"" + escapeJson(_title) + "\""; - - // Items cannot have their description updated after they have been submitted. - if (creating) { - jsonString += ",\"description\":\"" + escapeJson(_description) + "\""; - } - - jsonString += ",\"root_file_key\":\"" + escapeJson(_rootFilename) + "\""; - jsonString += ",\"category_ids\":[" + QStringLiteral("%1").arg(_categoryID) + "]"; - jsonString += ",\"license\":0"; - jsonString += ",\"files\":\"" + QString::fromLatin1(_fileData.toBase64()) + "\"}}"; - - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - - QNetworkReply* reply{ nullptr }; - if (creating) { - reply = networkAccessManager.post(request, jsonString.toUtf8()); - } else { - reply = networkAccessManager.put(request, jsonString.toUtf8()); - } - - connect(reply, &QNetworkReply::uploadProgress, this, [this](float bytesSent, float bytesTotal) { - if (_state == State::UploadingAvatar) { - emit uploadProgress(bytesSent, bytesTotal); - if (bytesSent >= bytesTotal) { - setState(State::WaitingForUploadResponse); - } - } - }); - - connect(reply, &QNetworkReply::finished, this, [this, reply]() { - _responseData = reply->readAll(); - - 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(); - setState(State::WaitingForInventory); - doWaitForInventory(); - } else { - qWarning() << "Got error response while uploading avatar: " << _responseData; - setError(Error::Unknown); - } - } else { - qWarning() << "Got error while uploading avatar: " << reply->error() << reply->errorString() << _responseData; - setError(Error::Unknown); - } - }); - - setState(State::UploadingAvatar); -#endif -} - -void MarketplaceItemUploader::doWaitForInventory() { - static const QString path = "/api/v1/commerce/inventory"; - - auto accountManager = DependencyManager::get(); - auto request = accountManager->createRequest(path, AccountManagerAuth::Required); - - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - - QNetworkReply* reply = networkAccessManager.post(request, ""); - - _numRequestsForInventory++; - - connect(reply, &QNetworkReply::finished, this, [this, reply]() { - auto data = reply->readAll(); - - 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"]; - auto valid = assetObject["valid"]; - if (version.isDouble() && valid.isBool()) { - if ((int)version.toDouble() >= _itemVersion && valid.toBool()) { - return true; - } - } - } - } - return false; - }; - - success = isAssetAvailable(); - } - if (success) { - qDebug() << "Found item in inventory"; - setState(State::Complete); - } else { - constexpr int MAX_INVENTORY_REQUESTS { 8 }; - constexpr int TIME_BETWEEN_INVENTORY_REQUESTS_MS { 5000 }; - if (_numRequestsForInventory > MAX_INVENTORY_REQUESTS) { - qDebug() << "Failed to find item in inventory"; - setError(Error::Unknown); - } else { - QTimer::singleShot(TIME_BETWEEN_INVENTORY_REQUESTS_MS, [this]() { doWaitForInventory(); }); - } - } - }); -} diff --git a/interface/src/avatar/MarketplaceItemUploader.h b/interface/src/avatar/MarketplaceItemUploader.h deleted file mode 100644 index 998413da88d..00000000000 --- a/interface/src/avatar/MarketplaceItemUploader.h +++ /dev/null @@ -1,105 +0,0 @@ -// -// MarketplaceItemUploader.h -// -// -// Created by Ryan Huffman on 12/10/2018 -// Copyright 2018 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#pragma once -#ifndef hifi_MarketplaceItemUploader_h -#define hifi_MarketplaceItemUploader_h - -#include "ProjectFile.h" - -#include -#include - -class QNetworkReply; - -class MarketplaceItemUploader : public QObject { - Q_OBJECT - - Q_PROPERTY(bool finished READ getFinished NOTIFY finishedChanged) - - Q_PROPERTY(bool complete READ getComplete NOTIFY stateChanged) - Q_PROPERTY(State state READ getState NOTIFY stateChanged) - Q_PROPERTY(Error error READ getError NOTIFY errorChanged) - Q_PROPERTY(QString responseData READ getResponseData) -public: - enum class Error { - None, - Unknown, - }; - Q_ENUM(Error); - - enum class State { - Idle, - GettingCategories, - UploadingAvatar, - WaitingForUploadResponse, - WaitingForInventory, - Complete, - }; - Q_ENUM(State); - - MarketplaceItemUploader(QString title, - QString description, - QString rootFilename, - QUuid marketplaceID, - QList filePaths); - - Q_INVOKABLE void send(); - - void setError(Error error); - - QString getResponseData() const { return _responseData; } - void setState(State newState); - State getState() const { return _state; } - bool getComplete() const { return _state == State::Complete; } - - QUuid getMarketplaceID() const { return _marketplaceID; } - - Error getError() const { return _error; } - bool getFinished() const { return _state == State::Complete || _error != Error::None; } - -signals: - void uploadProgress(qint64 bytesSent, qint64 bytesTotal); - void completed(); - - void stateChanged(State newState); - void errorChanged(Error error); - - // Triggered when the upload has finished, either succesfully completing, or stopping with an error - void finishedChanged(); - -private: - void doGetCategories(); - void doUploadAvatar(); - void doWaitForInventory(); - - QNetworkReply* _reply; - - State _state { State::Idle }; - Error _error { Error::None }; - - QString _title; - QString _description; - QString _rootFilename; - QUuid _marketplaceID; - int _categoryID; - int _itemVersion; - - QString _responseData; - - int _numRequestsForInventory { 0 }; - - QString _rootFilePath; - QList _filePaths; - QByteArray _fileData; -}; - -#endif // hifi_MarketplaceItemUploader_h diff --git a/interface/src/commerce/CommerceLogging.cpp b/interface/src/commerce/CommerceLogging.cpp deleted file mode 100644 index 65102e9699f..00000000000 --- a/interface/src/commerce/CommerceLogging.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// -// CommerceLogging.cpp -// interface/src/commerce -// -// Created by Howard Stearns on 8/9/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "CommerceLogging.h" - -Q_LOGGING_CATEGORY(commerce, "hifi.commerce") diff --git a/interface/src/commerce/CommerceLogging.h b/interface/src/commerce/CommerceLogging.h deleted file mode 100644 index d641977872f..00000000000 --- a/interface/src/commerce/CommerceLogging.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// CommerceLogging.h -// interface/src/commerce -// -// Created by Howard Stearns on 8/9/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_CommerceLogging_h -#define hifi_CommerceLogging_h - -#include - -Q_DECLARE_LOGGING_CATEGORY(commerce) - -#endif // hifi_CommerceLogging_h diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp deleted file mode 100644 index 4a41374ba34..00000000000 --- a/interface/src/commerce/Ledger.cpp +++ /dev/null @@ -1,510 +0,0 @@ -// -// Ledger.cpp -// interface/src/commerce -// -// Created by Howard Stearns on 8/4/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "Ledger.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include "Wallet.h" -#include "CommerceLogging.h" - -// inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}} -// balance answers {status: 'success', data: {balance: integer}} -// buy and receive_at answer {status: 'success'} -// account synthesizes a result {status: 'success', data: {keyStatus: "preexisting"|"conflicting"|"ok"}} - - -QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply* reply) { - QByteArray response = reply->readAll(); - QJsonObject data = QJsonDocument::fromJson(response).object(); -#if defined(DEV_BUILD) // Don't expose user's personal data in the wild. But during development this can be handy. - qInfo(commerce) << label << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact); -#endif - return data; -} -// Non-200 responses are not json: -QJsonObject Ledger::failResponse(const QString& label, QNetworkReply* reply) { - QString response = reply->readAll(); - qWarning(commerce) << "FAILED" << label << response; - - // tempResult will be NULL if the response isn't valid JSON. - QJsonDocument tempResult = QJsonDocument::fromJson(response.toLocal8Bit()); - if (tempResult.isNull()) { - QJsonObject result - { - { "status", "fail" }, - { "message", response } - }; - return result; - } else { - return tempResult.object(); - } -} -#define ApiHandler(NAME) void Ledger::NAME##Success(QNetworkReply* reply) { emit NAME##Result(apiResponse(#NAME, reply)); } -#define FailHandler(NAME) void Ledger::NAME##Failure(QNetworkReply* reply) { emit NAME##Result(failResponse(#NAME, reply)); } -#define Handler(NAME) ApiHandler(NAME) FailHandler(NAME) -Handler(buy) -Handler(receiveAt) -Handler(balance) -Handler(inventory) -Handler(transferAssetToNode) -Handler(transferAssetToUsername) -Handler(authorizeAssetTransfer) -Handler(alreadyOwned) -Handler(availableUpdates) -Handler(updateItem) - -void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, QJsonObject request) { - auto accountManager = DependencyManager::get(); - const QString URL = "/api/v1/commerce/"; - JSONCallbackParameters callbackParams(this, success, fail); -#if defined(DEV_BUILD) // Don't expose user's personal data in the wild. But during development this can be handy. - qCInfo(commerce) << "Sending" << QJsonDocument(request).toJson(QJsonDocument::Compact); -#endif - accountManager->sendRequest(URL + endpoint, - authType, - method, - callbackParams, - QJsonDocument(request).toJson()); -} - -void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) { - auto wallet = DependencyManager::get(); - QString signature = wallet->signWithKey(text, key); - QJsonObject request; - request[propertyName] = QString(text); - if (!controlled_failure) { - request["signature"] = signature; - } else { - request["signature"] = QString("controlled failure!"); - } - send(endpoint, success, fail, QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request); -} - -void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail, QJsonObject& requestParams) { - auto wallet = DependencyManager::get(); - QStringList cachedPublicKeys = wallet->listPublicKeys(); - if (!cachedPublicKeys.isEmpty()) { - requestParams["public_keys"] = QJsonArray::fromStringList(cachedPublicKeys); - send(endpoint, success, fail, QNetworkAccessManager::PostOperation, AccountManagerAuth::Required, requestParams); - } else { - qDebug(commerce) << "User attempted to call keysQuery, but cachedPublicKeys was empty!"; - } -} - -void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail) { - QJsonObject requestParams; - keysQuery(endpoint, success, fail, requestParams); -} - -void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure) { - QJsonObject transaction; - transaction["hfc_key"] = hfc_key; - transaction["cost"] = cost; - transaction["asset_id"] = asset_id; - transaction["inventory_key"] = inventory_key; - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure", controlled_failure); -} - -bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key, const QByteArray& locker) { - auto accountManager = DependencyManager::get(); - if (!accountManager->isLoggedIn()) { - qCWarning(commerce) << "Cannot set receiveAt when not logged in."; - QJsonObject result{ { "status", "fail" }, { "message", "Not logged in" } }; - emit receiveAtResult(result); - return false; // We know right away that we will fail, so tell the caller. - } - QJsonObject transaction; - transaction["public_key"] = hfc_key; - transaction["locker"] = QString::fromUtf8(locker); - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - signedSend("text", transactionString, signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); - return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in. -} - -bool Ledger::receiveAt() { - auto wallet = DependencyManager::get(); - auto keys = wallet->listPublicKeys(); - if (keys.isEmpty()) { - return false; - } - auto key = keys.first(); - return receiveAt(key, key, wallet->getWallet()); -} - -void Ledger::balance(const QStringList& keys) { - keysQuery("balance", "balanceSuccess", "balanceFailure"); -} - -void Ledger::inventory(const QString& editionFilter, const QString& typeFilter, const QString& titleFilter, const int& page, const int& perPage) { - QJsonObject params; - params["edition_filter"] = editionFilter; - params["type_filter"] = typeFilter; - params["title_filter"] = titleFilter; - params["page"] = page; - params["per_page"] = perPage; - keysQuery("inventory", "inventorySuccess", "inventoryFailure", params); -} - -QString hfcString(const QJsonValue& sentValue, const QJsonValue& receivedValue) { - int sent = sentValue.toInt(); - int received = receivedValue.toInt(); - if (sent <= 0 && received <= 0) { - return QString("0 HFC"); - } - QString result; - if (sent > 0) { - result += QString("-%1 HFC").arg(sent); - if (received > 0) { - result += QString("
"); - } - } - if (received > 0) { - result += QString("%1 HFC").arg(received); - } - return result; -} - -QString getUserPageBaseUrl() { - return MetaverseAPI::getCurrentMetaverseServerURL().toString() + "/users/"; -} - -QString getPlacePageBaseUrl() { - return MetaverseAPI::getCurrentMetaverseServerURL().toString() + "/places/"; -} - -static const QStringList KNOWN_USERS(QStringList() << "highfidelity" << "marketplace"); -QString userLink(const QString& username, const QString& placename) { - if (username.isEmpty()) { - if (placename.isEmpty()) { - return QString("someone"); - } else { - return QString("someone nearby").arg(getPlacePageBaseUrl(), placename); - } - } - if (KNOWN_USERS.contains(username)) { - return username; - } - return QString("%2").arg(getUserPageBaseUrl(), username); -} - -QString transactionString(const QJsonObject& valueObject) { - int sentCerts = valueObject["sent_certs"].toInt(); - int receivedCerts = valueObject["received_certs"].toInt(); - int sentMoney = valueObject["sent_money"].toInt(); - int receivedMoney = valueObject["received_money"].toInt(); - int dateInteger = valueObject["created_at"].toInt(); - QString transactionType = valueObject["transaction_type"].toString(); - QString message = valueObject["message"].toString(); - QDateTime createdAt(QDateTime::fromSecsSinceEpoch(dateInteger, Qt::UTC)); - QString result; - - if (sentCerts <= 0 && receivedCerts <= 0 && !KNOWN_USERS.contains(valueObject["sender_name"].toString())) { - // this is an hfc transfer. - if (sentMoney > 0) { - if (transactionType == "escrow") { - result += QString("Money transferred to coupon"); - } else { - QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString()); - result += QString("Money sent to %1").arg(recipient); - } - } else { - QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString()); - result += QString("Money from %1").arg(sender); - } - if (!message.isEmpty()) { - result += QString("
with memo: \"%1\"").arg(message); - } - } else if (sentMoney <= 0 && receivedMoney <= 0 && - (sentCerts > 0 || receivedCerts > 0) && - !KNOWN_USERS.contains(valueObject["sender_name"].toString()) && - !KNOWN_USERS.contains(valueObject["recipient_name"].toString()) - ) { - // this is a non-HFC asset transfer. - if (sentCerts > 0) { - if (transactionType == "escrow") { - result += QString("Item transferred to coupon"); - } else { - QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString()); - result += QString("Gift sent to %1").arg(recipient); - } - } else { - QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString()); - result += QString("Gift from %1").arg(sender); - } - if (!message.isEmpty()) { - result += QString("
with memo: \"%1\"").arg(message); - } - } else { - result += valueObject["message"].toString(); - } - - // no matter what we append a smaller date to the bottom of this... - result += QString("
%1").arg(createdAt.toLocalTime().toString(Qt::DefaultLocaleShortDate)); - return result; -} - -void Ledger::historySuccess(QNetworkReply* reply) { - // here we send a historyResult with some extra stuff in it - // Namely, the styled text we'd like to show. The issue is the - // QML cannot do that easily since it doesn't know what the wallet - // public key(s) are. Let's keep it that way - QByteArray response = reply->readAll(); - QJsonObject data = QJsonDocument::fromJson(response).object(); - qInfo(commerce) << "history" << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact); - - // we will need the array of public keys from the wallet - auto wallet = DependencyManager::get(); - auto keys = wallet->listPublicKeys(); - - // now we need to loop through the transactions and add fancy text... - auto historyArray = data.find("data").value().toObject().find("history").value().toArray(); - QJsonArray newHistoryArray; - - // TODO: do this with 0 copies if possible - for (auto it = historyArray.begin(); it != historyArray.end(); it++) { - // We have 2 text fields to synthesize, the one on the left is a listing - // of the HFC in/out of your wallet. The one on the right contains an explaination - // of the transaction. That could be just the memo (if it is a regular purchase), or - // more text (plus the optional memo) if an hfc transfer - auto valueObject = (*it).toObject(); - valueObject["hfc_text"] = hfcString(valueObject["sent_money"], valueObject["received_money"]); - valueObject["transaction_text"] = transactionString(valueObject); - newHistoryArray.push_back(valueObject); - } - // now copy the rest of the json -- this is inefficient - // TODO: try to do this without making copies - QJsonObject newData; - newData["status"] = "success"; - QJsonObject newDataData; - newDataData["history"] = newHistoryArray; - newData["data"] = newDataData; - newData["current_page"] = data["current_page"].toInt(); - emit historyResult(newData); -} - -void Ledger::historyFailure(QNetworkReply* reply) { - failResponse("history", reply); -} - -void Ledger::history(const QStringList& keys, const int& pageNumber, const int& itemsPerPage) { - QJsonObject params; - params["per_page"] = itemsPerPage; - params["page"] = pageNumber; - keysQuery("history", "historySuccess", "historyFailure", params); -} - -void Ledger::accountSuccess(QNetworkReply* reply) { - // lets set the appropriate stuff in the wallet now - auto wallet = DependencyManager::get(); - QByteArray response = reply->readAll(); - QJsonObject data = QJsonDocument::fromJson(response).object()["data"].toObject(); - - auto salt = QByteArray::fromBase64(data["salt"].toString().toUtf8()); - auto iv = QByteArray::fromBase64(data["iv"].toString().toUtf8()); - auto ckey = QByteArray::fromBase64(data["ckey"].toString().toUtf8()); - QString remotePublicKey = data["public_key"].toString(); - const QByteArray locker = data["locker"].toString().toUtf8(); - bool isOverride = wallet->wasSoftReset(); - - wallet->setIv(iv); - wallet->setCKey(ckey); - if (!locker.isEmpty()) { - wallet->setWallet(locker); - wallet->setPassphrase("ACCOUNT"); // We only locker wallets that have been converted to account-based auth. - } - wallet->setSalt(salt); - - QString keyStatus = "ok"; - QStringList localPublicKeys = wallet->listPublicKeys(); - if (remotePublicKey.isEmpty() || isOverride) { - if (!localPublicKeys.isEmpty()) { // Let the metaverse know about a local wallet. - receiveAt(); - } - } else { - if (localPublicKeys.isEmpty()) { - keyStatus = "preexisting"; - } else if (localPublicKeys.first() != remotePublicKey) { - keyStatus = "conflicting"; - } else if (locker.isEmpty()) { // Matches metaverse data, but we haven't lockered it yet. - receiveAt(); - } - } - - // none of the hfc account info should be emitted - QJsonObject json; - QJsonObject responseData{ { "status", "success"} }; - json["keyStatus"] = keyStatus; - responseData["data"] = json; - emit accountResult(responseData); -} - -void Ledger::accountFailure(QNetworkReply* reply) { - failResponse("account", reply); -} -void Ledger::account() { - send("hfc_account", "accountSuccess", "accountFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, QJsonObject()); -} - -// The api/failResponse is called just for the side effect of logging. -void Ledger::updateLocationSuccess(QNetworkReply* reply) { apiResponse("updateLocation", reply); } -void Ledger::updateLocationFailure(QNetworkReply* reply) { failResponse("updateLocation", reply); } -void Ledger::updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings, const bool controlledFailure) { - auto wallet = DependencyManager::get(); - auto walletScriptingInterface = DependencyManager::get(); - uint walletStatus = walletScriptingInterface->getWalletStatus(); - - if (walletStatus != (uint)wallet->WALLET_STATUS_READY) { - emit walletScriptingInterface->walletNotSetup(); - qDebug(commerce) << "User attempted to update the location of a certificate, but their wallet wasn't ready. Status:" << walletStatus; - } else { - QStringList cachedPublicKeys = wallet->listPublicKeys(); - if (!cachedPublicKeys.isEmpty()) { - QString key = cachedPublicKeys[0]; - QJsonObject transaction; - transaction["certificate_id"] = asset_id; - transaction["place_name"] = location; - if (alsoUpdateSiblings) { - transaction["also_update_siblings"] = true; - } - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); - } else { - qDebug(commerce) << "User attempted to update the location of a certificate, but cachedPublicKeys was empty!"; - } - } -} - -void Ledger::certificateInfoSuccess(QNetworkReply* reply) { - auto wallet = DependencyManager::get(); - auto accountManager = DependencyManager::get(); - - QByteArray response = reply->readAll(); - QJsonObject replyObject = QJsonDocument::fromJson(response).object(); - - QStringList keys = wallet->listPublicKeys(); - if (keys.count() != 0) { - QJsonObject data = replyObject["data"].toObject(); - if (data["transfer_recipient_key"].toString() == keys[0]) { - replyObject.insert("isMyCert", true); - } - } - qInfo(commerce) << "certificateInfo" << "response" << QJsonDocument(replyObject).toJson(QJsonDocument::Compact); - emit certificateInfoResult(replyObject); -} -void Ledger::certificateInfoFailure(QNetworkReply* reply) { - emit certificateInfoResult(failResponse("certificateInfo", reply)); -} -void Ledger::certificateInfo(const QString& certificateId) { - QString endpoint = "proof_of_purchase_status/transfer"; - QJsonObject request; - request["certificate_id"] = certificateId; - send(endpoint, "certificateInfoSuccess", "certificateInfoFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::None, request); -} - -void Ledger::transferAssetToNode(const QString& hfc_key, const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage) { - QJsonObject transaction; - transaction["public_key"] = hfc_key; - transaction["node_id"] = nodeID; - transaction["quantity"] = amount; - transaction["message"] = optionalMessage; - transaction["place_name"] = DependencyManager::get()->getPlaceName(); - if (!certificateID.isEmpty()) { - transaction["certificate_id"] = certificateID; - } - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - if (certificateID.isEmpty()) { - signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_node", "transferAssetToNodeSuccess", "transferAssetToNodeFailure"); - } else { - signedSend("transaction", transactionString, hfc_key, "transfer_asset_to_node", "transferAssetToNodeSuccess", "transferAssetToNodeFailure"); - } -} - -void Ledger::transferAssetToUsername(const QString& hfc_key, const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage) { - QJsonObject transaction; - transaction["public_key"] = hfc_key; - transaction["username"] = username; - transaction["quantity"] = amount; - transaction["message"] = optionalMessage; - transaction["place_name"] = DependencyManager::get()->getPlaceName(); - if (!certificateID.isEmpty()) { - transaction["certificate_id"] = certificateID; - } - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - if (certificateID.isEmpty()) { - signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_user", "transferAssetToUsernameSuccess", "transferAssetToUsernameFailure"); - } else { - signedSend("transaction", transactionString, hfc_key, "transfer_asset_to_user", "transferAssetToUsernameSuccess", "transferAssetToUsernameFailure"); - } -} - -void Ledger::authorizeAssetTransfer(const QString& hfc_key, const QString& couponID, const QString& certificateID, const int& amount, const QString& optionalMessage) { - QJsonObject transaction; - transaction["public_key"] = hfc_key; - transaction["coupon_id"] = couponID; - transaction["quantity"] = amount; - transaction["message"] = optionalMessage; - if (!certificateID.isEmpty()) { - transaction["certificate_id"] = certificateID; - } - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - signedSend("transaction", transactionString, hfc_key, "authorize", "authorizeAssetTransferSuccess", "authorizeAssetTransferFailure"); -} - -void Ledger::alreadyOwned(const QString& marketplaceId) { - auto wallet = DependencyManager::get(); - QString endpoint = "already_owned"; - QJsonObject request; - QStringList cachedPublicKeys = wallet->listPublicKeys(); - if (!cachedPublicKeys.isEmpty()) { - request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); - request["marketplace_item_id"] = marketplaceId; - send(endpoint, "alreadyOwnedSuccess", "alreadyOwnedFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request); - } else { - qDebug(commerce) << "User attempted to use the alreadyOwned endpoint, but cachedPublicKeys was empty!"; - } -} - -void Ledger::getAvailableUpdates(const QString& itemId, const int& pageNumber, const int& itemsPerPage) { - auto wallet = DependencyManager::get(); - QString endpoint = "available_updates"; - QJsonObject request; - request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); - if (!itemId.isEmpty()) { - request["marketplace_item_id"] = itemId; - } - request["per_page"] = itemsPerPage; - request["page"] = pageNumber; - send(endpoint, "availableUpdatesSuccess", "availableUpdatesFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request); -} - -void Ledger::updateItem(const QString& hfc_key, const QString& certificate_id) { - QJsonObject transaction; - transaction["public_key"] = hfc_key; - transaction["certificate_id"] = certificate_id; - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - signedSend("transaction", transactionString, hfc_key, "update_item", "updateItemSuccess", "updateItemFailure"); -} diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h deleted file mode 100644 index 64528e617d6..00000000000 --- a/interface/src/commerce/Ledger.h +++ /dev/null @@ -1,110 +0,0 @@ -// -// Ledger.h -// interface/src/commerce -// -// Bottlenecks all interaction with the blockchain or other ledger system. -// -// Created by Howard Stearns on 8/4/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_Ledger_h -#define hifi_Ledger_h - -#include -#include -#include -#include -#include "AccountManager.h" - - -class Ledger : public QObject, public Dependency { - Q_OBJECT - SINGLETON_DEPENDENCY - -public: - void buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure = false); - bool receiveAt(const QString& hfc_key, const QString& signing_key, const QByteArray& locker); - bool receiveAt(); - void balance(const QStringList& keys); - void inventory(const QString& editionFilter, const QString& typeFilter, const QString& titleFilter, const int& page, const int& perPage); - void history(const QStringList& keys, const int& pageNumber, const int& itemsPerPage); - void account(); - void updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings = false, const bool controlledFailure = false); - void certificateInfo(const QString& certificateId); - void transferAssetToNode(const QString& hfc_key, const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage); - void transferAssetToUsername(const QString& hfc_key, const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage); - void authorizeAssetTransfer(const QString& hfc_key, const QString& couponID, const QString& certificateID, const int& amount, const QString& optionalMessage); - void alreadyOwned(const QString& marketplaceId); - void getAvailableUpdates(const QString& itemId = "", const int& pageNumber = 1, const int& itemsPerPage = 10); - void updateItem(const QString& hfc_key, const QString& certificate_id); - - enum CertificateStatus { - CERTIFICATE_STATUS_UNKNOWN = 0, - CERTIFICATE_STATUS_VERIFICATION_SUCCESS, - CERTIFICATE_STATUS_VERIFICATION_TIMEOUT, - CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED, - CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED, - }; - -signals: - void buyResult(QJsonObject result); - void receiveAtResult(QJsonObject result); - void balanceResult(QJsonObject result); - void inventoryResult(QJsonObject result); - void historyResult(QJsonObject result); - void accountResult(QJsonObject result); - void locationUpdateResult(QJsonObject result); - void certificateInfoResult(QJsonObject result); - void transferAssetToNodeResult(QJsonObject result); - void transferAssetToUsernameResult(QJsonObject result); - void authorizeAssetTransferResult(QJsonObject result); - void alreadyOwnedResult(QJsonObject result); - void availableUpdatesResult(QJsonObject result); - void updateItemResult(QJsonObject result); - - void updateCertificateStatus(const EntityItemID& entityID, uint certStatus); - -public slots: - void buySuccess(QNetworkReply* reply); - void buyFailure(QNetworkReply* reply); - void receiveAtSuccess(QNetworkReply* reply); - void receiveAtFailure(QNetworkReply* reply); - void balanceSuccess(QNetworkReply* reply); - void balanceFailure(QNetworkReply* reply); - void inventorySuccess(QNetworkReply* reply); - void inventoryFailure(QNetworkReply* reply); - void historySuccess(QNetworkReply* reply); - void historyFailure(QNetworkReply* reply); - void accountSuccess(QNetworkReply* reply); - void accountFailure(QNetworkReply* reply); - void updateLocationSuccess(QNetworkReply* reply); - void updateLocationFailure(QNetworkReply* reply); - void certificateInfoSuccess(QNetworkReply* reply); - void certificateInfoFailure(QNetworkReply* reply); - void transferAssetToNodeSuccess(QNetworkReply* reply); - void transferAssetToNodeFailure(QNetworkReply* reply); - void transferAssetToUsernameSuccess(QNetworkReply* reply); - void transferAssetToUsernameFailure(QNetworkReply* reply); - void authorizeAssetTransferSuccess(QNetworkReply* reply); - void authorizeAssetTransferFailure(QNetworkReply* reply); - void alreadyOwnedSuccess(QNetworkReply* reply); - void alreadyOwnedFailure(QNetworkReply* reply); - void availableUpdatesSuccess(QNetworkReply* reply); - void availableUpdatesFailure(QNetworkReply* reply); - void updateItemSuccess(QNetworkReply* reply); - void updateItemFailure(QNetworkReply* reply); - -private: - QJsonObject apiResponse(const QString& label, QNetworkReply* reply); - QJsonObject failResponse(const QString& label, QNetworkReply* reply); - void send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, QJsonObject request); - void keysQuery(const QString& endpoint, const QString& success, const QString& fail, QJsonObject& extraRequestParams); - void keysQuery(const QString& endpoint, const QString& success, const QString& fail); - void signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure = false); -}; - -#endif // hifi_Ledger_h diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp deleted file mode 100644 index 47105e0f3a2..00000000000 --- a/interface/src/commerce/QmlCommerce.cpp +++ /dev/null @@ -1,471 +0,0 @@ -// -// QmlCommerce.cpp -// interface/src/commerce -// -// Created by Howard Stearns on 8/4/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "QmlCommerce.h" -#include "CommerceLogging.h" -#include "Application.h" -#include "DependencyManager.h" -#include "Ledger.h" -#include "Wallet.h" -#include -#include -#include -#include -#include -#include "scripting/HMDScriptingInterface.h" - -QmlCommerce::QmlCommerce() : - _appsPath(PathUtils::getAppDataPath() + "Apps/") -{ - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - connect(ledger.data(), &Ledger::buyResult, this, &QmlCommerce::buyResult); - connect(ledger.data(), &Ledger::balanceResult, this, &QmlCommerce::balanceResult); - connect(ledger.data(), &Ledger::inventoryResult, this, &QmlCommerce::inventoryResult); - connect(wallet.data(), &Wallet::securityImageResult, this, &QmlCommerce::securityImageResult); - connect(ledger.data(), &Ledger::historyResult, this, &QmlCommerce::historyResult); - connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult); - connect(ledger.data(), &Ledger::accountResult, this, &QmlCommerce::accountResult); - connect(wallet.data(), &Wallet::walletStatusResult, this, &QmlCommerce::walletStatusResult); - connect(ledger.data(), &Ledger::certificateInfoResult, this, &QmlCommerce::certificateInfoResult); - connect(ledger.data(), &Ledger::alreadyOwnedResult, this, &QmlCommerce::alreadyOwnedResult); - connect(ledger.data(), &Ledger::updateCertificateStatus, this, &QmlCommerce::updateCertificateStatus); - connect(ledger.data(), &Ledger::transferAssetToNodeResult, this, &QmlCommerce::transferAssetToNodeResult); - connect(ledger.data(), &Ledger::transferAssetToUsernameResult, this, &QmlCommerce::transferAssetToUsernameResult); - connect(ledger.data(), &Ledger::authorizeAssetTransferResult, this, &QmlCommerce::authorizeAssetTransferResult); - connect(ledger.data(), &Ledger::availableUpdatesResult, this, &QmlCommerce::availableUpdatesResult); - connect(ledger.data(), &Ledger::updateItemResult, this, &QmlCommerce::updateItemResult); - - auto accountManager = DependencyManager::get(); - connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() { setPassphrase(""); }); -} - - -void QmlCommerce::openSystemApp(const QString& appName) { - static const QMap systemApps { - {"GOTO", "hifi/tablet/TabletAddressDialog.qml"}, - {"PEOPLE", "hifi/Pal.qml"}, - {"WALLET", "hifi/commerce/wallet/Wallet.qml"}, - {"MARKET", "hifi/commerce/marketplace/Marketplace.qml"} - }; - - static const QMap systemInject{ - }; - - - auto tablet = dynamic_cast( - DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); - - QMap::const_iterator appPathIter = systemApps.find(appName); - if (appPathIter != systemApps.end()) { - if (appPathIter->contains(".qml", Qt::CaseInsensitive)) { - tablet->loadQMLSource(*appPathIter); - } - else if (appPathIter->contains(".html", Qt::CaseInsensitive)) { - QMap::const_iterator injectIter = systemInject.find(appName); - if (appPathIter == systemInject.end()) { - tablet->gotoWebScreen(MetaverseAPI::getCurrentMetaverseServerURL().toString() + *appPathIter); - } - else { - QString inject = "file:///" + qApp->applicationDirPath() + *injectIter; - tablet->gotoWebScreen(MetaverseAPI::getCurrentMetaverseServerURL().toString() + *appPathIter, inject); - } - } - else { - qCDebug(commerce) << "Attempted to open unknown type of URL!"; - return; - } - } - else { - qCDebug(commerce) << "Attempted to open unknown APP!"; - return; - } - - DependencyManager::get()->openTablet(); -} - - -void QmlCommerce::getWalletStatus() { - auto wallet = DependencyManager::get(); - wallet->getWalletStatus(); -} - -void QmlCommerce::getLoginStatus() { - emit loginStatusResult(DependencyManager::get()->isLoggedIn()); -} - -void QmlCommerce::getKeyFilePathIfExists() { - auto wallet = DependencyManager::get(); - emit keyFilePathIfExistsResult(wallet->getKeyFilePath()); -} - -bool QmlCommerce::copyKeyFileFrom(const QString& pathname) { - auto wallet = DependencyManager::get(); - return wallet->copyKeyFileFrom(pathname); -} - -void QmlCommerce::getWalletAuthenticatedStatus() { - auto wallet = DependencyManager::get(); - emit walletAuthenticatedStatusResult(wallet->walletIsAuthenticatedWithPassphrase()); -} - -void QmlCommerce::getSecurityImage() { - auto wallet = DependencyManager::get(); - wallet->getSecurityImage(); -} - -void QmlCommerce::chooseSecurityImage(const QString& imageFile) { - auto wallet = DependencyManager::get(); - wallet->chooseSecurityImage(imageFile); -} - -void QmlCommerce::buy(const QString& assetId, int cost, const bool controlledFailure) { - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - QStringList keys = wallet->listPublicKeys(); - if (keys.count() == 0) { - QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } }; - return emit buyResult(result); - } - QString key = keys[0]; - // For now, we receive at the same key that pays for it. - ledger->buy(key, cost, assetId, key, controlledFailure); -} - -void QmlCommerce::balance() { - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - QStringList cachedPublicKeys = wallet->listPublicKeys(); - if (!cachedPublicKeys.isEmpty()) { - ledger->balance(cachedPublicKeys); - } -} - -void QmlCommerce::inventory(const QString& editionFilter, - const QString& typeFilter, - const QString& titleFilter, - const int& page, - const int& perPage) { - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - QStringList cachedPublicKeys = wallet->listPublicKeys(); - if (!cachedPublicKeys.isEmpty()) { - ledger->inventory(editionFilter, typeFilter, titleFilter, page, perPage); - } -} - -void QmlCommerce::history(const int& pageNumber, const int& itemsPerPage) { - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - QStringList cachedPublicKeys = wallet->listPublicKeys(); - if (!cachedPublicKeys.isEmpty()) { - ledger->history(cachedPublicKeys, pageNumber, itemsPerPage); - } -} - -void QmlCommerce::changePassphrase(const QString& oldPassphrase, const QString& newPassphrase) { - auto wallet = DependencyManager::get(); - if (wallet->getPassphrase()->isEmpty()) { - emit changePassphraseStatusResult(wallet->setPassphrase(newPassphrase)); - } else if (wallet->getPassphrase() == oldPassphrase && !newPassphrase.isEmpty()) { - emit changePassphraseStatusResult(wallet->changePassphrase(newPassphrase)); - } else { - emit changePassphraseStatusResult(false); - } -} - -void QmlCommerce::setSoftReset() { - auto wallet = DependencyManager::get(); - wallet->setSoftReset(); -} - -void QmlCommerce::clearWallet() { - auto wallet = DependencyManager::get(); - wallet->clear(); -} - -void QmlCommerce::setPassphrase(const QString& passphrase) { - auto wallet = DependencyManager::get(); - wallet->setPassphrase(passphrase); - getWalletAuthenticatedStatus(); -} - -void QmlCommerce::generateKeyPair() { - auto wallet = DependencyManager::get(); - wallet->generateKeyPair(); - getWalletAuthenticatedStatus(); -} - -void QmlCommerce::account() { - auto ledger = DependencyManager::get(); - ledger->account(); -} - -void QmlCommerce::certificateInfo(const QString& certificateId) { - auto ledger = DependencyManager::get(); - ledger->certificateInfo(certificateId); -} - -void QmlCommerce::transferAssetToNode(const QString& nodeID, - const QString& certificateID, - const int& amount, - const QString& optionalMessage) { - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - QStringList keys = wallet->listPublicKeys(); - if (keys.count() == 0) { - QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } }; - return emit transferAssetToNodeResult(result); - } - QString key = keys[0]; - ledger->transferAssetToNode(key, nodeID, certificateID, amount, optionalMessage); -} - -void QmlCommerce::transferAssetToUsername(const QString& username, - const QString& certificateID, - const int& amount, - const QString& optionalMessage) { - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - QStringList keys = wallet->listPublicKeys(); - if (keys.count() == 0) { - QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } }; - return emit transferAssetToUsernameResult(result); - } - QString key = keys[0]; - ledger->transferAssetToUsername(key, username, certificateID, amount, optionalMessage); -} - -void QmlCommerce::authorizeAssetTransfer(const QString& couponID, - const QString& certificateID, - const int& amount, - const QString& optionalMessage) { - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - QStringList keys = wallet->listPublicKeys(); - if (keys.count() == 0) { - QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } }; - return emit authorizeAssetTransferResult(result); - } - QString key = keys[0]; - ledger->authorizeAssetTransfer(key, couponID, certificateID, amount, optionalMessage); -} - -void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID, const QString& itemName) { - if (!certificateID.isEmpty()) { - auto ledger = DependencyManager::get(); - ledger->updateLocation( - certificateID, - DependencyManager::get()->getPlaceName(), - true); - } - qApp->replaceDomainContent(itemHref, itemName); - QJsonObject messageProperties = { - { "status", "SuccessfulRequestToReplaceContent" }, - { "content_set_url", itemHref } }; - UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); - emit contentSetChanged(itemHref); -} - -void QmlCommerce::alreadyOwned(const QString& marketplaceId) { - auto ledger = DependencyManager::get(); - ledger->alreadyOwned(marketplaceId); -} - -QString QmlCommerce::getInstalledApps(const QString& justInstalledAppID) { - QString installedAppsFromMarketplace; - QStringList runningScripts = DependencyManager::get()->getRunningScripts(); - - QDir directory(_appsPath); - QStringList apps = directory.entryList(QStringList("*.app.json")); - foreach (QString appFileName, apps) { - // If we were supplied a "justInstalledAppID" argument, that means we're entering this function - // to get the new list of installed apps immediately after installing an app. - // In that case, the app we installed may not yet have its associated script running - - // that task is asynchronous and takes a nonzero amount of time. This is especially true - // for apps that are not in Interface's script cache. - // Thus, we protect against deleting the .app.json from the user's disk (below) - // by skipping that check for the app we just installed. - if ((justInstalledAppID != "") && ((justInstalledAppID + ".app.json") == appFileName)) { - installedAppsFromMarketplace += appFileName + ","; - continue; - } - - QFile appFile(_appsPath + appFileName); - if (appFile.open(QIODevice::ReadOnly)) { - QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll()); - - appFile.close(); - - QJsonObject appFileJsonObject = appFileJsonDocument.object(); - QString scriptURL = appFileJsonObject["scriptURL"].toString(); - - // If the script .app.json is on the user's local disk but the associated script isn't running - // for some reason (i.e. the user stopped it from Running Scripts), - // delete the .app.json from the user's local disk. - if (!runningScripts.contains(scriptURL)) { - if (!appFile.remove()) { - qCWarning(commerce) << "Couldn't delete local .app.json file (app's script isn't running). App filename is:" - << appFileName; - } - } else { - installedAppsFromMarketplace += appFileName; - installedAppsFromMarketplace += ","; - } - } else { - qCDebug(commerce) << "Couldn't open local .app.json file for reading."; - } - } - - return installedAppsFromMarketplace; -} - -bool QmlCommerce::installApp(const QString& itemHref, const bool& alsoOpenImmediately) { - if (!QDir(_appsPath).exists()) { - if (!QDir().mkdir(_appsPath)) { - qCDebug(commerce) << "Couldn't make _appsPath directory."; - return false; - } - } - - QUrl appHref(itemHref); - - auto request = - DependencyManager::get()->createResourceRequest(this, appHref, true, -1, "QmlCommerce::installApp"); - - if (!request) { - qCDebug(commerce) << "Couldn't create resource request for app."; - return false; - } - - connect(request, &ResourceRequest::finished, this, [=]() { - if (request->getResult() != ResourceRequest::Success) { - qCDebug(commerce) << "Failed to get .app.json file from remote."; - return false; - } - - // Copy the .app.json to the apps directory inside %AppData%/High Fidelity/Interface - auto requestData = request->getData(); - QFile appFile(_appsPath + "/" + appHref.fileName()); - if (!appFile.open(QIODevice::WriteOnly)) { - qCDebug(commerce) << "Couldn't open local .app.json file for creation."; - return false; - } - if (appFile.write(requestData) == -1) { - qCDebug(commerce) << "Couldn't write to local .app.json file."; - return false; - } - // Close the file - appFile.close(); - - // Read from the returned datastream to know what .js to add to Running Scripts - QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(requestData); - QJsonObject appFileJsonObject = appFileJsonDocument.object(); - QString scriptUrl = appFileJsonObject["scriptURL"].toString(); - - // Don't try to re-load (install) a script if it's already running - QStringList runningScripts = DependencyManager::get()->getRunningScripts(); - if (!runningScripts.contains(scriptUrl)) { - if ((DependencyManager::get()->loadScript(scriptUrl.trimmed())).isNull()) { - qCDebug(commerce) << "Couldn't load script."; - return false; - } - - QFileInfo appFileInfo(appFile); - emit appInstalled(appFileInfo.baseName()); - } - - if (alsoOpenImmediately) { - QmlCommerce::openApp(itemHref); - } - - return true; - }); - request->send(); - return true; -} - -bool QmlCommerce::uninstallApp(const QString& itemHref) { - QUrl appHref(itemHref); - - // Read from the file to know what .js script to stop - QFile appFile(_appsPath + "/" + appHref.fileName()); - if (!appFile.open(QIODevice::ReadOnly)) { - qCDebug(commerce) - << "Couldn't open local .app.json file for deletion. Cannot continue with app uninstallation. App filename is:" - << appHref.fileName(); - return false; - } - QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll()); - QJsonObject appFileJsonObject = appFileJsonDocument.object(); - QString scriptUrl = appFileJsonObject["scriptURL"].toString(); - - if (!DependencyManager::get()->stopScript(scriptUrl.trimmed(), false)) { - qCWarning(commerce) << "Couldn't stop script during app uninstall. Continuing anyway."; - } - - // Delete the .app.json from the filesystem - // remove() closes the file first. - if (!appFile.remove()) { - qCWarning(commerce) << "Couldn't delete local .app.json file during app uninstall. Continuing anyway. App filename is:" - << appHref.fileName(); - } - - QFileInfo appFileInfo(appFile); - emit appUninstalled(appFileInfo.baseName()); - return true; -} - -bool QmlCommerce::openApp(const QString& itemHref) { - QUrl appHref(itemHref); - - // Read from the file to know what .html or .qml document to open - QFile appFile(_appsPath + "/" + appHref.fileName()); - if (!appFile.open(QIODevice::ReadOnly)) { - qCDebug(commerce) << "Couldn't open local .app.json file:" << appFile; - return false; - } - QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll()); - QJsonObject appFileJsonObject = appFileJsonDocument.object(); - QString homeUrl = appFileJsonObject["homeURL"].toString(); - - auto tablet = dynamic_cast( - DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); - if (homeUrl.contains(".qml", Qt::CaseInsensitive)) { - tablet->loadQMLSource(homeUrl); - } else if (homeUrl.contains(".html", Qt::CaseInsensitive)) { - tablet->gotoWebScreen(homeUrl); - } else { - qCDebug(commerce) << "Attempted to open unknown type of homeURL!"; - return false; - } - - DependencyManager::get()->openTablet(); - - return true; -} - -void QmlCommerce::getAvailableUpdates(const QString& itemId, const int& pageNumber, const int& itemsPerPage) { - auto ledger = DependencyManager::get(); - ledger->getAvailableUpdates(itemId, pageNumber, itemsPerPage); -} - -void QmlCommerce::updateItem(const QString& certificateId) { - auto ledger = DependencyManager::get(); - auto wallet = DependencyManager::get(); - QStringList keys = wallet->listPublicKeys(); - if (keys.count() == 0) { - QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } }; - return emit updateItemResult(result); - } - QString key = keys[0]; - ledger->updateItem(key, certificateId); -} diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h deleted file mode 100644 index 713a5ee94f7..00000000000 --- a/interface/src/commerce/QmlCommerce.h +++ /dev/null @@ -1,107 +0,0 @@ -// -// QmlCommerce.h -// interface/src/commerce -// -// Guard for safe use of Commerce (Wallet, Ledger) by authorized QML. -// -// Created by Howard Stearns on 8/4/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#pragma once -#ifndef hifi_QmlCommerce_h -#define hifi_QmlCommerce_h - -#include - -#include - -#include -#include - -class QmlCommerce : public QObject, public Dependency { - Q_OBJECT - -public: - QmlCommerce(); - void openSystemApp(const QString& appPath); - -signals: - void walletStatusResult(uint walletStatus); - - void loginStatusResult(bool isLoggedIn); - void keyFilePathIfExistsResult(const QString& path); - void securityImageResult(bool exists); - void walletAuthenticatedStatusResult(bool isAuthenticated); - void changePassphraseStatusResult(bool changeSuccess); - - void buyResult(QJsonObject result); - // Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and - // because we can't scalably know of out-of-band changes (e.g., another machine interacting with the block chain). - void balanceResult(QJsonObject result); - void inventoryResult(QJsonObject result); - void historyResult(QJsonObject result); - void accountResult(QJsonObject result); - void certificateInfoResult(QJsonObject result); - void alreadyOwnedResult(QJsonObject result); - void availableUpdatesResult(QJsonObject result); - void updateItemResult(QJsonObject result); - - void updateCertificateStatus(const EntityItemID& entityID, uint certStatus); - - void transferAssetToNodeResult(QJsonObject result); - void transferAssetToUsernameResult(QJsonObject result); - void authorizeAssetTransferResult(QJsonObject result); - - void contentSetChanged(const QString& contentSetHref); - - void appInstalled(const QString& appID); - void appUninstalled(const QString& appID); - -protected: - Q_INVOKABLE void getWalletStatus(); - - Q_INVOKABLE void getLoginStatus(); - Q_INVOKABLE void getKeyFilePathIfExists(); - Q_INVOKABLE void getSecurityImage(); - Q_INVOKABLE void getWalletAuthenticatedStatus(); - Q_INVOKABLE bool copyKeyFileFrom(const QString& pathname); - - Q_INVOKABLE void chooseSecurityImage(const QString& imageFile); - Q_INVOKABLE void setPassphrase(const QString& passphrase); - Q_INVOKABLE void changePassphrase(const QString& oldPassphrase, const QString& newPassphrase); - Q_INVOKABLE void setSoftReset(); - Q_INVOKABLE void clearWallet(); - - Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false); - Q_INVOKABLE void balance(); - Q_INVOKABLE void inventory(const QString& editionFilter = QString(), const QString& typeFilter = QString(), const QString& titleFilter = QString(), const int& page = 1, const int& perPage = 20); - Q_INVOKABLE void history(const int& pageNumber, const int& itemsPerPage = 100); - Q_INVOKABLE void generateKeyPair(); - Q_INVOKABLE void account(); - - Q_INVOKABLE void certificateInfo(const QString& certificateId); - Q_INVOKABLE void alreadyOwned(const QString& marketplaceId); - - Q_INVOKABLE void transferAssetToNode(const QString& nodeID, const QString& certificateID, const int& amount, const QString& optionalMessage); - Q_INVOKABLE void transferAssetToUsername(const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage); - Q_INVOKABLE void authorizeAssetTransfer(const QString& couponID, const QString& certificateID, const int& amount, const QString& optionalMessage); - - Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID, const QString& itemName); - - Q_INVOKABLE QString getInstalledApps(const QString& justInstalledAppID = ""); - Q_INVOKABLE bool installApp(const QString& appHref, const bool& alsoOpenImmediately = false); - Q_INVOKABLE bool uninstallApp(const QString& appHref); - Q_INVOKABLE bool openApp(const QString& appHref); - - Q_INVOKABLE void getAvailableUpdates(const QString& itemId = "", const int& pageNumber = 1, const int& itemsPerPage = 10); - Q_INVOKABLE void updateItem(const QString& certificateId); - -private: - const QString _appsPath; -}; - -#endif // hifi_QmlCommerce_h diff --git a/interface/src/commerce/QmlMarketplace.cpp b/interface/src/commerce/QmlMarketplace.cpp deleted file mode 100644 index 8197b20275d..00000000000 --- a/interface/src/commerce/QmlMarketplace.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// -// QmlMarketplace.cpp -// interface/src/commerce -// -// Guard for safe use of Marketplace by authorized QML. -// -// Created by Roxanne Skelly on 1/18/19. -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - - -#include "QmlMarketplace.h" -#include "CommerceLogging.h" -#include "Application.h" -#include "DependencyManager.h" -#include -#include -#include -#include -#include "scripting/HMDScriptingInterface.h" - -#define ApiHandler(NAME) void QmlMarketplace::NAME##Success(QNetworkReply* reply) { emit NAME##Result(apiResponse(#NAME, reply)); } -#define FailHandler(NAME) void QmlMarketplace::NAME##Failure(QNetworkReply* reply) { emit NAME##Result(failResponse(#NAME, reply)); } -#define Handler(NAME) ApiHandler(NAME) FailHandler(NAME) -Handler(getMarketplaceItems) -Handler(getMarketplaceItem) -Handler(marketplaceItemLike) -Handler(getMarketplaceCategories) - -QmlMarketplace::QmlMarketplace() { -} - -void QmlMarketplace::openMarketplace(const QString& marketplaceItemId) { - auto tablet = dynamic_cast( - DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); - tablet->loadQMLSource("hifi/commerce/marketplace/Marketplace.qml"); - DependencyManager::get()->openTablet(); - if (!marketplaceItemId.isEmpty()) { - tablet->sendToQml(QVariantMap({ { "method", "marketplace_openItem" }, { "itemId", marketplaceItemId } })); - } -} - -void QmlMarketplace::getMarketplaceItems( - const QString& q, - const QString& view, - const QString& category, - const QString& adminFilter, - const QString& adminFilterCost, - const QString& sort, - bool isAscending, - bool isFree, - int page, - int perPage) { - - QString endpoint = "items"; - QUrlQuery request; - request.addQueryItem("q", q); - request.addQueryItem("view", view); - request.addQueryItem("category", category); - request.addQueryItem("adminFilter", adminFilter); - request.addQueryItem("adminFilterCost", adminFilterCost); - request.addQueryItem("sort", sort); - request.addQueryItem("sort_dir", isAscending ? "asc" : "desc"); - if (isFree) { - request.addQueryItem("isFree", "true"); - } - request.addQueryItem("page", QString::number(page)); - request.addQueryItem("perPage", QString::number(perPage)); - send(endpoint, "getMarketplaceItemsSuccess", "getMarketplaceItemsFailure", QNetworkAccessManager::GetOperation, AccountManagerAuth::Optional, request); -} - -void QmlMarketplace::getMarketplaceItem(const QString& marketplaceItemId) { - QString endpoint = QString("items/") + marketplaceItemId; - send(endpoint, "getMarketplaceItemSuccess", "getMarketplaceItemFailure", QNetworkAccessManager::GetOperation, AccountManagerAuth::Optional); -} - -void QmlMarketplace::marketplaceItemLike(const QString& marketplaceItemId, const bool like) { - QString endpoint = QString("items/") + marketplaceItemId + "/like"; - send(endpoint, "marketplaceItemLikeSuccess", "marketplaceItemLikeFailure", like ? QNetworkAccessManager::PostOperation : QNetworkAccessManager::DeleteOperation, AccountManagerAuth::Required); -} - -void QmlMarketplace::getMarketplaceCategories() { - QString endpoint = "categories"; - send(endpoint, "getMarketplaceCategoriesSuccess", "getMarketplaceCategoriesFailure", QNetworkAccessManager::GetOperation, AccountManagerAuth::None); -} - - -void QmlMarketplace::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, const QUrlQuery & request) { - auto accountManager = DependencyManager::get(); - const QString URL = "/api/v1/marketplace/"; - JSONCallbackParameters callbackParams(this, success, fail); - - accountManager->sendRequest(URL + endpoint + "?" + request.toString(), - authType, - method, - callbackParams, - QByteArray(), - NULL, - QVariantMap()); - -} - -QJsonObject QmlMarketplace::apiResponse(const QString& label, QNetworkReply* reply) { - QByteArray response = reply->readAll(); - QJsonObject data = QJsonDocument::fromJson(response).object(); -#if defined(DEV_BUILD) // Don't expose user's personal data in the wild. But during development this can be handy. - qInfo(commerce) << label << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact); -#endif - return data; -} - -// Non-200 responses are not json: -QJsonObject QmlMarketplace::failResponse(const QString& label, QNetworkReply* reply) { - QString response = reply->readAll(); - qWarning(commerce) << "FAILED" << label << response; - - // tempResult will be NULL if the response isn't valid JSON. - QJsonDocument tempResult = QJsonDocument::fromJson(response.toLocal8Bit()); - if (tempResult.isNull()) { - QJsonObject result - { - { "status", "fail" }, - { "message", response } - }; - return result; - } - else { - return tempResult.object(); - } -} \ No newline at end of file diff --git a/interface/src/commerce/QmlMarketplace.h b/interface/src/commerce/QmlMarketplace.h deleted file mode 100644 index 76b3d414491..00000000000 --- a/interface/src/commerce/QmlMarketplace.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// QmlMarketplace.h -// interface/src/commerce -// -// Guard for safe use of Marketplace by authorized QML. -// -// Created by Roxanne Skelly on 1/18/19. -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#pragma once -#ifndef hifi_QmlMarketplace_h -#define hifi_QmlMarketplace_h - -#include - -#include -#include -#include "AccountManager.h" - -class QmlMarketplace : public QObject { - Q_OBJECT - -public: - QmlMarketplace(); - -public slots: - void getMarketplaceItemsSuccess(QNetworkReply* reply); - void getMarketplaceItemsFailure(QNetworkReply* reply); - void getMarketplaceItemSuccess(QNetworkReply* reply); - void getMarketplaceItemFailure(QNetworkReply* reply); - void getMarketplaceCategoriesSuccess(QNetworkReply* reply); - void getMarketplaceCategoriesFailure(QNetworkReply* reply); - void marketplaceItemLikeSuccess(QNetworkReply* reply); - void marketplaceItemLikeFailure(QNetworkReply* reply); - -protected: - Q_INVOKABLE void openMarketplace(const QString& marketplaceItemId = QString()); - Q_INVOKABLE void getMarketplaceItems( - const QString& q = QString(), - const QString& view = QString(), - const QString& category = QString(), - const QString& adminFilter = QString("published"), - const QString& adminFilterCost = QString(), - const QString& sort = QString(), - bool isAscending = false, - bool isFree = false, - int page = 1, - int perPage = 20); - Q_INVOKABLE void getMarketplaceItem(const QString& marketplaceItemId); - Q_INVOKABLE void marketplaceItemLike(const QString& marketplaceItemId, const bool like = true); - Q_INVOKABLE void getMarketplaceCategories(); - -signals: - void getMarketplaceItemsResult(QJsonObject result); - void getMarketplaceItemResult(QJsonObject result); - void getMarketplaceCategoriesResult(QJsonObject result); - void marketplaceItemLikeResult(QJsonObject result); - -private: - void send(const QString& endpoint, - const QString& success, - const QString& fail, - QNetworkAccessManager::Operation method, - AccountManagerAuth::Type authType, - const QUrlQuery& request = QUrlQuery()); - QJsonObject apiResponse(const QString& label, QNetworkReply* reply); - QJsonObject failResponse(const QString& label, QNetworkReply* reply); -}; - -#endif // hifi_QmlMarketplace_h diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp deleted file mode 100644 index c4498741174..00000000000 --- a/interface/src/commerce/Wallet.cpp +++ /dev/null @@ -1,950 +0,0 @@ -// -// Wallet.cpp -// interface/src/commerce -// -// Created by Howard Stearns on 8/4/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "Wallet.h" - -#include -#include -#include -#include -#include -#include -#include -// I know, right? But per https://www.openssl.org/docs/faq.html -// this avoids OPENSSL_Uplink(00007FF847238000,08): no OPENSSL_Applink -// at runtime. -#ifdef Q_OS_WIN -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "Application.h" -#include "CommerceLogging.h" -#include "Ledger.h" -#include "ui/SecurityImageProvider.h" -#include "scripting/HMDScriptingInterface.h" - -namespace { - const char* KEY_FILE = "hifikey"; - const char* INSTRUCTIONS_FILE = "backup_instructions.html"; - const char* IMAGE_HEADER = "-----BEGIN SECURITY IMAGE-----\n"; - const char* IMAGE_FOOTER = "-----END SECURITY IMAGE-----\n"; - - void initialize() { - static bool initialized = false; - if (!initialized) { - SSL_load_error_strings(); - SSL_library_init(); - OpenSSL_add_all_algorithms(); - initialized = true; - } - } - - QString keyFilePath() { - auto accountManager = DependencyManager::get(); - return PathUtils::getAppDataFilePath(QString("%1.%2").arg(accountManager->getAccountInfo().getUsername(), KEY_FILE)); - } - - // use the cached _passphrase if it exists, otherwise we need to prompt - int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) { - // just return a hardcoded pwd for now - auto wallet = DependencyManager::get(); - auto passphrase = wallet->getPassphrase(); - if (passphrase && !passphrase->isEmpty()) { - QString saltedPassphrase(*passphrase); - saltedPassphrase.append(wallet->getSalt()); - strcpy(password, saltedPassphrase.toUtf8().constData()); - return static_cast(passphrase->size()); - } else { - // this shouldn't happen - so lets log it to tell us we have - // a problem with the flow... - qCCritical(commerce) << "no cached passphrase while decrypting!"; - return 0; - } - } - - EC_KEY* readKeys(QString filename) { - QFile file(filename); - EC_KEY* key = NULL; - if (file.open(QFile::ReadOnly)) { - // file opened successfully - qCDebug(commerce) << "opened key file" << filename; - - QByteArray pemKeyBytes = file.readAll(); - BIO* bufio = BIO_new_mem_buf((void*)pemKeyBytes.constData(), pemKeyBytes.length()); - if ((key = PEM_read_bio_EC_PUBKEY(bufio, NULL, NULL, NULL))) { - // now read private key - - qCDebug(commerce) << "read public key"; - - if ((key = PEM_read_bio_ECPrivateKey(bufio, &key, passwordCallback, NULL))) { - qCDebug(commerce) << "read private key"; - } else { - qCDebug(commerce) << "failed to read private key"; - } - } else { - qCDebug(commerce) << "failed to read public key"; - } - BIO_free(bufio); - file.close(); - } else { - qCDebug(commerce) << "failed to open key file" << filename; - } - return key; - } - - bool writeKeys(QString filename, EC_KEY* keys) { - BIO* bio = BIO_new(BIO_s_mem()); - bool retval = false; - if (!PEM_write_bio_EC_PUBKEY(bio, keys)) { - BIO_free(bio); - qCCritical(commerce) << "failed to write public key"; - return retval; - } - - if (!PEM_write_bio_ECPrivateKey(bio, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) { - BIO_free(bio); - qCCritical(commerce) << "failed to write private key"; - return retval; - } - - QFile file(filename); - if (file.open(QIODevice::WriteOnly)) { - const char* bio_data; - long bio_size = BIO_get_mem_data(bio, &bio_data); - - QByteArray keyBytes(bio_data, bio_size); - file.write(keyBytes); - retval = true; - qCDebug(commerce) << "wrote keys successfully"; - file.close(); - } else { - qCDebug(commerce) << "failed to open key file" << filename; - } - BIO_free(bio); - return retval; - } - - QPair generateECKeypair() { - EC_KEY* keyPair = EC_KEY_new_by_curve_name(NID_secp256k1); - QPair retval {}; - - EC_KEY_set_asn1_flag(keyPair, OPENSSL_EC_NAMED_CURVE); - if (!EC_KEY_generate_key(keyPair)) { - qCDebug(commerce) << "Error generating EC Keypair -" << ERR_get_error(); - return retval; - } - - // grab the public key and private key from the file - unsigned char* publicKeyDER = NULL; - int publicKeyLength = i2d_EC_PUBKEY(keyPair, &publicKeyDER); - - unsigned char* privateKeyDER = NULL; - int privateKeyLength = i2d_ECPrivateKey(keyPair, &privateKeyDER); - - if (publicKeyLength <= 0 || privateKeyLength <= 0) { - qCDebug(commerce) << "Error getting DER public or private key from EC struct -" << ERR_get_error(); - - // cleanup the EC struct - EC_KEY_free(keyPair); - - // cleanup the public and private key DER data, if required - if (publicKeyLength > 0) { - OPENSSL_free(publicKeyDER); - } - - if (privateKeyLength > 0) { - OPENSSL_free(privateKeyDER); - } - - return retval; - } - - if (!writeKeys(keyFilePath(), keyPair)) { - qCDebug(commerce) << "couldn't save keys!"; - return retval; - } - - EC_KEY_free(keyPair); - - // prepare the return values. TODO: Fix this - we probably don't really even want the - // private key at all (better to read it when we need it?). Or maybe we do, when we have - // multiple keys? - retval.first = new QByteArray(reinterpret_cast(publicKeyDER), publicKeyLength); - retval.second = new QByteArray(reinterpret_cast(privateKeyDER), privateKeyLength); - - // cleanup the publicKeyDER and publicKeyDER data - OPENSSL_free(publicKeyDER); - OPENSSL_free(privateKeyDER); - return retval; - } - // END copied code (which will soon change) - - // the public key can just go into a byte array - QByteArray readPublicKey(QString filename) { - QByteArray retval; - QFile file(filename); - if (file.open(QIODevice::ReadOnly)) { - // file opened successfully - qCDebug(commerce) << "opened key file" << filename; - - QByteArray pemKeyBytes = file.readAll(); - BIO* bufio = BIO_new_mem_buf((void*)pemKeyBytes.constData(), pemKeyBytes.length()); - - EC_KEY* key = PEM_read_bio_EC_PUBKEY(bufio, NULL, NULL, NULL); - if (key) { - // file read successfully - unsigned char* publicKeyDER = NULL; - int publicKeyLength = i2d_EC_PUBKEY(key, &publicKeyDER); - // TODO: check for 0 length? - - // cleanup - EC_KEY_free(key); - - qCDebug(commerce) << "parsed public key file successfully"; - - QByteArray retval((char*)publicKeyDER, publicKeyLength); - OPENSSL_free(publicKeyDER); - BIO_free(bufio); - file.close(); - return retval; - } else { - qCDebug(commerce) << "couldn't parse" << filename; - } - BIO_free(bufio); - file.close(); - } else { - qCDebug(commerce) << "couldn't open" << filename; - } - return QByteArray(); - } - - // the private key should be read/copied into heap memory. For now, we need the EC_KEY struct - // so I'll return that. - EC_KEY* readPrivateKey(QString filename) { - QFile file(filename); - EC_KEY* key = NULL; - if (file.open(QIODevice::ReadOnly)) { - // file opened successfully - qCDebug(commerce) << "opened key file" << filename; - - QByteArray pemKeyBytes = file.readAll(); - BIO* bufio = BIO_new_mem_buf((void*)pemKeyBytes.constData(), pemKeyBytes.length()); - - if ((key = PEM_read_bio_ECPrivateKey(bufio, &key, passwordCallback, NULL))) { - qCDebug(commerce) << "parsed private key file successfully"; - - } else { - qCDebug(commerce) << "couldn't parse" << filename; - // if the passphrase is wrong, then let's not cache it - DependencyManager::get()->setPassphrase(""); - } - BIO_free(bufio); - file.close(); - } else { - qCDebug(commerce) << "couldn't open" << filename; - } - return key; - } - - // QT's QByteArray will convert to Base64 without any embedded newlines. This just - // writes it with embedded newlines, which is more readable. - void outputBase64WithNewlines(QFile& file, const QByteArray& b64Array) { - for (int i = 0; i < b64Array.size(); i += 64) { - file.write(b64Array.mid(i, 64)); - file.write("\n"); - } - } - - void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) { - // use the ones in the wallet - auto wallet = DependencyManager::get(); - memcpy(ivec, wallet->getIv(), 16); - memcpy(ckey, wallet->getCKey(), 32); - } - -} // close unnamed namespace - -Wallet::Wallet() { - auto nodeList = DependencyManager::get(); - auto ledger = DependencyManager::get(); - auto& packetReceiver = nodeList->getPacketReceiver(); - _passphrase = new QString(""); - - packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket"); - packetReceiver.registerListener(PacketType::ChallengeOwnershipRequest, this, "handleChallengeOwnershipPacket"); - - connect(ledger.data(), &Ledger::accountResult, this, [](QJsonObject result) { - auto wallet = DependencyManager::get(); - auto walletScriptingInterface = DependencyManager::get(); - uint status; - QString keyStatus = result.contains("data") ? result["data"].toObject()["keyStatus"].toString() : ""; - - if (wallet->getKeyFilePath().isEmpty() || !wallet->getSecurityImage()) { - if (keyStatus == "preexisting") { - status = (uint) WalletStatus::WALLET_STATUS_PREEXISTING; - } else { - status = (uint) WalletStatus::WALLET_STATUS_NOT_SET_UP; - } - } else if (!wallet->walletIsAuthenticatedWithPassphrase()) { - status = (uint) WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED; - } else if (keyStatus == "conflicting") { - status = (uint) WalletStatus::WALLET_STATUS_CONFLICTING; - } else { - status = (uint) WalletStatus::WALLET_STATUS_READY; - } - walletScriptingInterface->setWalletStatus(status); - }); - - connect(ledger.data(), &Ledger::accountResult, this, &Wallet::sendChallengeOwnershipResponses); - - auto accountManager = DependencyManager::get(); - connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() { - getWalletStatus(); - clear(); - }); -} - -void Wallet::clear() { - _publicKeys.clear(); - - if (_securityImage) { - delete _securityImage; - } - _securityImage = nullptr; - - // tell the provider we got nothing - updateImageProvider(); - _passphrase->clear(); -} - -Wallet::~Wallet() { - if (_securityImage) { - delete _securityImage; - } - - if (_passphrase) { - delete _passphrase; - } -} - -bool Wallet::setWallet(const QByteArray& wallet) { - QFile file(keyFilePath()); - if (!file.open(QIODevice::WriteOnly)) { - qCCritical(commerce) << "Unable to open wallet for write in" << keyFilePath(); - return false; - } - if (file.write(wallet) != wallet.count()) { - qCCritical(commerce) << "Unable to write wallet in" << keyFilePath(); - return false; - } - file.close(); - return true; -} -QByteArray Wallet::getWallet() { - QFile file(keyFilePath()); - if (!file.open(QIODevice::ReadOnly)) { - qCInfo(commerce) << "No existing wallet in" << keyFilePath(); - return QByteArray(); - } - QByteArray wallet = file.readAll(); - file.close(); - return wallet; -} - -bool Wallet::copyKeyFileFrom(const QString& pathname) { - QString existing = getKeyFilePath(); - qCDebug(commerce) << "Old keyfile" << existing; - if (!existing.isEmpty()) { - QString backup = QString(existing).insert(existing.indexOf(KEY_FILE) - 1, - QDateTime::currentDateTime().toString(Qt::ISODate).replace(":", "")); - qCDebug(commerce) << "Renaming old keyfile to" << backup; - if (!QFile::rename(existing, backup)) { - qCCritical(commerce) << "Unable to backup" << existing << "to" << backup; - return false; - } - } - QString destination = keyFilePath(); - bool result = QFile::copy(pathname, destination); - qCDebug(commerce) << "copy" << pathname << "to" << destination << "=>" << result; - return result; -} - -bool Wallet::writeBackupInstructions() { - QString inputFilename(PathUtils::resourcesPath() + "html/commerce/backup_instructions.html"); - QString outputFilename = PathUtils::getAppDataFilePath(INSTRUCTIONS_FILE); - QFile inputFile(inputFilename); - QFile outputFile(outputFilename); - bool retval = false; - - if (getKeyFilePath().isEmpty()) { - return false; - } - - if (QFile::exists(inputFilename) && inputFile.open(QIODevice::ReadOnly)) { - if (outputFile.open(QIODevice::ReadWrite)) { - // Read the data from the original file, then close it - QByteArray fileData = inputFile.readAll(); - inputFile.close(); - - // Translate the data from the original file into a QString - QString text(fileData); - - // Replace the necessary string - text.replace(QString("HIFIKEY_PATH_REPLACEME"), keyFilePath()); - - // Write the new text back to the file - outputFile.write(text.toUtf8()); - - // Close the output file - outputFile.close(); - - retval = true; - qCDebug(commerce) << "wrote html file successfully"; - } else { - qCDebug(commerce) << "failed to open output html file" << outputFilename; - } - } else { - qCDebug(commerce) << "failed to open input html file" << inputFilename; - } - return retval; -} - -bool Wallet::setPassphrase(const QString& passphrase) { - if (_passphrase) { - delete _passphrase; - } - _passphrase = new QString(passphrase); - - _publicKeys.clear(); - - writeBackupInstructions(); - - return true; -} - -bool Wallet::writeSecurityImage(const QPixmap* pixmap, const QString& outputFilePath) { - // aes requires a couple 128-bit keys (ckey and ivec). For now, I'll just - // use the md5 of the salt as the ckey (md5 is 128-bit), and ivec will be - // a constant. We can review this later - there are ways to generate keys - // from a password that may be better. - unsigned char ivec[16]; - unsigned char ckey[32]; - - initializeAESKeys(ivec, ckey, _salt); - - int tempSize, outSize; - QByteArray inputFileBuffer; - QBuffer buffer(&inputFileBuffer); - buffer.open(QIODevice::WriteOnly); - - // another spot where we are assuming only jpgs - pixmap->save(&buffer, "jpg"); - - // reserve enough capacity for encrypted bytes - unsigned char* outputFileBuffer = new unsigned char[inputFileBuffer.size() + AES_BLOCK_SIZE]; - - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - - // TODO: add error handling!!! - if (!EVP_EncryptInit_ex(ctx, EVP_des_ede3_cbc(), NULL, ckey, ivec)) { - qCDebug(commerce) << "encrypt init failure"; - delete[] outputFileBuffer; - return false; - } - if (!EVP_EncryptUpdate(ctx, outputFileBuffer, &tempSize, (unsigned char*)inputFileBuffer.data(), inputFileBuffer.size())) { - qCDebug(commerce) << "encrypt update failure"; - delete[] outputFileBuffer; - return false; - } - outSize = tempSize; - if (!EVP_EncryptFinal_ex(ctx, outputFileBuffer + outSize, &tempSize)) { - qCDebug(commerce) << "encrypt final failure"; - delete[] outputFileBuffer; - return false; - } - - outSize += tempSize; - EVP_CIPHER_CTX_free(ctx); - qCDebug(commerce) << "encrypted buffer size" << outSize; - QByteArray output((const char*)outputFileBuffer, outSize); - - // now APPEND to the file, - QByteArray b64output = output.toBase64(); - QFile outputFile(outputFilePath); - outputFile.open(QIODevice::Append); - outputFile.write(IMAGE_HEADER); - outputBase64WithNewlines(outputFile, b64output); - outputFile.write(IMAGE_FOOTER); - outputFile.close(); - - delete[] outputFileBuffer; - return true; -} - -bool Wallet::readSecurityImage(const QString& inputFilePath, unsigned char** outputBufferPtr, int* outputBufferSize) { - unsigned char ivec[16]; - unsigned char ckey[32]; - initializeAESKeys(ivec, ckey, _salt); - - // read encrypted file - QFile inputFile(inputFilePath); - if (!inputFile.exists()) { - qCDebug(commerce) << "cannot decrypt file" << inputFilePath << "it doesn't exist"; - return false; - } - inputFile.open(QIODevice::ReadOnly | QIODevice::Text); - bool foundHeader = false; - bool foundFooter = false; - - QByteArray base64EncryptedBuffer; - - while (!inputFile.atEnd()) { - QString line(inputFile.readLine()); - if (!foundHeader) { - foundHeader = (line == IMAGE_HEADER); - } else { - foundFooter = (line == IMAGE_FOOTER); - if (!foundFooter) { - base64EncryptedBuffer.append(line); - } - } - } - inputFile.close(); - if (! (foundHeader && foundFooter)) { - qCDebug(commerce) << "couldn't parse" << inputFilePath << foundHeader << foundFooter; - return false; - } - - // convert to bytes - auto encryptedBuffer = QByteArray::fromBase64(base64EncryptedBuffer); - - // setup decrypted buffer - unsigned char* outputBuffer = new unsigned char[encryptedBuffer.size()]; - int tempSize; - - // TODO: add error handling - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - if (!EVP_DecryptInit_ex(ctx, EVP_des_ede3_cbc(), NULL, ckey, ivec)) { - qCDebug(commerce) << "decrypt init failure"; - delete[] outputBuffer; - return false; - } - if (!EVP_DecryptUpdate(ctx, outputBuffer, &tempSize, (unsigned char*)encryptedBuffer.data(), encryptedBuffer.size())) { - qCDebug(commerce) << "decrypt update failure"; - delete[] outputBuffer; - return false; - } - *outputBufferSize = tempSize; - if (!EVP_DecryptFinal_ex(ctx, outputBuffer + tempSize, &tempSize)) { - qCDebug(commerce) << "decrypt final failure"; - delete[] outputBuffer; - return false; - } - EVP_CIPHER_CTX_free(ctx); - *outputBufferSize += tempSize; - *outputBufferPtr = outputBuffer; - qCDebug(commerce) << "decrypted buffer size" << *outputBufferSize; - return true; -} - -bool Wallet::walletIsAuthenticatedWithPassphrase() { - // try to read existing keys if they exist... - - // FIXME: initialize OpenSSL elsewhere soon - initialize(); - qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: checking" << (!_passphrase || !_passphrase->isEmpty()); - - // this should always be false if we don't have a passphrase - // cached yet - if (!_passphrase || _passphrase->isEmpty()) { - if (!getKeyFilePath().isEmpty()) { // If file exists, then it is an old school file that has not been lockered. Must get user's passphrase. - qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: No passphrase, but there is an existing wallet."; - return false; - } else { - qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: New setup."; - setPassphrase("ACCOUNT"); // Going forward, consider this an account-based client. - } - } - if (_publicKeys.count() > 0) { - // we _must_ be authenticated if the publicKeys are there - DependencyManager::get()->setWalletStatus((uint)WalletStatus::WALLET_STATUS_READY); - qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet was ready"; - return true; - } - - // otherwise, we have a passphrase but no keys, so we have to check - auto publicKey = readPublicKey(keyFilePath()); - - if (publicKey.size() > 0) { - if (auto key = readPrivateKey(keyFilePath())) { - EC_KEY_free(key); - - // be sure to add the public key so we don't do this over and over - _publicKeys.push_back(publicKey.toBase64()); - - if (*_passphrase != "ACCOUNT") { - changePassphrase("ACCOUNT"); // Rewrites with salt and constant, and will be lockered that way. - } - qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet now ready"; - return true; - } - } - qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet not ready"; - return false; -} - -bool Wallet::generateKeyPair() { - // FIXME: initialize OpenSSL elsewhere soon - initialize(); - - qCInfo(commerce) << "Generating keypair."; - auto keyPair = generateECKeypair(); - if (!keyPair.first) { - qCWarning(commerce) << "Empty keypair"; - return false; - } - - writeBackupInstructions(); - - // TODO: redo this soon -- need error checking and so on - writeSecurityImage(_securityImage, keyFilePath()); - QString key = keyPair.first->toBase64(); - _publicKeys.push_back(key); - qCDebug(commerce) << "public key:" << key; - _isOverridingServer = false; - - // It's arguable whether we want to change the receiveAt every time, but: - // 1. It's certainly needed the first time, when createIfNeeded answers true. - // 2. It is maximally private, and we can step back from that later if desired. - // 3. It maximally exercises all the machinery, so we are most likely to surface issues now. - auto ledger = DependencyManager::get(); - return ledger->receiveAt(key, key, getWallet()); -} - -QStringList Wallet::listPublicKeys() { - return _publicKeys; -} - -// for now a copy of how we sign in libraries/networking/src/DataServerAccountInfo - -// we sha256 the text, read the private key from disk (for now!), and return the signed -// sha256. Note later with multiple keys, we may need the key parameter (or something -// similar) so I left it alone for now. Also this will probably change when we move -// away from RSA keys anyways. Note that since this returns a QString, we better avoid -// the horror of code pages and so on (changing the bytes) by just returning a base64 -// encoded string representing the signature (suitable for http, etc...) -QString Wallet::signWithKey(const QByteArray& text, const QString& key) { - EC_KEY* ecPrivateKey = NULL; - - if ((ecPrivateKey = readPrivateKey(keyFilePath()))) { - const auto sig = std::make_unique(ECDSA_size(ecPrivateKey)); - - unsigned int signatureBytes = 0; - - qCInfo(commerce) << "Hashing and signing plaintext" << text << "with key at address" << ecPrivateKey; - - QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256); - - int retrn = ECDSA_sign(0, reinterpret_cast(hashedPlaintext.constData()), hashedPlaintext.size(), - sig.get(), &signatureBytes, ecPrivateKey); - - EC_KEY_free(ecPrivateKey); - QByteArray signature(reinterpret_cast(sig.get()), signatureBytes); - if (retrn != -1) { - return signature.toBase64(); - } - } - return QString(); -} - -void Wallet::updateImageProvider() { - SecurityImageProvider* securityImageProvider; - - // inform offscreenUI security image provider - auto offscreenUI = DependencyManager::get(); - if (!offscreenUI) { - return; - } - QQmlEngine* engine = offscreenUI->getSurfaceContext()->engine(); - securityImageProvider = reinterpret_cast(engine->imageProvider(SecurityImageProvider::PROVIDER_NAME)); - securityImageProvider->setSecurityImage(_securityImage); - - // inform tablet security image provider - TabletProxy* tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); - if (tablet) { - OffscreenQmlSurface* tabletSurface = tablet->getTabletSurface(); - if (tabletSurface) { - QQmlEngine* tabletEngine = tabletSurface->getSurfaceContext()->engine(); - securityImageProvider = reinterpret_cast(tabletEngine->imageProvider(SecurityImageProvider::PROVIDER_NAME)); - securityImageProvider->setSecurityImage(_securityImage); - } - } -} - -void Wallet::chooseSecurityImage(const QString& filename) { - if (_securityImage) { - delete _securityImage; - } - QString path = PathUtils::resourcesPath(); - path.append("/qml/hifi/dialogs/security/"); - path.append(filename); - - // now create a new security image pixmap - _securityImage = new QPixmap(); - - qCDebug(commerce) << "loading data for pixmap from" << path; - _securityImage->load(path); - - // update the image now - updateImageProvider(); - - // we could be choosing the _inital_ security image. If so, there - // will be no hifikey file yet. If that is the case, we are done. If - // there _is_ a keyfile, we need to update it (similar to changing the - // passphrase, we need to do so into a temp file and move it). - if (!QFile(keyFilePath()).exists()) { - qCDebug(commerce) << "initial security pic set for empty wallet"; - emit securityImageResult(true); - return; - } - - bool success = writeWallet(); - qCDebug(commerce) << "updated security pic" << success; - emit securityImageResult(success); -} - -bool Wallet::getSecurityImage() { - unsigned char* data; - int dataLen; - - // if already decrypted, don't do it again - if (_securityImage) { - updateImageProvider(); - emit securityImageResult(true); - return true; - } - - bool success = false; - // decrypt and return. Don't bother if we have no file to decrypt, or - // no salt set yet. - QFileInfo fileInfo(keyFilePath()); - if (fileInfo.exists() && _salt.size() > 0 && readSecurityImage(keyFilePath(), &data, &dataLen)) { - // create the pixmap - _securityImage = new QPixmap(); - _securityImage->loadFromData(data, dataLen, "jpg"); - qCDebug(commerce) << "created pixmap from encrypted file"; - - updateImageProvider(); - - delete[] data; - success = true; - } - emit securityImageResult(success); - return success; -} -QString Wallet::getKeyFilePath() { - QString filePath(keyFilePath()); - QFileInfo fileInfo(filePath); - if (fileInfo.exists()) { - return filePath; - } else { - return ""; - } -} - -bool Wallet::writeWallet(const QString& newPassphrase) { - EC_KEY* keys = readKeys(keyFilePath()); - auto ledger = DependencyManager::get(); - // Remove any existing locker, because it will be out of date. - if (!_publicKeys.isEmpty() && !ledger->receiveAt(_publicKeys.first(), _publicKeys.first(), QByteArray())) { - return false; // FIXME: receiveAt could fail asynchronously. - } - if (keys) { - // we read successfully, so now write to a new temp file - QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp")); - QString oldPassphrase = *_passphrase; - if (!newPassphrase.isEmpty()) { - setPassphrase(newPassphrase); - } - - if (writeKeys(tempFileName, keys)) { - if (writeSecurityImage(_securityImage, tempFileName)) { - // ok, now move the temp file to the correct spot - QFile(QString(keyFilePath())).remove(); - QFile(tempFileName).rename(QString(keyFilePath())); - qCDebug(commerce) << "wallet written successfully"; - emit keyFilePathIfExistsResult(getKeyFilePath()); - if (!walletIsAuthenticatedWithPassphrase() || !ledger->receiveAt()) { - // FIXME: Should we fail the whole operation? - // Tricky, because we'll need the the key and file from the TEMP location... - qCWarning(commerce) << "Failed to update locker"; - } - return true; - } else { - qCDebug(commerce) << "couldn't write security image to temp wallet"; - } - } else { - qCDebug(commerce) << "couldn't write keys to temp wallet"; - } - // if we are here, we failed, so cleanup - QFile(tempFileName).remove(); - if (!newPassphrase.isEmpty()) { - setPassphrase(oldPassphrase); - } - - } else { - qCDebug(commerce) << "couldn't read wallet - bad passphrase?"; - // TODO: review this, but it seems best to reset the passphrase - // since we couldn't decrypt the existing wallet (or is doesn't - // exist perhaps). - setPassphrase(""); - } - return false; -} - -bool Wallet::changePassphrase(const QString& newPassphrase) { - qCDebug(commerce) << "changing passphrase"; - return writeWallet(newPassphrase); -} - -void Wallet::handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode) { - _pendingChallenges.push_back(packet); - sendChallengeOwnershipResponses(); -} - -void Wallet::sendChallengeOwnershipResponses() { - if (_pendingChallenges.size() == 0) { - return; - } - if (getSalt().length() == 0) { - qCDebug(commerce) << "Not responding to ownership challenge due to missing Wallet salt"; - return; - } - - auto nodeList = DependencyManager::get(); - - EC_KEY* ec = readKeys(keyFilePath()); - - for (const auto& packet: _pendingChallenges) { - - // With EC keys, we receive a nonce from the metaverse server, which is signed - // here with the private key and returned. Verification is done at server. - - QString sig; - bool challengeOriginatedFromClient = packet->getType() == PacketType::ChallengeOwnershipRequest; - int status; - int idByteArraySize; - int textByteArraySize; - int challengingNodeUUIDByteArraySize; - - packet->readPrimitive(&idByteArraySize); - packet->readPrimitive(&textByteArraySize); // returns a cast char*, size - if (challengeOriginatedFromClient) { - packet->readPrimitive(&challengingNodeUUIDByteArraySize); - } - - // "encryptedText" is now a series of random bytes, a nonce - QByteArray id = packet->read(idByteArraySize); - QByteArray text = packet->read(textByteArraySize); - QByteArray challengingNodeUUID; - if (challengeOriginatedFromClient) { - challengingNodeUUID = packet->read(challengingNodeUUIDByteArraySize); - } - - if (ec) { - ERR_clear_error(); - sig = signWithKey(text, ""); // base64 signature, QByteArray cast (on return) to QString FIXME should pass ec as string so we can tell which key to sign with - status = 1; - } else { - qCDebug(commerce) << "During entity ownership challenge, creating the EC-signed nonce failed."; - status = -1; - } - - QByteArray textByteArray; - if (status > -1) { - textByteArray = sig.toUtf8(); - } - textByteArraySize = textByteArray.size(); - int idSize = id.size(); - // setup the packet - const SharedNodePointer sendingNode = nodeList->nodeWithLocalID(packet->getSourceID()); - if (!sendingNode.isNull()) { - if (challengeOriginatedFromClient) { - auto textPacket = NLPacket::create(PacketType::ChallengeOwnershipReply, - idSize + textByteArraySize + challengingNodeUUIDByteArraySize + 3 * sizeof(int), - true); - - textPacket->writePrimitive(idSize); - textPacket->writePrimitive(textByteArraySize); - textPacket->writePrimitive(challengingNodeUUIDByteArraySize); - textPacket->write(id); - textPacket->write(textByteArray); - textPacket->write(challengingNodeUUID); - - qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing signed text" << textByteArray << "for id" << id; - - nodeList->sendPacket(std::move(textPacket), *sendingNode); - } else { - auto textPacket = NLPacket::create(PacketType::ChallengeOwnership, idSize + textByteArraySize + 2 * sizeof(int), true); - - textPacket->writePrimitive(idSize); - textPacket->writePrimitive(textByteArraySize); - textPacket->write(id); - textPacket->write(textByteArray); - - qCDebug(commerce) << "Sending ChallengeOwnership Packet containing signed text" << textByteArray << "for id" << id; - - nodeList->sendPacket(std::move(textPacket), *sendingNode); - } - } else { - qCDebug(commerce) << "Challenging Node Local ID" << packet->getSourceID() << "disconnected before response"; - } - - - if (status == -1) { - qCDebug(commerce) << "During entity ownership challenge, signing the text failed."; - long error = ERR_get_error(); - if (error != 0) { - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "EC error:" << error_str; - } - } - } - - EC_KEY_free(ec); - _pendingChallenges.clear(); -} - -void Wallet::account() { - auto ledger = DependencyManager::get(); - ledger->account(); -} - -void Wallet::getWalletStatus() { - auto walletScriptingInterface = DependencyManager::get(); - - if (DependencyManager::get()->isLoggedIn()) { - // This will set account info for the wallet, allowing us to decrypt and display the security image. - account(); - } else { - walletScriptingInterface->setWalletStatus((uint)WalletStatus::WALLET_STATUS_NOT_LOGGED_IN); - return; - } -} diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h deleted file mode 100644 index 52b956dc5be..00000000000 --- a/interface/src/commerce/Wallet.h +++ /dev/null @@ -1,122 +0,0 @@ -// -// Wallet.h -// interface/src/commerce -// -// API for secure keypair management -// -// Created by Howard Stearns on 8/4/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_Wallet_h -#define hifi_Wallet_h - -#include -#include -#include -#include "scripting/WalletScriptingInterface.h" - -#include - -class Wallet : public QObject, public Dependency { - Q_OBJECT - SINGLETON_DEPENDENCY - -public: - Wallet(); - ~Wallet(); - // These are currently blocking calls, although they might take a moment. - bool generateKeyPair(); - QStringList listPublicKeys(); - QString signWithKey(const QByteArray& text, const QString& key); - void chooseSecurityImage(const QString& imageFile); - bool getSecurityImage(); - QString getKeyFilePath(); - bool copyKeyFileFrom(const QString& pathname); - - void setSalt(const QByteArray& salt) { _salt = salt; } - QByteArray getSalt() { return _salt; } - void setIv(const QByteArray& iv) { _iv = iv; } - QByteArray getIv() { return _iv; } - void setCKey(const QByteArray& ckey) { _ckey = ckey; } - QByteArray getCKey() { return _ckey; } - - bool setPassphrase(const QString& passphrase); - QString* getPassphrase() { return _passphrase; } - bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); } - bool walletIsAuthenticatedWithPassphrase(); - bool changePassphrase(const QString& newPassphrase); - void setSoftReset() { _isOverridingServer = true; } - bool wasSoftReset() { bool was = _isOverridingServer; _isOverridingServer = false; return was; } - void clear(); - - void getWalletStatus(); - - /**jsdoc - *

A WalletStatus may have one of the following values:

- * - * - * - * - * - * - * - * - * - * - * - * - *
ValueMeaningDescription
0Not logged inThe user is not logged in.
1Not set upThe user's wallet has not been set up.
2Pre-existingThere is a wallet present on the server but not one - * locally.
3ConflictingThere is a wallet present on the server plus one present locally, - * and they don't match.
4Not authenticatedThere is a wallet present locally but the user hasn't - * logged into it.
5ReadyThe wallet is ready for use.
- *

Wallets used to be stored locally but now they're only stored on the server. A wallet is present in both places if - * your computer previously stored its information locally.

- * @typedef {number} WalletScriptingInterface.WalletStatus - */ - enum WalletStatus { - WALLET_STATUS_NOT_LOGGED_IN = 0, - WALLET_STATUS_NOT_SET_UP, - WALLET_STATUS_PREEXISTING, - WALLET_STATUS_CONFLICTING, - WALLET_STATUS_NOT_AUTHENTICATED, - WALLET_STATUS_READY - }; - -signals: - void securityImageResult(bool exists); - void keyFilePathIfExistsResult(const QString& path); - - void walletStatusResult(uint walletStatus); - -private slots: - void handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode); - void sendChallengeOwnershipResponses(); - -private: - friend class Ledger; - QStringList _publicKeys{}; - QPixmap* _securityImage { nullptr }; - QByteArray _salt; - QByteArray _iv; - QByteArray _ckey; - QString* _passphrase { nullptr }; - bool _isOverridingServer { false }; - std::vector> _pendingChallenges; - - bool writeWallet(const QString& newPassphrase = QString("")); - void updateImageProvider(); - bool writeSecurityImage(const QPixmap* pixmap, const QString& outputFilePath); - bool readSecurityImage(const QString& inputFilePath, unsigned char** outputBufferPtr, int* outputBufferLen); - bool writeBackupInstructions(); - - bool setWallet(const QByteArray& wallet); - QByteArray getWallet(); - - void account(); -}; - -#endif // hifi_Wallet_h diff --git a/interface/src/scripting/WalletScriptingInterface.cpp b/interface/src/scripting/WalletScriptingInterface.cpp deleted file mode 100644 index 60f850adac9..00000000000 --- a/interface/src/scripting/WalletScriptingInterface.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// -// WalletScriptingInterface.cpp -// interface/src/scripting -// -// Created by Zach Fox on 2017-09-29. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "WalletScriptingInterface.h" -#include - -CheckoutProxy::CheckoutProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(qmlObject, parent) { - Q_ASSERT(QThread::currentThread() == qApp->thread()); -} - -WalletScriptingInterface::WalletScriptingInterface() { - connect(DependencyManager::get().data(), - &AccountManager::limitedCommerceChanged, this, &WalletScriptingInterface::limitedCommerceChanged); -} - -void WalletScriptingInterface::refreshWalletStatus() { - auto wallet = DependencyManager::get(); - wallet->getWalletStatus(); -} - -void WalletScriptingInterface::setWalletStatus(const uint& status) { - _walletStatus = status; - emit DependencyManager::get()->walletStatusResult(status); -} - -void WalletScriptingInterface::proveAvatarEntityOwnershipVerification(const QUuid& entityID) { - QSharedPointer contextOverlayInterface = DependencyManager::get(); - EntityItemProperties entityProperties = DependencyManager::get()->getEntityProperties(entityID, - contextOverlayInterface->getEntityPropertyFlags()); - if (entityProperties.getEntityHostType() == entity::HostType::AVATAR) { - if (!entityID.isNull() && entityProperties.getCertificateID().length() > 0) { - contextOverlayInterface->requestOwnershipVerification(entityID); - } else { - qCDebug(entities) << "Failed to prove ownership of:" << entityID << "is null or not a certified item"; - } - } else { - qCDebug(entities) << "Failed to prove ownership of:" << entityID << "is not an avatar entity"; - } -} diff --git a/interface/src/scripting/WalletScriptingInterface.h b/interface/src/scripting/WalletScriptingInterface.h deleted file mode 100644 index 849caa8427a..00000000000 --- a/interface/src/scripting/WalletScriptingInterface.h +++ /dev/null @@ -1,170 +0,0 @@ -// -// WalletScriptingInterface.h -// interface/src/scripting -// -// Created by Zach Fox on 2017-09-29. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_WalletScriptingInterface_h -#define hifi_WalletScriptingInterface_h - -#include -#include - -#include -#include -#include -#include "Application.h" -#include "commerce/Wallet.h" -#include "ui/overlays/ContextOverlayInterface.h" -#include - -class CheckoutProxy : public QmlWrapper { - Q_OBJECT -public: - CheckoutProxy(QObject* qmlObject, QObject* parent = nullptr); -}; - -/**jsdoc - * The WalletScriptingInterface API provides functions related to the user's wallet and verification of certified - * avatar entities. - * - * @namespace WalletScriptingInterface - * - * @hifi-interface - * @hifi-client-entity - * @hifi-avatar - * - * @property {WalletScriptingInterface.WalletStatus} walletStatus - The status of the user's wallet. Read-only. - * @property {boolean} limitedCommerce - true if Interface is running in limited commerce mode. In limited commerce - * mode, certain Interface functionalities are disabled, e.g., users can't buy items that are not free from the Marketplace. - * The Oculus Store and Steam versions of Interface run in limited commerce mode. Read-only. - */ -class WalletScriptingInterface : public QObject, public Dependency { - Q_OBJECT - SINGLETON_DEPENDENCY - Q_PROPERTY(uint walletStatus READ getWalletStatus WRITE setWalletStatus NOTIFY walletStatusChanged) - Q_PROPERTY(bool limitedCommerce READ getLimitedCommerce WRITE setLimitedCommerce NOTIFY limitedCommerceChanged) - -public: - - WalletScriptingInterface(); - - /**jsdoc - * Checks and updates the user's wallet status. - * @function WalletScriptingInterface.refreshWalletStatus - */ - Q_INVOKABLE void refreshWalletStatus(); - - /**jsdoc - * Gets the current status of the user's wallet. - * @function WalletScriptingInterface.getWalletStatus - * @returns {WalletScriptingInterface.WalletStatus} - * @example Use two methods to report your wallet's status. - * print("Wallet status: " + WalletScriptingInterface.walletStatus); // Same value as next line. - * print("Wallet status: " + WalletScriptingInterface.getWalletStatus()); - */ - Q_INVOKABLE uint getWalletStatus() { return _walletStatus; } - - /**jsdoc - * Check that a certified avatar entity is owned by the avatar whose entity it is. The result of the check is provided via - * the {@link WalletScriptingInterface.ownershipVerificationSuccess|ownershipVerificationSuccess} and - * {@link WalletScriptingInterface.ownershipVerificationFailed|ownershipVerificationFailed} signals. - *

Warning: Neither of these signals are triggered if the entity is not an avatar entity or is not - * certified.

- * @function WalletScriptingInterface.proveAvatarEntityOwnershipVerification - * @param {Uuid} entityID - The avatar entity's ID. - * @example Check the ownership of all nearby certified avatar entities. - * // Set up response handling. - * function ownershipSuccess(entityID) { - * print("Ownership test succeeded for: " + entityID); - * } - * function ownershipFailed(entityID) { - * print("Ownership test failed for: " + entityID); - * } - * WalletScriptingInterface.ownershipVerificationSuccess.connect(ownershipSuccess); - * WalletScriptingInterface.ownershipVerificationFailed.connect(ownershipFailed); - * - * // Check ownership of all nearby certified avatar entities. - * var entityIDs = Entities.findEntities(MyAvatar.position, 10); - * var i, length; - * for (i = 0, length = entityIDs.length; i < length; i++) { - * var properties = Entities.getEntityProperties(entityIDs[i], ["entityHostType", "certificateID"]); - * if (properties.entityHostType === "avatar" && properties.certificateID !== "") { - * print("Prove ownership of: " + entityIDs[i]); - * WalletScriptingInterface.proveAvatarEntityOwnershipVerification(entityIDs[i]); - * } - * } - * - * // Tidy up. - * Script.scriptEnding.connect(function () { - * WalletScriptingInterface.ownershipVerificationFailed.disconnect(ownershipFailed); - * WalletScriptingInterface.ownershipVerificationSuccess.disconnect(ownershipSuccess); - * }); - */ - Q_INVOKABLE void proveAvatarEntityOwnershipVerification(const QUuid& entityID); - - // setWalletStatus() should never be made Q_INVOKABLE. If it were, - // scripts could cause the Wallet to incorrectly report its status. - void setWalletStatus(const uint& status); - - bool getLimitedCommerce() { return DependencyManager::get()->getLimitedCommerce(); } - void setLimitedCommerce(bool isLimited) { DependencyManager::get()->setLimitedCommerce(isLimited); }; - -signals: - - /**jsdoc - * Triggered when the user's wallet status changes. - * @function WalletScriptingInterface.walletStatusChanged - * @returns {Signal} - * @example Report when your wallet status changes, e.g., when you log in and out. - * WalletScriptingInterface.walletStatusChanged.connect(function () { - * print("Wallet status changed to: " + WalletScriptingInterface.walletStatus"); - * }); - */ - void walletStatusChanged(); - - /**jsdoc - * Triggered when the user's limited commerce status changes. - * @function WalletScriptingInterface.limitedCommerceChanged - * @returns {Signal} - */ - void limitedCommerceChanged(); - - /**jsdoc - * Triggered when the user rezzes a certified entity but the user's wallet is not ready. So the certified location of the - * entity cannot be updated in the metaverse. - * @function WalletScriptingInterface.walletNotSetup - * @returns {Signal} - */ - void walletNotSetup(); - - /**jsdoc - * Triggered when a certified avatar entity's ownership check requested via - * {@link WalletScriptingInterface.proveAvatarEntityOwnershipVerification|proveAvatarEntityOwnershipVerification} or - * {@link ContextOverlay.requestOwnershipVerification} succeeds. - * @function WalletScriptingInterface.ownershipVerificationSuccess - * @param {Uuid} entityID - The ID of the avatar entity checked. - * @returns {Signal} - */ - void ownershipVerificationSuccess(const QUuid& entityID); - - /**jsdoc - * Triggered when a certified avatar entity's ownership check requested via - * {@link WalletScriptingInterface.proveAvatarEntityOwnershipVerification|proveAvatarEntityOwnershipVerification} or - * {@link ContextOverlay.requestOwnershipVerification} fails. - * @function WalletScriptingInterface.ownershipVerificationFailed - * @param {Uuid} entityID - The ID of the avatar entity checked. - * @returns {Signal} - */ - void ownershipVerificationFailed(const QUuid& entityID); - -private: - uint _walletStatus; -}; - -#endif // hifi_WalletScriptingInterface_h diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 434adf0bc8b..f85db1c29ec 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -28,7 +28,6 @@ #include "MainWindow.h" #include "Menu.h" #include "OffscreenUi.h" -#include "commerce/QmlCommerce.h" #include "NetworkingConstants.h" static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); @@ -141,8 +140,6 @@ void WindowScriptingInterface::openUrl(const QUrl& url) { auto scheme = url.scheme(); if (scheme == URL_SCHEME_HIFI) { DependencyManager::get()->handleLookupString(url.toString()); - } else if (scheme == URL_SCHEME_HIFIAPP) { - DependencyManager::get()->openSystemApp(url.path()); } else { #if defined(Q_OS_ANDROID) QMap args; diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 1eaad05e33b..c6cb99fb1cd 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -126,7 +126,6 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _filterDropdown->addItem("hifi.audioclient"); _filterDropdown->addItem("hifi.animation"); _filterDropdown->addItem("hifi.avatars"); - _filterDropdown->addItem("hifi.commerce"); _filterDropdown->addItem("hifi.controllers"); _filterDropdown->addItem("hifi.entities"); _filterDropdown->addItem("hifi.gl"); diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp deleted file mode 100644 index 0f1c8978f07..00000000000 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ /dev/null @@ -1,435 +0,0 @@ -// -// ContextOverlayInterface.cpp -// interface/src/ui/overlays -// -// Created by Zach Fox on 2017-07-14. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "ContextOverlayInterface.h" -#include "Application.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -static const float CONTEXT_OVERLAY_TABLET_OFFSET = 30.0f; // Degrees -static const float CONTEXT_OVERLAY_TABLET_ORIENTATION = 210.0f; // Degrees -static const float CONTEXT_OVERLAY_TABLET_DISTANCE = 0.65F; // Meters -ContextOverlayInterface::ContextOverlayInterface() { - // "context_overlay" debug log category disabled by default. - // Create your own "qtlogging.ini" file and set your "QT_LOGGING_CONF" environment variable - // if you'd like to enable/disable certain categories. - // More details: http://doc.qt.io/qt-5/qloggingcategory.html#configuring-categories - QLoggingCategory::setFilterRules(QStringLiteral("hifi.context_overlay.debug=false")); - - _entityScriptingInterface = DependencyManager::get(); - _hmdScriptingInterface = DependencyManager::get(); - _tabletScriptingInterface = DependencyManager::get(); - _selectionScriptingInterface = DependencyManager::get(); - - _entityPropertyFlags += PROP_POSITION; - _entityPropertyFlags += PROP_ROTATION; - _entityPropertyFlags += PROP_MARKETPLACE_ID; - _entityPropertyFlags += PROP_DIMENSIONS; - _entityPropertyFlags += PROP_REGISTRATION_POINT; - _entityPropertyFlags += PROP_CERTIFICATE_ID; - _entityPropertyFlags += PROP_ENTITY_HOST_TYPE; - _entityPropertyFlags += PROP_OWNING_AVATAR_ID; - - auto entityScriptingInterface = DependencyManager::get().data(); - connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::clickDownOnEntity); - connect(entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity, this, &ContextOverlayInterface::mouseReleaseOnEntity); - connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, &ContextOverlayInterface::contextOverlays_hoverEnterEntity); - connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, &ContextOverlayInterface::contextOverlays_hoverLeaveEntity); - - connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay); - connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay); - - connect(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"), &TabletProxy::tabletShownChanged, this, [&]() { - if (_contextOverlayJustClicked && _hmdScriptingInterface->isMounted()) { - QUuid tabletFrameID = _hmdScriptingInterface->getCurrentTabletFrameID(); - auto myAvatar = DependencyManager::get()->getMyAvatar(); - glm::quat cameraOrientation = qApp->getCamera().getOrientation(); - - EntityItemProperties properties; - float sensorToWorldScale = myAvatar->getSensorToWorldScale(); - properties.setPosition(myAvatar->getEyePosition() + glm::quat(glm::radians(glm::vec3(0.0f, CONTEXT_OVERLAY_TABLET_OFFSET, 0.0f))) * ((CONTEXT_OVERLAY_TABLET_DISTANCE * sensorToWorldScale) * (cameraOrientation * Vectors::FRONT))); - properties.setRotation(cameraOrientation * glm::quat(glm::radians(glm::vec3(0.0f, CONTEXT_OVERLAY_TABLET_ORIENTATION, 0.0f)))); - DependencyManager::get()->editEntity(tabletFrameID, properties); - _contextOverlayJustClicked = false; - } - }); - connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity); - - { - _selectionScriptingInterface->enableListHighlight("contextOverlayHighlightList", QVariantMap()); - } - - auto nodeList = DependencyManager::get(); - auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::ChallengeOwnershipReply, this, "handleChallengeOwnershipReplyPacket"); - _challengeOwnershipTimeoutTimer.setSingleShot(true); -} - -static const glm::u8vec3 CONTEXT_OVERLAY_COLOR = { 255, 255, 255 }; -static const float CONTEXT_OVERLAY_INSIDE_DISTANCE = 1.0f; // in meters -static const float CONTEXT_OVERLAY_SIZE = 0.09f; // in meters, same x and y dims -static const float CONTEXT_OVERLAY_OFFSET_DISTANCE = 0.1f; -static const float CONTEXT_OVERLAY_OFFSET_ANGLE = 5.0f; -static const float CONTEXT_OVERLAY_UNHOVERED_ALPHA = 0.85f; -static const float CONTEXT_OVERLAY_HOVERED_ALPHA = 1.0f; -static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMIN = 0.6f; -static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMAX = 1.0f; -static const float CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD = 1.0f; - -void ContextOverlayInterface::setEnabled(bool enabled) { - _enabled = enabled; - if (!enabled) { - // Destroy any potentially-active ContextOverlays when disabling the interface - createOrDestroyContextOverlay(EntityItemID(), PointerEvent()); - } -} - -void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& id, const PointerEvent& event) { - if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(id)) { - _mouseDownEntity = id; - _mouseDownEntityTimestamp = usecTimestampNow(); - } else if ((event.shouldFocus() || event.getButton() == PointerEvent::PrimaryButton) && id == _contextOverlayID) { - qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "ID:" << id; - emit contextOverlayClicked(_currentEntityWithContextOverlay); - _contextOverlayJustClicked = true; - } else { - if (!_currentEntityWithContextOverlay.isNull()) { - disableEntityHighlight(_currentEntityWithContextOverlay); - destroyContextOverlay(_currentEntityWithContextOverlay, event); - } - } -} - -static const float CONTEXT_OVERLAY_CLICK_HOLD_TIME_MSEC = 400.0f; -void ContextOverlayInterface::mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { - if (!_mouseDownEntity.isNull() && ((usecTimestampNow() - _mouseDownEntityTimestamp) > (CONTEXT_OVERLAY_CLICK_HOLD_TIME_MSEC * USECS_PER_MSEC))) { - _mouseDownEntity = EntityItemID(); - } - if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID) && _mouseDownEntity == entityItemID) { - createOrDestroyContextOverlay(entityItemID, event); - } -} - -bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) { - if (_enabled && event.getButton() == PointerEvent::SecondaryButton) { - if (contextOverlayFilterPassed(entityItemID)) { - if (event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get()->isMouse(event.getID())) { - enableEntityHighlight(entityItemID); - } - - qCDebug(context_overlay) << "Creating Context Overlay on top of entity with ID: " << entityItemID; - - // Add all necessary variables to the stack - EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags); - glm::vec3 cameraPosition = qApp->getCamera().getPosition(); - glm::vec3 entityDimensions = entityProperties.getDimensions(); - glm::vec3 entityPosition = entityProperties.getPosition(); - glm::vec3 registrationPoint = entityProperties.getRegistrationPoint(); - glm::vec3 contextOverlayPosition = entityProperties.getPosition(); - glm::vec2 contextOverlayDimensions; - - // Update the position of the overlay if the registration point of the entity - // isn't default - if (registrationPoint != glm::vec3(0.5f)) { - glm::vec3 adjustPos = registrationPoint - glm::vec3(0.5f); - entityPosition = entityPosition - (entityProperties.getRotation() * (adjustPos * entityDimensions)); - } - - enableEntityHighlight(entityItemID); - - AABox boundingBox = AABox(entityPosition - (entityDimensions / 2.0f), entityDimensions * 2.0f); - - // Update the cached Entity Marketplace ID - _entityMarketplaceID = entityProperties.getMarketplaceID(); - - - if (!_currentEntityWithContextOverlay.isNull() && _currentEntityWithContextOverlay != entityItemID) { - disableEntityHighlight(_currentEntityWithContextOverlay); - } - - // Update the cached "Current Entity with Context Overlay" variable - setCurrentEntityWithContextOverlay(entityItemID); - - // Here, we determine the position and dimensions of the Context Overlay. - if (boundingBox.contains(cameraPosition)) { - // If the camera is inside the box... - // ...position the Context Overlay 1 meter in front of the camera. - contextOverlayPosition = cameraPosition + CONTEXT_OVERLAY_INSIDE_DISTANCE * (qApp->getCamera().getOrientation() * Vectors::FRONT); - contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_SIZE, CONTEXT_OVERLAY_SIZE) * glm::distance(contextOverlayPosition, cameraPosition); - } else { - // Rotate the Context Overlay some number of degrees offset from the entity - // along the line cast from your head to the entity's bounding box. - glm::vec3 direction = glm::normalize(entityPosition - cameraPosition); - float distance; - BoxFace face; - glm::vec3 normal; - boundingBox.findRayIntersection(cameraPosition, direction, 1.0f / direction, distance, face, normal); - float offsetAngle = -CONTEXT_OVERLAY_OFFSET_ANGLE; - if (event.getID() == 1) { // "1" is left hand - offsetAngle *= -1.0f; - } - contextOverlayPosition = cameraPosition + - (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f)))) * (direction * (distance - CONTEXT_OVERLAY_OFFSET_DISTANCE)); - contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_SIZE, CONTEXT_OVERLAY_SIZE) * glm::distance(contextOverlayPosition, cameraPosition); - } - - // Finally, setup and draw the Context Overlay - auto entityScriptingInterface = DependencyManager::get(); - if (_contextOverlayID == UNKNOWN_ENTITY_ID || !entityScriptingInterface->isAddedEntity(_contextOverlayID)) { - EntityItemProperties properties; - properties.setType(EntityTypes::Image); - properties.setAlpha(CONTEXT_OVERLAY_UNHOVERED_ALPHA); - properties.getPulse().setMin(CONTEXT_OVERLAY_UNHOVERED_PULSEMIN); - properties.getPulse().setMax(CONTEXT_OVERLAY_UNHOVERED_PULSEMAX); - properties.getPulse().setColorMode(PulseMode::IN_PHASE); - properties.setIgnorePickIntersection(false); - properties.setRenderLayer(RenderLayer::FRONT); - properties.setImageURL(PathUtils::resourcesUrl() + "images/inspect-icon.png"); - properties.setBillboardMode(BillboardMode::FULL); - - _contextOverlayID = entityScriptingInterface->addEntityInternal(properties, entity::HostType::LOCAL); - } - - EntityItemProperties properties; - properties.setPosition(contextOverlayPosition); - properties.setDimensions(glm::vec3(contextOverlayDimensions, 0.01f)); - properties.setRotation(entityProperties.getRotation()); - properties.setVisible(true); - entityScriptingInterface->editEntity(_contextOverlayID, properties); - - return true; - } - } else { - if (!_currentEntityWithContextOverlay.isNull()) { - disableEntityHighlight(_currentEntityWithContextOverlay); - return destroyContextOverlay(_currentEntityWithContextOverlay, event); - } - return false; - } - return false; -} - -bool ContextOverlayInterface::contextOverlayFilterPassed(const EntityItemID& entityItemID) { - EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags); - return (entityProperties.getCertificateID().length() != 0); -} - -bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) { - if (_contextOverlayID != UNKNOWN_ENTITY_ID) { - qCDebug(context_overlay) << "Destroying Context Overlay on top of entity with ID: " << entityItemID; - disableEntityHighlight(entityItemID); - setCurrentEntityWithContextOverlay(QUuid()); - _entityMarketplaceID.clear(); - DependencyManager::get()->deleteEntity(_contextOverlayID); - _contextOverlayID = UNKNOWN_ENTITY_ID; - return true; - } - return false; -} - -bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityItemID) { - return ContextOverlayInterface::destroyContextOverlay(entityItemID, PointerEvent()); -} - -void ContextOverlayInterface::contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event) { - if (_contextOverlayID == id) { - qCDebug(context_overlay) << "Started hovering over Context Overlay. ID:" << id; - EntityItemProperties properties; - properties.setColor(CONTEXT_OVERLAY_COLOR); - properties.getPulse().setColorMode(PulseMode::NONE); - properties.getPulse().setPeriod(0.0f); - properties.setAlpha(CONTEXT_OVERLAY_HOVERED_ALPHA); - DependencyManager::get()->editEntity(_contextOverlayID, properties); - } -} - -void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const QUuid& id, const PointerEvent& event) { - if (_contextOverlayID == id) { - qCDebug(context_overlay) << "Stopped hovering over Context Overlay. ID:" << id; - EntityItemProperties properties; - properties.setColor(CONTEXT_OVERLAY_COLOR); - properties.getPulse().setColorMode(PulseMode::IN_PHASE); - properties.getPulse().setPeriod(CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD); - properties.setAlpha(CONTEXT_OVERLAY_UNHOVERED_ALPHA); - DependencyManager::get()->editEntity(_contextOverlayID, properties); - } -} - -void ContextOverlayInterface::contextOverlays_hoverEnterEntity(const EntityItemID& id, const PointerEvent& event) { - bool isMouse = event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get()->isMouse(event.getID()); - if (contextOverlayFilterPassed(id) && _enabled && !isMouse) { - enableEntityHighlight(id); - } -} - -void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemID& id, const PointerEvent& event) { - bool isMouse = event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get()->isMouse(event.getID()); - if (_currentEntityWithContextOverlay != id && _enabled && !isMouse) { - disableEntityHighlight(id); - } -} - -void ContextOverlayInterface::requestOwnershipVerification(const QUuid& entityID) { - - setLastInspectedEntity(entityID); - - EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityID, _entityPropertyFlags); - - auto nodeList = DependencyManager::get(); - - if (entityProperties.verifyStaticCertificateProperties()) { - if (entityProperties.getEntityHostType() == entity::HostType::AVATAR) { - SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer); - - if (entityServer) { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest; - networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - QUrl requestURL = MetaverseAPI::getCurrentMetaverseServerURL(); - requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer"); - QJsonObject request; - request["certificate_id"] = entityProperties.getCertificateID(); - networkRequest.setUrl(requestURL); - - QNetworkReply* networkReply = NULL; - networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); - - connect(networkReply, &QNetworkReply::finished, [=]() { - QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); - jsonObject = jsonObject["data"].toObject(); - - if (networkReply->error() == QNetworkReply::NoError) { - if (!jsonObject["invalid_reason"].toString().isEmpty()) { - qCDebug(entities) << "invalid_reason not empty"; - } else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") { - qCDebug(entities) << "'transfer_status' is 'failed'"; - } else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") { - qCDebug(entities) << "'transfer_status' is 'pending'"; - } else { - QString ownerKey = jsonObject["transfer_recipient_key"].toString(); - - QByteArray id = entityID.toByteArray(); - QByteArray text = DependencyManager::get()->getTree()->computeNonce(entityID, ownerKey); - QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122(); - - int idByteArraySize = id.length(); - int textByteArraySize = text.length(); - int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length(); - - auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest, - idByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int), - true); - challengeOwnershipPacket->writePrimitive(idByteArraySize); - challengeOwnershipPacket->writePrimitive(textByteArraySize); - challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize); - challengeOwnershipPacket->write(id); - challengeOwnershipPacket->write(text); - challengeOwnershipPacket->write(nodeToChallengeByteArray); - nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer); - - // Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer", Q_ARG(const EntityItemID&, entityID)); - return; - } else { - startChallengeOwnershipTimer(entityID); - } - } - } else { - qCDebug(entities) << "Call failed with error" << networkReply->error() << - "More info:" << networkReply->readAll(); - } - - networkReply->deleteLater(); - }); - } else { - qCWarning(context_overlay) << "Couldn't get Entity Server!"; - } - } else { - // We don't currently verify ownership of entities that aren't Avatar Entities, - // so they always pass Ownership Verification. It's necessary to emit this signal - // so that the Inspection Certificate can continue its information-grabbing process. - auto ledger = DependencyManager::get(); - emit ledger->updateCertificateStatus(entityID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS)); - } - } else { - auto ledger = DependencyManager::get(); - _challengeOwnershipTimeoutTimer.stop(); - emit ledger->updateCertificateStatus(entityID, (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED)); - emit DependencyManager::get()->ownershipVerificationFailed(entityID); - qCDebug(context_overlay) << "Entity" << entityID << "failed static certificate verification!"; - } -} - -void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityID) { - _selectionScriptingInterface->addToSelectedItemsList("contextOverlayHighlightList", "entity", entityID); -} - -void ContextOverlayInterface::disableEntityHighlight(const EntityItemID& entityID) { - _selectionScriptingInterface->removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); -} - -void ContextOverlayInterface::deletingEntity(const EntityItemID& entityID) { - if (_currentEntityWithContextOverlay == entityID) { - destroyContextOverlay(_currentEntityWithContextOverlay, PointerEvent()); - } -} - -void ContextOverlayInterface::startChallengeOwnershipTimer(const EntityItemID& entityItemID) { - auto ledger = DependencyManager::get(); - EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags); - - connect(&_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() { - qCDebug(entities) << "Ownership challenge timed out for" << entityItemID; - emit ledger->updateCertificateStatus(entityItemID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_TIMEOUT)); - emit DependencyManager::get()->ownershipVerificationFailed(entityItemID); - }); - - _challengeOwnershipTimeoutTimer.start(5000); -} - -void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode) { - auto ledger = DependencyManager::get(); - - _challengeOwnershipTimeoutTimer.stop(); - - int idByteArraySize; - int textByteArraySize; - - packet->readPrimitive(&idByteArraySize); - packet->readPrimitive(&textByteArraySize); - - EntityItemID id(packet->read(idByteArraySize)); - QString text(packet->read(textByteArraySize)); - - bool verificationSuccess = DependencyManager::get()->getTree()->verifyNonce(id, text); - - if (verificationSuccess) { - emit ledger->updateCertificateStatus(id, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS)); - emit DependencyManager::get()->ownershipVerificationSuccess(id); - } else { - emit ledger->updateCertificateStatus(id, (uint)(ledger->CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED)); - emit DependencyManager::get()->ownershipVerificationFailed(id); - } -} diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h deleted file mode 100644 index 5d11b254fc3..00000000000 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ /dev/null @@ -1,226 +0,0 @@ -// -// ContextOverlayInterface.h -// interface/src/ui/overlays -// -// Created by Zach Fox on 2017-07-14. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#pragma once -#ifndef hifi_ContextOverlayInterface_h -#define hifi_ContextOverlayInterface_h - -#include -#include - -#include -#include -#include -#include "avatar/AvatarManager.h" - -#include "EntityScriptingInterface.h" -#include "scripting/HMDScriptingInterface.h" -#include "scripting/SelectionScriptingInterface.h" -#include "scripting/WalletScriptingInterface.h" - -#include "EntityTree.h" -#include "ContextOverlayLogging.h" - -/**jsdoc - * The ContextOverlay API manages the "i" proof-of-provenance context overlay that appears on Marketplace items - * when a user right-clicks them. - * - * @namespace ContextOverlay - * - * @hifi-interface - * @hifi-client-entity - * @hifi-avatar - * - * @property {boolean} enabled - true if the context overlay is enabled to be displayed, false if it - * is disabled and will never be displayed. - * @property {Uuid} entityWithContextOverlay - The ID of the entity that the context overlay is currently displayed for, - * null if the context overlay is not currently displayed. - * @property {boolean} isInMarketplaceInspectionMode - Currently not used. - */ -class ContextOverlayInterface : public QObject, public Dependency { - Q_OBJECT - - Q_PROPERTY(QUuid entityWithContextOverlay READ getCurrentEntityWithContextOverlay WRITE setCurrentEntityWithContextOverlay) - Q_PROPERTY(bool enabled READ getEnabled WRITE setEnabled) - Q_PROPERTY(bool isInMarketplaceInspectionMode READ getIsInMarketplaceInspectionMode WRITE setIsInMarketplaceInspectionMode) - - QSharedPointer _entityScriptingInterface; - EntityPropertyFlags _entityPropertyFlags; - QSharedPointer _hmdScriptingInterface; - QSharedPointer _tabletScriptingInterface; - QSharedPointer _selectionScriptingInterface; - QUuid _contextOverlayID { UNKNOWN_ENTITY_ID }; -public: - ContextOverlayInterface(); - - /**jsdoc - * Gets the ID of the entity that the context overlay is currently displayed for. - * @function ContextOverlay.getCurrentEntityWithContextOverlay - * @returns {Uuid} - The ID of the entity that the context overlay is currently displayed for, null if the - * context overlay is not currently displayed. - */ - Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; } - - void setCurrentEntityWithContextOverlay(const QUuid& entityID) { _currentEntityWithContextOverlay = entityID; } - void setLastInspectedEntity(const QUuid& entityID) { _challengeOwnershipTimeoutTimer.stop(); } - void setEnabled(bool enabled); - bool getEnabled() { return _enabled; } - bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; } - void setIsInMarketplaceInspectionMode(bool mode) { _isInMarketplaceInspectionMode = mode; } - - /**jsdoc - * Initiates a check on an avatar entity belongs to the user wearing it. The result is returned via - * {@link WalletScriptingInterface.ownershipVerificationSuccess} or - * {@link WalletScriptingInterface.ownershipVerificationFailed}. - *

Warning: Neither of these signals are triggered if the entity is not an avatar entity or is not - * certified.

- * @function ContextOverlay.requestOwnershipVerification - * @param {Uuid} entityID - The ID of the entity to check. - */ - Q_INVOKABLE void requestOwnershipVerification(const QUuid& entityID); - - EntityPropertyFlags getEntityPropertyFlags() { return _entityPropertyFlags; } - -signals: - /**jsdoc - * Triggered when the user clicks on the context overlay. - * @function ContextOverlay.contextOverlayClicked - * @param {Uuid} id - The ID of the entity that the context overlay is for. - * @returns {Signal} - * @example Report when a context overlay is clicked. - * ContextOverlay.contextOverlayClicked.connect(function (id) { - * print("Context overlay clicked for:", id); - * }); - */ - void contextOverlayClicked(const QUuid& currentEntityWithContextOverlay); - -public slots: - - /**jsdoc - * @function ContextOverlay.clickDownOnEntity - * @param {Uuid} id - Entity ID. - * @param {PointerEvent} event - Pointer event. - * @deprecated This method is deprecated and will be removed. - */ - // FIXME: Method shouldn't be in the API. - void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - - /**jsdoc - * @function ContextOverlay.mouseReleaseOnEntity - * @param {Uuid} id - Entity ID. - * @param {PointerEvent} event - Pointer event. - * @deprecated This method is deprecated and will be removed. - */ - // FIXME: Method shouldn't be in the API. - void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); - - /**jsdoc - * Displays or deletes the context overlay as appropriate for the target entity and a pointer event: the context overlay - * must be enabled and the pointer event must be a right-click; if so, then any current context overlay is deleted, and if - * the target entity should have a context overlay then it is displayed. - * @function ContextOverlay.createOrDestroyContextOverlay - * @param {Uuid} entityID - The target entity. - * @param {PointerEvent} pointerEvent - The pointer event. - * @returns {boolean} - true if the context overlay was deleted or displayed on the specified entity, - * false if no action was taken. - */ - bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); - - /**jsdoc - * Deletes the context overlay and removes the entity highlight, if shown. - * @function ContextOverlay.destroyContextOverlay - * @param {Uuid} entityID - The ID of the entity. - * @param {PointerEvent} [event] - Not used. - * @returns {boolean} - true if the context overlay was deleted, false if it wasn't (e.g., it - * wasn't displayed). - */ - bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); - bool destroyContextOverlay(const EntityItemID& entityItemID); - - /**jsdoc - * @function ContextOverlay.contextOverlays_hoverEnterOverlay - * @param {Uuid} id - Overlay ID. - * @param {PointerEvent} event - Pointer event. - * @deprecated This method is deprecated and will be removed. - */ - // FIXME: Method shouldn't be in the API. - void contextOverlays_hoverEnterOverlay(const QUuid& id, const PointerEvent& event); - - /**jsdoc - * @function ContextOverlay.contextOverlays_hoverLeaveOverlay - * @param {Uuid} id - Overlay ID. - * @param {PointerEvent} event - Pointer event. - * @deprecated This method is deprecated and will be removed. - */ - // FIXME: Method shouldn't be in the API. - void contextOverlays_hoverLeaveOverlay(const QUuid& id, const PointerEvent& event); - - /**jsdoc - * @function ContextOverlay.contextOverlays_hoverEnterEntity - * @param {Uuid} id - Entity ID. - * @param {PointerEvent} event - Pointer event. - * @deprecated This method is deprecated and will be removed. - */ - // FIXME: Method shouldn't be in the API. - void contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event); - - /**jsdoc - * @function ContextOverlay.contextOverlays_hoverLeaveEntity - * @param {Uuid} id - Entity ID. - * @param {PointerEvent} event - Pointer event. - * @deprecated This method is deprecated and will be removed. - */ - // FIXME: Method shouldn't be in the API. - void contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event); - - /**jsdoc - * Checks with a context overlay should be displayed for an entity — in particular, whether the item has a non-empty - * certificate ID. - * @function ContextOverlay.contextOverlayFilterPassed - * @param {Uuid} entityID - The ID of the entity to check. - * @returns {boolean} - true if the context overlay should be shown for the entity, false if it - * shouldn't. - * @example Report whether the context overlay should be displayed for entities clicked. - * Entities.clickDownOnEntity.connect(function (id, event) { - * print("Item clicked:", id); - * print("Should display context overlay:", ContextOverlay.contextOverlayFilterPassed(id)); - * }); - */ - bool contextOverlayFilterPassed(const EntityItemID& entityItemID); - -private slots: - void handleChallengeOwnershipReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode); - -private: - - enum { - MAX_SELECTION_COUNT = 16 - }; - bool _verboseLogging { true }; - bool _enabled { true }; - EntityItemID _mouseDownEntity; - quint64 _mouseDownEntityTimestamp; - EntityItemID _currentEntityWithContextOverlay; - QString _entityMarketplaceID; - bool _contextOverlayJustClicked { false }; - - bool _isInMarketplaceInspectionMode { false }; - - void enableEntityHighlight(const EntityItemID& entityItemID); - void disableEntityHighlight(const EntityItemID& entityItemID); - - void deletingEntity(const EntityItemID& entityItemID); - - Q_INVOKABLE void startChallengeOwnershipTimer(const EntityItemID& entityItemID); - QTimer _challengeOwnershipTimeoutTimer; -}; - -#endif // hifi_ContextOverlayInterface_h diff --git a/interface/src/ui/overlays/ContextOverlayLogging.cpp b/interface/src/ui/overlays/ContextOverlayLogging.cpp deleted file mode 100644 index c2c3fb77346..00000000000 --- a/interface/src/ui/overlays/ContextOverlayLogging.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// -// ContextOverlayLogging.cpp -// interface/src/ui/overlays -// -// Created by Zach Fox on 2017-07-17 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "ContextOverlayLogging.h" - -Q_LOGGING_CATEGORY(context_overlay, "hifi.context_overlay") diff --git a/interface/src/ui/overlays/ContextOverlayLogging.h b/interface/src/ui/overlays/ContextOverlayLogging.h deleted file mode 100644 index 182ebc14253..00000000000 --- a/interface/src/ui/overlays/ContextOverlayLogging.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// ContextOverlayLogging.h -// interface/src/ui/overlays -// -// Created by Zach Fox on 2017-07-17 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#pragma once -#ifndef hifi_ContextOverlayLogging_h -#define hifi_ContextOverlayLogging_h - -#include - -Q_DECLARE_LOGGING_CATEGORY(context_overlay) - -#endif // hifi_ContextOverlayLogging_h diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index aaaf7d645a2..6cb0481cead 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -135,9 +135,6 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, #endif queueOctreeEditMessage(type, bufferOut); - if (type == PacketType::EntityAdd && !properties.getCertificateID().isEmpty()) { - emit addingEntityWithCertificate(properties.getCertificateID(), DependencyManager::get()->getPlaceName()); - } } // if we still have properties to send, switch the message type to edit, and request only the packets that didn't fit diff --git a/libraries/entities/src/EntityEditPacketSender.h b/libraries/entities/src/EntityEditPacketSender.h index 3cc2f016f0c..62c124d0702 100644 --- a/libraries/entities/src/EntityEditPacketSender.h +++ b/libraries/entities/src/EntityEditPacketSender.h @@ -43,9 +43,6 @@ class EntityEditPacketSender : public OctreeEditPacketSender { virtual char getMyNodeType() const override { return NodeType::EntityServer; } virtual void adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, qint64 clockSkew) override; -signals: - void addingEntityWithCertificate(const QString& certificateID, const QString& placeName); - public slots: void processEntityEditNackPacket(QSharedPointer message, SharedNodePointer sendingNode); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ddedf0db183..ad20bededf8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -49,7 +49,6 @@ int entityItemPointernMetaTypeId = qRegisterMetaType(); int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; -QString EntityItem::_marketplacePublicKey; std::function EntityItem::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode, const glm::vec3&) { return rotation; }; std::function EntityItem::_getPrimaryViewFrustumPositionOperator = []() { return glm::vec3(0.0f); }; @@ -339,18 +338,18 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_SERVER_SCRIPTS, getServerScripts()); // Certifiable Properties - APPEND_ENTITY_PROPERTY(PROP_ITEM_NAME, getItemName()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, getItemDescription()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, getItemCategories()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_ARTIST, getItemArtist()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_LICENSE, getItemLicense()); - APPEND_ENTITY_PROPERTY(PROP_LIMITED_RUN, getLimitedRun()); - APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID()); - APPEND_ENTITY_PROPERTY(PROP_EDITION_NUMBER, getEditionNumber()); - APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, getEntityInstanceNumber()); - APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, getCertificateID()); - APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_TYPE, getCertificateType()); - APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, getStaticCertificateVersion()); + APPEND_ENTITY_PROPERTY(PROP_ITEM_NAME, QString()); + APPEND_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString()); + APPEND_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString()); + APPEND_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString()); + APPEND_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString()); + APPEND_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32(-1)); + APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString()); + APPEND_ENTITY_PROPERTY(PROP_EDITION_NUMBER, 0U); + APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, 0U); + APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString()); + APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_TYPE, QString()); + APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, 0U); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -945,18 +944,18 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } // Certifiable props - READ_ENTITY_PROPERTY(PROP_ITEM_NAME, QString, setItemName); - READ_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString, setItemDescription); - READ_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString, setItemCategories); - READ_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString, setItemArtist); - READ_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString, setItemLicense); - READ_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32, setLimitedRun); - READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); - READ_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32, setEditionNumber); - READ_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber); - READ_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString, setCertificateID); - READ_ENTITY_PROPERTY(PROP_CERTIFICATE_TYPE, QString, setCertificateType); - READ_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, quint32, setStaticCertificateVersion); + SKIP_ENTITY_PROPERTY(PROP_ITEM_NAME, QString); + SKIP_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString); + SKIP_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString); + SKIP_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString); + SKIP_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString); + SKIP_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32); + SKIP_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString); + SKIP_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32); + SKIP_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32); + SKIP_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString); + SKIP_ENTITY_PROPERTY(PROP_CERTIFICATE_TYPE, QString); + SKIP_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, quint32); bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, somethingChanged); @@ -1392,20 +1391,6 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire COPY_ENTITY_PROPERTY_TO_PROPERTIES(scriptTimestamp, getScriptTimestamp); COPY_ENTITY_PROPERTY_TO_PROPERTIES(serverScripts, getServerScripts); - // Certifiable Properties - COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemName, getItemName); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemDescription, getItemDescription); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemCategories, getItemCategories); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemArtist, getItemArtist); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(itemLicense, getItemLicense); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(limitedRun, getLimitedRun); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(marketplaceID, getMarketplaceID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(editionNumber, getEditionNumber); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(entityInstanceNumber, getEntityInstanceNumber); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(certificateID, getCertificateID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(certificateType, getCertificateType); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(staticCertificateVersion, getStaticCertificateVersion); - // Script local data COPY_ENTITY_PROPERTY_TO_PROPERTIES(localPosition, getLocalPosition); COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRotation, getLocalOrientation); @@ -1543,20 +1528,6 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(scriptTimestamp, setScriptTimestamp); SET_ENTITY_PROPERTY_FROM_PROPERTIES(serverScripts, setServerScripts); - // Certifiable Properties - SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemName, setItemName); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemDescription, setItemDescription); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemCategories, setItemCategories); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemArtist, setItemArtist); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(itemLicense, setItemLicense); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(limitedRun, setLimitedRun); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(marketplaceID, setMarketplaceID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(editionNumber, setEditionNumber); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(entityInstanceNumber, setEntityInstanceNumber); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(certificateID, setCertificateID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(certificateType, setCertificateType); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(staticCertificateVersion, setStaticCertificateVersion); - if (updateQueryAACube()) { somethingChanged = true; } @@ -3131,36 +3102,6 @@ void EntityItem::setPrivateUserData(const QString& value) { }); } -// Certifiable Properties -#define DEFINE_PROPERTY_GETTER(type, accessor, var) \ -type EntityItem::get##accessor() const { \ - type result; \ - withReadLock([&] { \ - result = _##var; \ - }); \ - return result; \ -} - -#define DEFINE_PROPERTY_SETTER(type, accessor, var) \ -void EntityItem::set##accessor(const type & value) { \ - withWriteLock([&] { \ - _##var = value; \ - }); \ -} -#define DEFINE_PROPERTY_ACCESSOR(type, accessor, var) DEFINE_PROPERTY_GETTER(type, accessor, var) DEFINE_PROPERTY_SETTER(type, accessor, var) -DEFINE_PROPERTY_ACCESSOR(QString, ItemName, itemName) -DEFINE_PROPERTY_ACCESSOR(QString, ItemDescription, itemDescription) -DEFINE_PROPERTY_ACCESSOR(QString, ItemCategories, itemCategories) -DEFINE_PROPERTY_ACCESSOR(QString, ItemArtist, itemArtist) -DEFINE_PROPERTY_ACCESSOR(QString, ItemLicense, itemLicense) -DEFINE_PROPERTY_ACCESSOR(quint32, LimitedRun, limitedRun) -DEFINE_PROPERTY_ACCESSOR(QString, MarketplaceID, marketplaceID) -DEFINE_PROPERTY_ACCESSOR(quint32, EditionNumber, editionNumber) -DEFINE_PROPERTY_ACCESSOR(quint32, EntityInstanceNumber, entityInstanceNumber) -DEFINE_PROPERTY_ACCESSOR(QString, CertificateID, certificateID) -DEFINE_PROPERTY_ACCESSOR(QString, CertificateType, certificateType) -DEFINE_PROPERTY_ACCESSOR(quint32, StaticCertificateVersion, staticCertificateVersion) - uint32_t EntityItem::getDirtyFlags() const { uint32_t result; withReadLock([&] { @@ -3236,38 +3177,6 @@ void EntityItem::somethingChangedNotification() { }); } -// static -void EntityItem::retrieveMarketplacePublicKey() { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest; - networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - QUrl requestURL = MetaverseAPI::getCurrentMetaverseServerURL(); - requestURL.setPath("/api/v1/commerce/marketplace_key"); - QJsonObject request; - networkRequest.setUrl(requestURL); - - QNetworkReply* networkReply = NULL; - networkReply = networkAccessManager.get(networkRequest); - - connect(networkReply, &QNetworkReply::finished, [=]() { - QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); - jsonObject = jsonObject["data"].toObject(); - - if (networkReply->error() == QNetworkReply::NoError) { - if (!jsonObject["public_key"].toString().isEmpty()) { - EntityItem::_marketplacePublicKey = jsonObject["public_key"].toString(); - qCWarning(entities) << "Marketplace public key has been set to" << _marketplacePublicKey; - } else { - qCWarning(entities) << "Marketplace public key is empty!"; - } - } else { - qCWarning(entities) << "Call to" << networkRequest.url() << "failed! Error:" << networkReply->error(); - } - - networkReply->deleteLater(); - }); -} - void EntityItem::collectChildrenForDelete(std::vector& entitiesToDelete, const QUuid& sessionID) const { // Deleting an entity has consequences for its children, however there are rules dictating what can be deleted. // This method helps enforce those rules: not for this entity, but for its children. diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 2a6952fc0db..29be79aff4d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -361,32 +361,6 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc bool pendingRelease(uint64_t timestamp) const; bool stillWaitingToTakeOwnership(uint64_t timestamp) const; - // Certifiable Properties - QString getItemName() const; - void setItemName(const QString& value); - QString getItemDescription() const; - void setItemDescription(const QString& value); - QString getItemCategories() const; - void setItemCategories(const QString& value); - QString getItemArtist() const; - void setItemArtist(const QString& value); - QString getItemLicense() const; - void setItemLicense(const QString& value); - quint32 getLimitedRun() const; - void setLimitedRun(const quint32&); - QString getMarketplaceID() const; - void setMarketplaceID(const QString& value); - quint32 getEditionNumber() const; - void setEditionNumber(const quint32&); - quint32 getEntityInstanceNumber() const; - void setEntityInstanceNumber(const quint32&); - QString getCertificateID() const; - void setCertificateID(const QString& value); - QString getCertificateType() const; - void setCertificateType(const QString& value); - quint32 getStaticCertificateVersion() const; - void setStaticCertificateVersion(const quint32&); - bool getCloneable() const; void setCloneable(bool value); float getCloneLifetime() const; @@ -543,9 +517,6 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc ChangeHandlerId registerChangeHandler(const ChangeHandlerCallback& handler); void deregisterChangeHandler(const ChangeHandlerId& changeHandlerId); - static QString _marketplacePublicKey; - static void retrieveMarketplacePublicKey(); - void collectChildrenForDelete(std::vector& entitiesToDelete, const QUuid& sessionID) const; float getBoundingRadius() const { return _boundingRadius; } @@ -670,20 +641,6 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc QString _href; //Hyperlink href QString _description; //Hyperlink description - // Certifiable Properties - QString _itemName { ENTITY_ITEM_DEFAULT_ITEM_NAME }; - QString _itemDescription { ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION }; - QString _itemCategories { ENTITY_ITEM_DEFAULT_ITEM_CATEGORIES }; - QString _itemArtist { ENTITY_ITEM_DEFAULT_ITEM_ARTIST }; - QString _itemLicense { ENTITY_ITEM_DEFAULT_ITEM_LICENSE }; - quint32 _limitedRun { ENTITY_ITEM_DEFAULT_LIMITED_RUN }; - QString _certificateID { ENTITY_ITEM_DEFAULT_CERTIFICATE_ID }; - QString _certificateType { ENTITY_ITEM_DEFAULT_CERTIFICATE_TYPE }; - quint32 _editionNumber { ENTITY_ITEM_DEFAULT_EDITION_NUMBER }; - quint32 _entityInstanceNumber { ENTITY_ITEM_DEFAULT_ENTITY_INSTANCE_NUMBER }; - QString _marketplaceID { ENTITY_ITEM_DEFAULT_MARKETPLACE_ID }; - quint32 _staticCertificateVersion { ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION }; - // NOTE: Damping is applied like this: v *= pow(1 - damping, dt) // diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index d671d46c22a..50b4f1c3ebb 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -464,20 +464,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); CHECK_PROPERTY_CHANGE(PROP_SERVER_SCRIPTS, serverScripts); - // Certifiable Properties - CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); - CHECK_PROPERTY_CHANGE(PROP_ITEM_DESCRIPTION, itemDescription); - CHECK_PROPERTY_CHANGE(PROP_ITEM_CATEGORIES, itemCategories); - CHECK_PROPERTY_CHANGE(PROP_ITEM_ARTIST, itemArtist); - CHECK_PROPERTY_CHANGE(PROP_ITEM_LICENSE, itemLicense); - CHECK_PROPERTY_CHANGE(PROP_LIMITED_RUN, limitedRun); - CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID); - CHECK_PROPERTY_CHANGE(PROP_EDITION_NUMBER, editionNumber); - CHECK_PROPERTY_CHANGE(PROP_ENTITY_INSTANCE_NUMBER, entityInstanceNumber); - CHECK_PROPERTY_CHANGE(PROP_CERTIFICATE_ID, certificateID); - CHECK_PROPERTY_CHANGE(PROP_CERTIFICATE_TYPE, certificateType); - CHECK_PROPERTY_CHANGE(PROP_STATIC_CERTIFICATE_VERSION, staticCertificateVersion); - // Location data for scripts CHECK_PROPERTY_CHANGE(PROP_LOCAL_POSITION, localPosition); CHECK_PROPERTY_CHANGE(PROP_LOCAL_ROTATION, localRotation); @@ -812,23 +798,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * * @property {Entities.Grab} grab - The entity's grab-related properties. * - * @property {string} itemName="" - Certifiable name of the Marketplace item. - * @property {string} itemDescription="" - Certifiable description of the Marketplace item. - * @property {string} itemCategories="" - Certifiable category of the Marketplace item. - * @property {string} itemArtist="" - Certifiable artist that created the Marketplace item. - * @property {string} itemLicense="" - Certifiable license URL for the Marketplace item. - * @property {number} limitedRun=4294967295 - Certifiable maximum integer number of editions (copies) of the Marketplace item - * allowed to be sold. - * @property {number} editionNumber=0 - Certifiable integer edition (copy) number or the Marketplace item. Each copy sold in - * the Marketplace is numbered sequentially, starting at 1. - * @property {number} entityInstanceNumber=0 - Certifiable integer instance number for identical entities in a Marketplace - * item. A Marketplace item may have multiple, identical parts. If so, then each is numbered sequentially with an instance - * number. - * @property {string} marketplaceID="" - Certifiable UUID for the Marketplace item, as used in the URL of the item's download - * and its Marketplace Web page. - * @property {string} certificateID="" - Hash of the entity's static certificate JSON, signed by the artist's private key. - * @property {number} staticCertificateVersion=0 - The version of the method used to generate the certificateID. - * * @comment The different entity types have additional properties as follows: * @see {@link Entities.EntityProperties-Box|EntityProperties-Box} * @see {@link Entities.EntityProperties-Gizmo|EntityProperties-Gizmo} @@ -1641,20 +1610,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SERVER_SCRIPTS, serverScripts); - // Certifiable Properties - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_NAME, itemName); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_DESCRIPTION, itemDescription); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_CATEGORIES, itemCategories); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_ARTIST, itemArtist); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_LICENSE, itemLicense); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIMITED_RUN, limitedRun); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EDITION_NUMBER, editionNumber); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ENTITY_INSTANCE_NUMBER, entityInstanceNumber); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CERTIFICATE_ID, certificateID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CERTIFICATE_TYPE, certificateType); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STATIC_CERTIFICATE_VERSION, staticCertificateVersion); - // Local props for scripts COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); @@ -2063,20 +2018,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(scriptTimestamp, quint64, setScriptTimestamp); COPY_PROPERTY_FROM_QSCRIPTVALUE(serverScripts, QString, setServerScripts); - // Certifiable Properties - COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); - COPY_PROPERTY_FROM_QSCRIPTVALUE(itemDescription, QString, setItemDescription); - COPY_PROPERTY_FROM_QSCRIPTVALUE(itemCategories, QString, setItemCategories); - COPY_PROPERTY_FROM_QSCRIPTVALUE(itemArtist, QString, setItemArtist); - COPY_PROPERTY_FROM_QSCRIPTVALUE(itemLicense, QString, setItemLicense); - COPY_PROPERTY_FROM_QSCRIPTVALUE(limitedRun, quint32, setLimitedRun); - COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(editionNumber, quint32, setEditionNumber); - COPY_PROPERTY_FROM_QSCRIPTVALUE(entityInstanceNumber, quint32, setEntityInstanceNumber); - COPY_PROPERTY_FROM_QSCRIPTVALUE(certificateID, QString, setCertificateID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(certificateType, QString, setCertificateType); - COPY_PROPERTY_FROM_QSCRIPTVALUE(staticCertificateVersion, quint32, setStaticCertificateVersion); - // Script location data COPY_PROPERTY_FROM_QSCRIPTVALUE(localPosition, vec3, setLocalPosition); COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, quat, setLocalRotation); @@ -2354,20 +2295,6 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(scriptTimestamp); COPY_PROPERTY_IF_CHANGED(serverScripts); - // Certifiable Properties - COPY_PROPERTY_IF_CHANGED(itemName); - COPY_PROPERTY_IF_CHANGED(itemDescription); - COPY_PROPERTY_IF_CHANGED(itemCategories); - COPY_PROPERTY_IF_CHANGED(itemArtist); - COPY_PROPERTY_IF_CHANGED(itemLicense); - COPY_PROPERTY_IF_CHANGED(limitedRun); - COPY_PROPERTY_IF_CHANGED(marketplaceID); - COPY_PROPERTY_IF_CHANGED(editionNumber); - COPY_PROPERTY_IF_CHANGED(entityInstanceNumber); - COPY_PROPERTY_IF_CHANGED(certificateID); - COPY_PROPERTY_IF_CHANGED(certificateType); - COPY_PROPERTY_IF_CHANGED(staticCertificateVersion); - // Local props for scripts COPY_PROPERTY_IF_CHANGED(localPosition); COPY_PROPERTY_IF_CHANGED(localRotation); @@ -2678,20 +2605,6 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr ADD_PROPERTY_TO_MAP(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64); ADD_PROPERTY_TO_MAP(PROP_SERVER_SCRIPTS, ServerScripts, serverScripts, QString); - // Certifiable Properties - ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); - ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString); - ADD_PROPERTY_TO_MAP(PROP_ITEM_CATEGORIES, ItemCategories, itemCategories, QString); - ADD_PROPERTY_TO_MAP(PROP_ITEM_ARTIST, ItemArtist, itemArtist, QString); - ADD_PROPERTY_TO_MAP(PROP_ITEM_LICENSE, ItemLicense, itemLicense, QString); - ADD_PROPERTY_TO_MAP(PROP_LIMITED_RUN, LimitedRun, limitedRun, quint32); - ADD_PROPERTY_TO_MAP(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString); - ADD_PROPERTY_TO_MAP(PROP_EDITION_NUMBER, EditionNumber, editionNumber, quint32); - ADD_PROPERTY_TO_MAP(PROP_ENTITY_INSTANCE_NUMBER, EntityInstanceNumber, entityInstanceNumber, quint32); - ADD_PROPERTY_TO_MAP(PROP_CERTIFICATE_ID, CertificateID, certificateID, QString); - ADD_PROPERTY_TO_MAP(PROP_CERTIFICATE_TYPE, CertificateType, certificateType, QString); - ADD_PROPERTY_TO_MAP(PROP_STATIC_CERTIFICATE_VERSION, StaticCertificateVersion, staticCertificateVersion, quint32); - // Local script props ADD_PROPERTY_TO_MAP(PROP_LOCAL_POSITION, LocalPosition, localPosition, vec3); ADD_PROPERTY_TO_MAP(PROP_LOCAL_ROTATION, LocalRotation, localRotation, quat); @@ -3142,20 +3055,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, properties.getScriptTimestamp()); APPEND_ENTITY_PROPERTY(PROP_SERVER_SCRIPTS, properties.getServerScripts()); - // Certifiable Properties - APPEND_ENTITY_PROPERTY(PROP_ITEM_NAME, properties.getItemName()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, properties.getItemDescription()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, properties.getItemCategories()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_ARTIST, properties.getItemArtist()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_LICENSE, properties.getItemLicense()); - APPEND_ENTITY_PROPERTY(PROP_LIMITED_RUN, properties.getLimitedRun()); - APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID()); - APPEND_ENTITY_PROPERTY(PROP_EDITION_NUMBER, properties.getEditionNumber()); - APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, properties.getEntityInstanceNumber()); - APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, properties.getCertificateID()); - APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_TYPE, properties.getCertificateType()); - APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, properties.getStaticCertificateVersion()); - if (properties.getType() == EntityTypes::ParticleEffect) { APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType())); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL()); @@ -3632,20 +3531,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SERVER_SCRIPTS, QString, setServerScripts); - // Certifiable Properties - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_NAME, QString, setItemName); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_DESCRIPTION, QString, setItemDescription); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_CATEGORIES, QString, setItemCategories); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_ARTIST, QString, setItemArtist); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ITEM_LICENSE, QString, setItemLicense); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIMITED_RUN, quint32, setLimitedRun); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EDITION_NUMBER, quint32, setEditionNumber); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CERTIFICATE_ID, QString, setCertificateID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CERTIFICATE_TYPE, QString, setCertificateType); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STATIC_CERTIFICATE_VERSION, quint32, setStaticCertificateVersion); - if (properties.getType() == EntityTypes::ParticleEffect) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); @@ -4052,20 +3937,6 @@ void EntityItemProperties::markAllChanged() { _scriptTimestampChanged = true; _serverScriptsChanged = true; - // Certifiable Properties - _itemNameChanged = true; - _itemDescriptionChanged = true; - _itemCategoriesChanged = true; - _itemArtistChanged = true; - _itemLicenseChanged = true; - _limitedRunChanged = true; - _marketplaceIDChanged = true; - _editionNumberChanged = true; - _entityInstanceNumberChanged = true; - _certificateIDChanged = true; - _certificateTypeChanged = true; - _staticCertificateVersionChanged = true; - // Common _shapeTypeChanged = true; _compoundShapeURLChanged = true; @@ -4507,44 +4378,6 @@ QList EntityItemProperties::listChangedProperties() { out += "serverScripts"; } - // Certifiable Properties - if (itemNameChanged()) { - out += "itemName"; - } - if (itemDescriptionChanged()) { - out += "itemDescription"; - } - if (itemCategoriesChanged()) { - out += "itemCategories"; - } - if (itemArtistChanged()) { - out += "itemArtist"; - } - if (itemLicenseChanged()) { - out += "itemLicense"; - } - if (limitedRunChanged()) { - out += "limitedRun"; - } - if (marketplaceIDChanged()) { - out += "marketplaceID"; - } - if (editionNumberChanged()) { - out += "editionNumber"; - } - if (entityInstanceNumberChanged()) { - out += "entityInstanceNumber"; - } - if (certificateIDChanged()) { - out += "certificateID"; - } - if (certificateTypeChanged()) { - out += "certificateType"; - } - if (staticCertificateVersionChanged()) { - out += "staticCertificateVersion"; - } - // Common if (shapeTypeChanged()) { out += "shapeType"; @@ -4982,133 +4815,6 @@ bool EntityItemProperties::grabbingRelatedPropertyChanged() const { grabProperties.equippableIndicatorScaleChanged() || grabProperties.equippableIndicatorOffsetChanged(); } -// Checking Certifiable Properties -#define ADD_STRING_PROPERTY(n, N) if (!get##N().isEmpty()) json[#n] = get##N() -#define ADD_ENUM_PROPERTY(n, N) json[#n] = get##N##AsString() -#define ADD_INT_PROPERTY(n, N) if (get##N() != 0) json[#n] = (get##N() == (quint32) -1) ? -1.0 : ((double) get##N()) -QByteArray EntityItemProperties::getStaticCertificateJSON() const { - // Produce a compact json of every non-default static certificate property, with the property names in alphabetical order. - // The static certificate properties include all an only those properties that cannot be changed without altering the identity - // of the entity as reviewed during the certification submission. - - QJsonObject json; - - quint32 staticCertificateVersion = getStaticCertificateVersion(); - - if (!getAnimation().getURL().isEmpty()) { - json["animationURL"] = getAnimation().getURL(); - } - if (staticCertificateVersion >= 3) { - ADD_STRING_PROPERTY(certificateType, CertificateType); - } - ADD_STRING_PROPERTY(collisionSoundURL, CollisionSoundURL); - ADD_STRING_PROPERTY(compoundShapeURL, CompoundShapeURL); - ADD_INT_PROPERTY(editionNumber, EditionNumber); - ADD_INT_PROPERTY(entityInstanceNumber, EntityInstanceNumber); - ADD_STRING_PROPERTY(itemArtist, ItemArtist); - ADD_STRING_PROPERTY(itemCategories, ItemCategories); - ADD_STRING_PROPERTY(itemDescription, ItemDescription); - ADD_STRING_PROPERTY(itemLicenseUrl, ItemLicense); - ADD_STRING_PROPERTY(itemName, ItemName); - ADD_INT_PROPERTY(limitedRun, LimitedRun); - ADD_STRING_PROPERTY(marketplaceID, MarketplaceID); - ADD_STRING_PROPERTY(modelURL, ModelURL); - ADD_STRING_PROPERTY(script, Script); - if (staticCertificateVersion >= 1) { - ADD_STRING_PROPERTY(serverScripts, ServerScripts); - } - ADD_ENUM_PROPERTY(shapeType, ShapeType); - ADD_INT_PROPERTY(staticCertificateVersion, StaticCertificateVersion); - json["type"] = EntityTypes::getEntityTypeName(getType()); - - return QJsonDocument(json).toJson(QJsonDocument::Compact); -} -QByteArray EntityItemProperties::getStaticCertificateHash() const { - return QCryptographicHash::hash(getStaticCertificateJSON(), QCryptographicHash::Sha256); -} - -// FIXME: This is largely copied from EntityItemProperties::verifyStaticCertificateProperties, which should be refactored to use this. -// I also don't like the nested-if style, but for this step I'm deliberately preserving the similarity. -bool EntityItemProperties::verifySignature(const QString& publicKey, const QByteArray& digestByteArray, const QByteArray& signatureByteArray) { - - if (digestByteArray.isEmpty()) { - return false; - } - - auto keyByteArray = publicKey.toUtf8(); - auto key = keyByteArray.constData(); - int keyLength = publicKey.length(); - - BIO *bio = BIO_new_mem_buf((void*)key, keyLength); - EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); - if (evp_key) { - EC_KEY* ec = EVP_PKEY_get1_EC_KEY(evp_key); - if (ec) { - const unsigned char* digest = reinterpret_cast(digestByteArray.constData()); - int digestLength = digestByteArray.length(); - - const unsigned char* signature = reinterpret_cast(signatureByteArray.constData()); - int signatureLength = signatureByteArray.length(); - - ERR_clear_error(); - // ECSDA verification prototype: note that type is currently ignored - // int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, - // const unsigned char *sig, int siglen, EC_KEY *eckey); - int answer = ECDSA_verify(0, - digest, - digestLength, - signature, - signatureLength, - ec); - long error = ERR_get_error(); - if (error != 0 || answer == -1) { - qCWarning(entities) << "ERROR while verifying signature!" - << "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength - << "\nDigest:" << digest << "\nDigest Length:" << digestLength - << "\nSignature:" << signature << "\nSignature Length:" << signatureLength; - while (error != 0) { - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "EC error:" << error_str; - error = ERR_get_error(); - } - } - EC_KEY_free(ec); - if (bio) { - BIO_free(bio); - } - if (evp_key) { - EVP_PKEY_free(evp_key); - } - return (answer == 1); - } else { - if (bio) { - BIO_free(bio); - } - if (evp_key) { - EVP_PKEY_free(evp_key); - } - long error = ERR_get_error(); - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "Failed to verify signature! key" << publicKey << " EC key error:" << error_str; - return false; - } - } else { - if (bio) { - BIO_free(bio); - } - long error = ERR_get_error(); - const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "Failed to verify signature! key" << publicKey << " EC PEM error:" << error_str; - return false; - } -} - -bool EntityItemProperties::verifyStaticCertificateProperties() { - // True IFF a non-empty certificateID matches the static certificate json. - // I.e., if we can verify that the certificateID was produced by Vircadia signing the static certificate hash. - return verifySignature(EntityItem::_marketplacePublicKey, getStaticCertificateHash(), QByteArray::fromBase64(getCertificateID().toUtf8())); -} - void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityIDToClone) { setName(getName() + "-clone-" + entityIDToClone.toString()); setLocked(false); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index efc8b5dc33c..e48c8be086e 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -228,20 +228,6 @@ class EntityItemProperties { DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP); DEFINE_PROPERTY_REF(PROP_SERVER_SCRIPTS, ServerScripts, serverScripts, QString, ENTITY_ITEM_DEFAULT_SERVER_SCRIPTS); - // Certifiable Properties - related to Proof of Purchase certificates - DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); - DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION); - DEFINE_PROPERTY_REF(PROP_ITEM_CATEGORIES, ItemCategories, itemCategories, QString, ENTITY_ITEM_DEFAULT_ITEM_CATEGORIES); - DEFINE_PROPERTY_REF(PROP_ITEM_ARTIST, ItemArtist, itemArtist, QString, ENTITY_ITEM_DEFAULT_ITEM_ARTIST); - DEFINE_PROPERTY_REF(PROP_ITEM_LICENSE, ItemLicense, itemLicense, QString, ENTITY_ITEM_DEFAULT_ITEM_LICENSE); - DEFINE_PROPERTY_REF(PROP_LIMITED_RUN, LimitedRun, limitedRun, quint32, ENTITY_ITEM_DEFAULT_LIMITED_RUN); - DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID); - DEFINE_PROPERTY_REF(PROP_EDITION_NUMBER, EditionNumber, editionNumber, quint32, ENTITY_ITEM_DEFAULT_EDITION_NUMBER); - DEFINE_PROPERTY_REF(PROP_ENTITY_INSTANCE_NUMBER, EntityInstanceNumber, entityInstanceNumber, quint32, ENTITY_ITEM_DEFAULT_ENTITY_INSTANCE_NUMBER); - DEFINE_PROPERTY_REF(PROP_CERTIFICATE_ID, CertificateID, certificateID, QString, ENTITY_ITEM_DEFAULT_CERTIFICATE_ID); - DEFINE_PROPERTY_REF(PROP_CERTIFICATE_TYPE, CertificateType, certificateType, QString, ENTITY_ITEM_DEFAULT_CERTIFICATE_TYPE); - DEFINE_PROPERTY_REF(PROP_STATIC_CERTIFICATE_VERSION, StaticCertificateVersion, staticCertificateVersion, quint32, ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION); - // these are used when bouncing location data into and out of scripts DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glm::vec3, ENTITY_ITEM_ZERO_VEC3); DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, quat, ENTITY_ITEM_DEFAULT_ROTATION); @@ -496,11 +482,6 @@ class EntityItemProperties { QByteArray getPackedStrokeColors() const; QByteArray packStrokeColors(const QVector& strokeColors) const; - QByteArray getStaticCertificateJSON() const; - QByteArray getStaticCertificateHash() const; - bool verifyStaticCertificateProperties(); - static bool verifySignature(const QString& key, const QByteArray& text, const QByteArray& signature); - void convertToCloneProperties(const EntityItemID& entityIDToClone); protected: @@ -639,20 +620,6 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusStart, radiusStart, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusFinish, radiusFinish, ""); - // Certifiable Properties - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemName, itemName, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemDescription, itemDescription, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemCategories, itemCategories, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemArtist, itemArtist, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ItemLicense, itemLicense, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, LimitedRun, limitedRun, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, EditionNumber, editionNumber, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, EntityInstanceNumber, entityInstanceNumber, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CertificateID, certificateID, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CertificateType, certificateType, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, StaticCertificateVersion, staticCertificateVersion, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalPosition, localPosition, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalRotation, localRotation, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalVelocity, localVelocity, ""); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index cc12eb37b47..c9ecff41f22 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -31,20 +31,6 @@ const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); const QString ENTITY_ITEM_DEFAULT_PRIVATE_USER_DATA = QString(""); const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid(); -// Certifiable Properties -const QString ENTITY_ITEM_DEFAULT_ITEM_NAME = QString(""); -const QString ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION = QString(""); -const QString ENTITY_ITEM_DEFAULT_ITEM_CATEGORIES = QString(""); -const QString ENTITY_ITEM_DEFAULT_ITEM_ARTIST = QString(""); -const QString ENTITY_ITEM_DEFAULT_ITEM_LICENSE = QString(""); -const quint32 ENTITY_ITEM_DEFAULT_LIMITED_RUN = -1; -const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString(""); -const quint32 ENTITY_ITEM_DEFAULT_EDITION_NUMBER = 0; -const quint32 ENTITY_ITEM_DEFAULT_ENTITY_INSTANCE_NUMBER = 0; -const QString ENTITY_ITEM_DEFAULT_CERTIFICATE_ID = QString(""); -const QString ENTITY_ITEM_DEFAULT_CERTIFICATE_TYPE = QString(""); -const quint32 ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION = 0; - const glm::u8vec3 ENTITY_ITEM_DEFAULT_COLOR = { 255, 255, 255 }; const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f; const bool ENTITY_ITEM_DEFAULT_VISIBLE = true; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index fd83c99ca5e..cc8419e11eb 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -53,8 +53,6 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership connect(nodeList.data(), &NodeList::isAllowedEditorChanged, this, &EntityScriptingInterface::canAdjustLocksChanged); connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptingInterface::canRezChanged); connect(nodeList.data(), &NodeList::canRezTmpChanged, this, &EntityScriptingInterface::canRezTmpChanged); - connect(nodeList.data(), &NodeList::canRezCertifiedChanged, this, &EntityScriptingInterface::canRezCertifiedChanged); - connect(nodeList.data(), &NodeList::canRezTmpCertifiedChanged, this, &EntityScriptingInterface::canRezTmpCertifiedChanged); connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged); connect(nodeList.data(), &NodeList::canGetAndSetPrivateUserDataChanged, this, &EntityScriptingInterface::canGetAndSetPrivateUserDataChanged); @@ -88,16 +86,6 @@ bool EntityScriptingInterface::canRezTmp() { return nodeList->getThisNodeCanRezTmp(); } -bool EntityScriptingInterface::canRezCertified() { - auto nodeList = DependencyManager::get(); - return nodeList->getThisNodeCanRezCertified(); -} - -bool EntityScriptingInterface::canRezTmpCertified() { - auto nodeList = DependencyManager::get(); - return nodeList->getThisNodeCanRezTmpCertified(); -} - bool EntityScriptingInterface::canWriteAssets() { auto nodeList = DependencyManager::get(); return nodeList->getThisNodeCanWriteAssets(); @@ -2264,32 +2252,6 @@ glm::mat4 EntityScriptingInterface::getEntityLocalTransform(const QUuid& entityI return result; } -QString EntityScriptingInterface::getStaticCertificateJSON(const QUuid& entityID) { - QByteArray result; - if (_entityTree) { - _entityTree->withReadLock([&] { - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); - if (entity) { - result = entity->getProperties().getStaticCertificateJSON(); - } - }); - } - return result; -} - -bool EntityScriptingInterface::verifyStaticCertificateProperties(const QUuid& entityID) { - bool result = false; - if (_entityTree) { - _entityTree->withReadLock([&] { - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); - if (entity) { - result = entity->getProperties().verifyStaticCertificateProperties(); - } - }); - } - return result; -} - const EntityPropertyInfo EntityScriptingInterface::getPropertyInfo(const QString& propertyName) const { EntityPropertyInfo propertyInfo; EntityItemProperties::getPropertyInfo(propertyName, propertyInfo); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index dae0922f4a7..59ca2f314e3 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -243,25 +243,6 @@ public slots: */ Q_INVOKABLE bool canRezTmp(); - /**jsdoc - * Checks whether or not the script can rez (create) new certified entities in the domain. Certified entities are entities - * that have PoP certificates. - * @function Entities.canRezCertified - * @returns {boolean} true if the domain server will allow the script to rez (create) new certified entities, - * otherwise false. - */ - Q_INVOKABLE bool canRezCertified(); - - /**jsdoc - * Checks whether or not the script can rez (create) new temporary certified entities in the domain. Temporary entities are - * entities with a finite lifetime property value set. Certified entities are entities that have PoP - * certificates. - * @function Entities.canRezTmpCertified - * @returns {boolean} true if the domain server will allow the script to rez (create) new temporary certified - * entities, otherwise false. - */ - Q_INVOKABLE bool canRezTmpCertified(); - /**jsdoc * Checks whether or not the script can make changes to the asset server's assets. * @function Entities.canWriteAssets @@ -2104,25 +2085,6 @@ public slots: int parentJointIndex = -1, bool scalesWithParent = false); - /**jsdoc - * Gets the static certificate for an entity. The static certificate contains static properties of the item which cannot - * be altered. - * @function Entities.getStaticCertificateJSON - * @param {Uuid} entityID - The ID of the entity to get the static certificate for. - * @returns {string} The entity's static certificate as a JSON string if the entity can be found, otherwise "". - */ - Q_INVOKABLE QString getStaticCertificateJSON(const QUuid& entityID); - - /**jsdoc - * Verifies the entity's proof of provenance, i.e., that the entity's certificateID property was produced by - * High Fidelity signing the entity's static certificate JSON. - * @function Entities.verifyStaticCertificateProperties - * @param {Uuid} entityID - The ID of the entity to verify. - * @returns {boolean} true if the entity can be found, its certificateID property is present, and - * its value matches the entity's static certificate JSON; otherwise false. - */ - Q_INVOKABLE bool verifyStaticCertificateProperties(const QUuid& entityID); - /**jsdoc * Gets information about an entity property, including a minimum to maximum range for some numerical properties. * @function Entities.getPropertyInfo @@ -2209,26 +2171,6 @@ public slots: */ void canRezTmpChanged(bool canRezTmp); - /**jsdoc - * Triggered when your ability to rez (create) certified entities changes. Certified entities are entities that have PoP - * certificates. - * @function Entities.canRezCertifiedChanged - * @param {boolean} canRezCertified - true if the script can rez (create) certified entities, - * false if it can't. - * @returns {Signal} - */ - void canRezCertifiedChanged(bool canRezCertified); - - /**jsdoc - * Triggered when your ability to rez (create) temporary certified entities changes. Temporary entities are entities with a - * finite lifetime property value set. Certified entities are entities that have PoP certificates. - * @function Entities.canRezTmpCertifiedChanged - * @param {boolean} canRezTmpCertified - true if the script can rez (create) temporary certified entities, - * false if it can't. - * @returns {Signal} - */ - void canRezTmpCertifiedChanged(bool canRezTmpCertified); - /**jsdoc * Triggered when your ability to make changes to the asset server's assets changes. * @function Entities.canWriteAssetsChanged diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index e6f5e36202c..681c165bfa8 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -50,8 +50,6 @@ EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage) { resetClientEditStats(); - - EntityItem::retrieveMarketplacePublicKey(); } EntityTree::~EntityTree() { @@ -290,10 +288,6 @@ bool EntityTree::handlesEditPacketType(PacketType packetType) const { void EntityTree::postAddEntity(EntityItemPointer entity) { assert(entity); - if (getIsServer()) { - addCertifiedEntityOnServer(entity); - } - // check to see if we need to simulate this entity.. if (_simulation) { _simulation->addEntity(entity); @@ -548,7 +542,6 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti if (properties.getEntityHostType() == entity::HostType::DOMAIN && getIsClient() && !nodeList->getThisNodeCanRez() && !nodeList->getThisNodeCanRezTmp() && - !nodeList->getThisNodeCanRezCertified() && !nodeList->getThisNodeCanRezTmpCertified() && !_serverlessDomain && !isClone && !isImport) { return nullptr; } @@ -763,8 +756,6 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) foreach(const EntityToDeleteDetails& details, entities) { EntityItemPointer theEntity = details.entity; if (getIsServer()) { - removeCertifiedEntityOnServer(theEntity); - // set up the deleted entities ID QWriteLocker recentlyDeletedEntitiesLocker(&_recentlyDeletedEntitiesLock); _recentlyDeletedEntityItemIDs.insert(deletedAt, theEntity->getEntityItemID()); @@ -1433,367 +1424,6 @@ bool EntityTree::isScriptInWhitelist(const QString& scriptProperty) { return false; } -void EntityTree::addCertifiedEntityOnServer(EntityItemPointer entity) { - QString certID(entity->getCertificateID()); - EntityItemID existingEntityItemID; - if (!certID.isEmpty()) { - EntityItemID entityItemID = entity->getEntityItemID(); - QWriteLocker locker(&_entityCertificateIDMapLock); - QList& entityList = _entityCertificateIDMap[certID]; // inserts it if needed. - if (!entityList.isEmpty() && !entity->getCertificateType().contains(DOMAIN_UNLIMITED)) { - existingEntityItemID = entityList.first(); // we will only care about the first, if any, below. - entityList.removeOne(existingEntityItemID); - } - entityList << entityItemID; // adds to list within hash because entityList is a reference. - qCDebug(entities) << "Certificate ID" << certID << "belongs to" << entityItemID << "total" << entityList.size() << "entities."; - } - // Handle an already-existing entity from the tree if it has the same - // CertificateID as the entity we're trying to add. - if (!existingEntityItemID.isNull()) { - qCDebug(entities) << "Certificate ID" << certID << "already exists on entity with ID" - << existingEntityItemID << ". No action will be taken to remove it."; - // FIXME: All certificate checking needs to be moved to its own files, - // then the deletion settings need to have a toggle for domain owners - // and a setting to change the verification service provider. - // withWriteLock([&] { - // deleteEntity(existingEntityItemID, true); - // }); - } -} - -void EntityTree::removeCertifiedEntityOnServer(EntityItemPointer entity) { - QString certID = entity->getCertificateID(); - if (!certID.isEmpty()) { - QWriteLocker entityCertificateIDMapLocker(&_entityCertificateIDMapLock); - QList& entityList = _entityCertificateIDMap[certID]; - entityList.removeOne(entity->getEntityItemID()); - if (entityList.isEmpty()) { - // hmmm, do we to make it be a hash instead of a list, so that this is faster if you stamp out 1000 of a domainUnlimited? - _entityCertificateIDMap.remove(certID); - } - } -} - -void EntityTree::startDynamicDomainVerificationOnServer(float minimumAgeToRemove) { - QReadLocker locker(&_entityCertificateIDMapLock); - QHashIterator> i(_entityCertificateIDMap); - qCDebug(entities) << _entityCertificateIDMap.size() << "certificates present."; - while (i.hasNext()) { - i.next(); - const auto& certificateID = i.key(); - const auto& entityIDs = i.value(); - if (entityIDs.isEmpty()) { - continue; - } - - // Examine each cert: - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest; - networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - QUrl requestURL = MetaverseAPI::getCurrentMetaverseServerURL(); - requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/location"); - QJsonObject request; - request["certificate_id"] = certificateID; - networkRequest.setUrl(requestURL); - - QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); - - connect(networkReply, &QNetworkReply::finished, this, [this, entityIDs, networkReply, minimumAgeToRemove, certificateID] { - - QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); - jsonObject = jsonObject["data"].toObject(); - bool failure = networkReply->error() != QNetworkReply::NoError; - auto failureReason = networkReply->error(); - networkReply->deleteLater(); - if (failure) { - qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << failureReason - << "; NOT deleting cert" << certificateID << "More info:" << jsonObject; - return; - } - QString thisDomainID = DependencyManager::get()->getDomainID().remove(QRegExp("\\{|\\}")); - if (jsonObject["domain_id"].toString() == thisDomainID) { - // Entity belongs here. Nothing to do. - return; - } - // Entity does not belong here: - QList retained; - for (int i = 0; i < entityIDs.size(); i++) { - EntityItemID entityID = entityIDs.at(i); - EntityItemPointer entity = findEntityByEntityItemID(entityID); - if (!entity) { - qCDebug(entities) << "Entity undergoing dynamic domain verification is no longer available:" << entityID; - continue; - } - if (entity->getAge() <= minimumAgeToRemove) { - qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << entityID; - retained << entityID; - continue; - } - qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() - << "doesn't match the current Domain ID" << thisDomainID << ". No action will be taken to remove it: " << entityID; - // FIXME: All certificate checking needs to be moved to its own files, - // then the deletion settings need to have a toggle for domain owners - // and a setting to change the verification service provider. - // withWriteLock([&] { - // deleteEntity(entityID, true); - // }); - } - { - QWriteLocker entityCertificateIDMapLocker(&_entityCertificateIDMapLock); - if (retained.isEmpty()) { - qCDebug(entities) << "Removed" << certificateID; - _entityCertificateIDMap.remove(certificateID); - } else { - qCDebug(entities) << "Retained" << retained.size() << "young entities for" << certificateID; - _entityCertificateIDMap[certificateID] = retained; - } - } - }); - } -} - -void EntityTree::startChallengeOwnershipTimer(const EntityItemID& entityItemID) { - QTimer* _challengeOwnershipTimeoutTimer = new QTimer(this); - connect(this, &EntityTree::killChallengeOwnershipTimeoutTimer, this, [=](const EntityItemID& id) { - if (entityItemID == id && _challengeOwnershipTimeoutTimer) { - _challengeOwnershipTimeoutTimer->stop(); - _challengeOwnershipTimeoutTimer->deleteLater(); - } - }); - connect(_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() { - qCDebug(entities) << "Ownership challenge timed out for entity " << entityItemID << ". No action will be taken to remove it."; - // FIXME: All certificate checking needs to be moved to its own files, - // then the deletion settings need to have a toggle for domain owners - // and a setting to change the verification service provider. - // withWriteLock([&] { - // deleteEntity(entityItemID, true); - // }); - if (_challengeOwnershipTimeoutTimer) { - _challengeOwnershipTimeoutTimer->stop(); - _challengeOwnershipTimeoutTimer->deleteLater(); - } - }); - _challengeOwnershipTimeoutTimer->setSingleShot(true); - _challengeOwnershipTimeoutTimer->start(5000); -} - -QByteArray EntityTree::computeNonce(const EntityItemID& entityID, const QString ownerKey) { - QUuid nonce = QUuid::createUuid(); //random, 5-hex value, separated by "-" - QByteArray nonceBytes = nonce.toByteArray(); - - QWriteLocker locker(&_entityNonceMapLock); - _entityNonceMap.insert(entityID, QPair(nonce, ownerKey)); - - return nonceBytes; -} - -bool EntityTree::verifyNonce(const EntityItemID& entityID, const QString& nonce) { - QString actualNonce, key; - { - QWriteLocker locker(&_entityNonceMapLock); - QPair sent = _entityNonceMap.take(entityID); - actualNonce = sent.first.toString(); - key = sent.second; - } - - QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n"; - QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray(actualNonce.toUtf8()), QCryptographicHash::Sha256); - bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8())); - - if (verificationSuccess) { - qCDebug(entities) << "Ownership challenge for Entity ID" << entityID << "succeeded."; - } else { - qCDebug(entities) << "Ownership challenge for Entity ID" << entityID << "failed. Actual nonce:" << actualNonce << - "\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key; - } - - return verificationSuccess; -} - -void EntityTree::processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { - int idByteArraySize; - int textByteArraySize; - int nodeToChallengeByteArraySize; - - message.readPrimitive(&idByteArraySize); - message.readPrimitive(&textByteArraySize); - message.readPrimitive(&nodeToChallengeByteArraySize); - - QByteArray id(message.read(idByteArraySize)); - QByteArray text(message.read(textByteArraySize)); - QByteArray nodeToChallenge(message.read(nodeToChallengeByteArraySize)); - - sendChallengeOwnershipRequestPacket(id, text, nodeToChallenge, sourceNode); -} - -void EntityTree::processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { - auto nodeList = DependencyManager::get(); - - int idByteArraySize; - int textByteArraySize; - int challengingNodeUUIDByteArraySize; - - message.readPrimitive(&idByteArraySize); - message.readPrimitive(&textByteArraySize); - message.readPrimitive(&challengingNodeUUIDByteArraySize); - - QByteArray id(message.read(idByteArraySize)); - QByteArray text(message.read(textByteArraySize)); - QUuid challengingNode = QUuid::fromRfc4122(message.read(challengingNodeUUIDByteArraySize)); - - auto challengeOwnershipReplyPacket = NLPacket::create(PacketType::ChallengeOwnershipReply, - idByteArraySize + text.length() + 2 * sizeof(int), - true); - challengeOwnershipReplyPacket->writePrimitive(idByteArraySize); - challengeOwnershipReplyPacket->writePrimitive(text.length()); - challengeOwnershipReplyPacket->write(id); - challengeOwnershipReplyPacket->write(text); - - nodeList->sendPacket(std::move(challengeOwnershipReplyPacket), *(nodeList->nodeWithUUID(challengingNode))); -} - -void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode) { - // 1. Obtain a nonce - auto nodeList = DependencyManager::get(); - - QByteArray text = computeNonce(entityItemID, ownerKey); - - if (text == "") { - qCDebug(entities) << "CRITICAL ERROR: Couldn't compute nonce. No action will be taken to remove this entity."; - // FIXME: All certificate checking needs to be moved to its own files, - // then the deletion settings need to have a toggle for domain owners - // and a setting to change the verification service provider. - // withWriteLock([&] { - // deleteEntity(entityItemID, true); - // }); - } else { - qCDebug(entities) << "Challenging ownership of Cert ID" << certID; - // 2. Send the nonce to the rezzing avatar's node - QByteArray idByteArray = entityItemID.toByteArray(); - int idByteArraySize = idByteArray.size(); - auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnership, - idByteArraySize + text.length() + 2 * sizeof(int), - true); - challengeOwnershipPacket->writePrimitive(idByteArraySize); - challengeOwnershipPacket->writePrimitive(text.length()); - challengeOwnershipPacket->write(idByteArray); - challengeOwnershipPacket->write(text); - nodeList->sendPacket(std::move(challengeOwnershipPacket), *senderNode); - - // 3. Kickoff a 10-second timeout timer that deletes the entity if we don't get an ownership response in time - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer", Q_ARG(const EntityItemID&, entityItemID)); - return; - } else { - startChallengeOwnershipTimer(entityItemID); - } - } -} - -void EntityTree::sendChallengeOwnershipRequestPacket(const QByteArray& id, const QByteArray& text, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode) { - auto nodeList = DependencyManager::get(); - - // In this case, Client A is challenging Client B. Client A is inspecting a certified entity that it wants - // to make sure belongs to Avatar B. - QByteArray senderNodeUUID = senderNode->getUUID().toRfc4122(); - - int idByteArraySize = id.length(); - int TextByteArraySize = text.length(); - int senderNodeUUIDSize = senderNodeUUID.length(); - - auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest, - idByteArraySize + TextByteArraySize + senderNodeUUIDSize + 3 * sizeof(int), - true); - challengeOwnershipPacket->writePrimitive(idByteArraySize); - challengeOwnershipPacket->writePrimitive(TextByteArraySize); - challengeOwnershipPacket->writePrimitive(senderNodeUUIDSize); - challengeOwnershipPacket->write(id); - challengeOwnershipPacket->write(text); - challengeOwnershipPacket->write(senderNodeUUID); - - nodeList->sendPacket(std::move(challengeOwnershipPacket), *(nodeList->nodeWithUUID(QUuid::fromRfc4122(nodeToChallenge)))); -} - -void EntityTree::validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode) { - // Start owner verification. - auto nodeList = DependencyManager::get(); - // First, asynchronously hit "proof_of_purchase_status?transaction_type=transfer" endpoint. - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest; - networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - QUrl requestURL = MetaverseAPI::getCurrentMetaverseServerURL(); - requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer"); - QJsonObject request; - request["certificate_id"] = certID; - networkRequest.setUrl(requestURL); - - QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); - - connect(networkReply, &QNetworkReply::finished, [this, networkReply, entityItemID, certID, senderNode]() { - QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); - jsonObject = jsonObject["data"].toObject(); - - if (networkReply->error() == QNetworkReply::NoError) { - if (!jsonObject["invalid_reason"].toString().isEmpty()) { - qCDebug(entities) << "invalid_reason not empty, no action will be taken to delete entity" << entityItemID; - // FIXME: All certificate checking needs to be moved to its own files, - // then the deletion settings need to have a toggle for domain owners - // and a setting to change the verification service provider. - // withWriteLock([&] { - // deleteEntity(entityItemID, true); - // }); - } else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") { - qCDebug(entities) << "'transfer_status' is 'failed', no action will be taken to delete entity" << entityItemID; - // FIXME: All certificate checking needs to be moved to its own files, - // then the deletion settings need to have a toggle for domain owners - // and a setting to change the verification service provider. - // withWriteLock([&] { - // deleteEntity(entityItemID, true); - // }); - } else { - // Second, challenge ownership of the PoP cert - // (ignore pending status; a failure will be cleaned up during DDV) - sendChallengeOwnershipPacket(certID, - jsonObject["transfer_recipient_key"].toString(), - entityItemID, - senderNode); - } - } else { - qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; no action will be taken to delete entity" << entityItemID - << "More info:" << jsonObject; - // FIXME: All certificate checking needs to be moved to its own files, - // then the deletion settings need to have a toggle for domain owners - // and a setting to change the verification service provider. - // withWriteLock([&] { - // deleteEntity(entityItemID, true); - // }); - } - - networkReply->deleteLater(); - }); -} - -void EntityTree::processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { - int idByteArraySize; - int textByteArraySize; - - message.readPrimitive(&idByteArraySize); - message.readPrimitive(&textByteArraySize); - - EntityItemID id(message.read(idByteArraySize)); - QString text(message.read(textByteArraySize)); - - emit killChallengeOwnershipTimeoutTimer(id); - - if (!verifyNonce(id, text)) { - withWriteLock([&] { - deleteEntity(id, true); - }); - } -} - // NOTE: Caller must lock the tree before calling this. int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) { @@ -1939,8 +1569,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c if (!isClone) { if ((isAdd || properties.lifetimeChanged()) && - ((!senderNode->getCanRez() && senderNode->getCanRezTmp()) || - (!senderNode->getCanRezCertified() && senderNode->getCanRezTmpCertified()))) { + ((!senderNode->getCanRez() && senderNode->getCanRezTmp()))) { // this node is only allowed to rez temporary entities. if need be, cap the lifetime. if (properties.getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME || properties.getLifetime() > _maxTmpEntityLifetime) { @@ -2020,22 +1649,14 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c _totalUpdates++; } else if (isAdd) { bool failedAdd = !allowed; - bool isCertified = !properties.getCertificateID().isEmpty(); bool isCloneable = properties.getCloneable(); int cloneLimit = properties.getCloneLimit(); if (!allowed) { qCDebug(entities) << "Filtered entity add. ID:" << entityItemID; - } else if (!isClone && !isCertified && !senderNode->getCanRez() && !senderNode->getCanRezTmp()) { - failedAdd = true; - qCDebug(entities) << "User without 'uncertified rez rights' [" << senderNode->getUUID() - << "] attempted to add an uncertified entity with ID:" << entityItemID; - } else if (!isClone && isCertified && !senderNode->getCanRezCertified() && !senderNode->getCanRezTmpCertified()) { - failedAdd = true; - qCDebug(entities) << "User without 'certified rez rights' [" << senderNode->getUUID() - << "] attempted to add a certified entity with ID:" << entityItemID; - } else if (isClone && isCertified && !properties.getCertificateType().contains(DOMAIN_UNLIMITED)) { + } else if (!isClone && !senderNode->getCanRez() && !senderNode->getCanRezTmp()) { failedAdd = true; - qCDebug(entities) << "User attempted to clone certified entity from entity ID:" << entityIDToClone; + qCDebug(entities) << "User without 'rez rights' [" << senderNode->getUUID() + << "] attempted to add an entity with ID:" << entityItemID; } else if (isClone && !isCloneable) { failedAdd = true; qCDebug(entities) << "User attempted to clone non-cloneable entity from entity ID:" << entityIDToClone; @@ -2054,18 +1675,6 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c endCreate = usecTimestampNow(); _totalCreates++; - if (newEntity && isCertified && getIsServer()) { - if (!properties.verifyStaticCertificateProperties()) { - qCDebug(entities) << "User" << senderNode->getUUID() - << "attempted to add a certified entity with ID" << entityItemID << "which failed" - << "static certificate verification."; - // Delete the entity we just added if it doesn't pass static certificate verification - deleteEntity(entityItemID, true); - } else { - validatePop(properties.getCertificateID(), entityItemID, senderNode); - } - } - if (newEntity && isClone) { entityToClone->addCloneID(newEntity->getEntityItemID()); newEntity->setCloneOriginID(entityIDToClone); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 66e761f7a04..78fab3af6fa 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -90,9 +90,6 @@ class EntityTree : public Octree, public SpatialParentTree { void fixupTerseEditLogging(EntityItemProperties& properties, QList& changedProperties); virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) override; - virtual void processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override; - virtual void processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override; - virtual void processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) override; virtual EntityItemID evalRayIntersection(const glm::vec3& origin, const glm::vec3& direction, QVector entityIdsToInclude, QVector entityIdsToDiscard, @@ -251,9 +248,6 @@ class EntityTree : public Octree, public SpatialParentTree { static const float DEFAULT_MAX_TMP_ENTITY_LIFETIME; - QByteArray computeNonce(const EntityItemID& entityID, const QString ownerKey); - bool verifyNonce(const EntityItemID& entityID, const QString& nonce); - QUuid getMyAvatarSessionUUID() { return _myAvatar ? _myAvatar->getSessionUUID() : QUuid(); } void setMyAvatar(std::shared_ptr myAvatar) { _myAvatar = myAvatar; } @@ -281,7 +275,6 @@ class EntityTree : public Octree, public SpatialParentTree { void updateEntityQueryAACube(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, bool force, bool tellServer); - void startDynamicDomainVerificationOnServer(float minimumAgeToRemove); signals: void deletingEntity(const EntityItemID& entityID); @@ -330,12 +323,6 @@ class EntityTree : public Octree, public SpatialParentTree { mutable QReadWriteLock _entityMapLock; QHash _entityMap; - mutable QReadWriteLock _entityCertificateIDMapLock; - QHash> _entityCertificateIDMap; - - mutable QReadWriteLock _entityNonceMapLock; - QHash> _entityNonceMap; - EntitySimulationPointer _simulation; bool _wantEditLogging = false; @@ -380,15 +367,7 @@ class EntityTree : public Octree, public SpatialParentTree { MovingEntitiesOperator _entityMover; QHash _entitiesToAdd; - Q_INVOKABLE void startChallengeOwnershipTimer(const EntityItemID& entityItemID); - private: - void addCertifiedEntityOnServer(EntityItemPointer entity); - void removeCertifiedEntityOnServer(EntityItemPointer entity); - void sendChallengeOwnershipPacket(const QString& certID, const QString& ownerKey, const EntityItemID& entityItemID, const SharedNodePointer& senderNode); - void sendChallengeOwnershipRequestPacket(const QByteArray& id, const QByteArray& text, const QByteArray& nodeToChallenge, const SharedNodePointer& senderNode); - void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode); - std::shared_ptr _myAvatar{ nullptr }; static std::function _getEntityObjectOperator; diff --git a/libraries/fbx/src/FST.cpp b/libraries/fbx/src/FST.cpp index fd074099608..00ebfa84ec1 100644 --- a/libraries/fbx/src/FST.cpp +++ b/libraries/fbx/src/FST.cpp @@ -27,7 +27,6 @@ FST::FST(QString fstPath, QVariantHash data) : _fstPath(std::move(fstPath)) { }; setValueFromFSTData(NAME_FIELD, _name); setValueFromFSTData(FILENAME_FIELD, _modelPath); - setValueFromFSTData(MARKETPLACE_ID_FIELD, _marketplaceID); if (data.contains(SCRIPT_FIELD)) { QVariantList scripts = data.values(SCRIPT_FIELD); @@ -163,7 +162,6 @@ QVariantHash FST::getMapping() const { mapping.unite(_other); mapping.insert(NAME_FIELD, _name); mapping.insert(FILENAME_FIELD, _modelPath); - mapping.insert(MARKETPLACE_ID_FIELD, _marketplaceID); for (const auto& scriptPath : _scriptPaths) { mapping.insertMulti(SCRIPT_FIELD, scriptPath); } @@ -178,8 +176,3 @@ bool FST::write() { fst.write(FSTReader::writeMapping(getMapping())); return true; } - -void FST::setMarketplaceID(QUuid marketplaceID) { - _marketplaceID = marketplaceID; - emit marketplaceIDChanged(); -} diff --git a/libraries/fbx/src/FST.h b/libraries/fbx/src/FST.h index 0f4c1ecd3ae..eb5ff7f6777 100644 --- a/libraries/fbx/src/FST.h +++ b/libraries/fbx/src/FST.h @@ -23,8 +23,6 @@ class FST : public QObject { Q_OBJECT Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged) Q_PROPERTY(QString modelPath READ getModelPath WRITE setModelPath NOTIFY modelPathChanged) - Q_PROPERTY(QUuid marketplaceID READ getMarketplaceID) - Q_PROPERTY(bool hasMarketplaceID READ getHasMarketplaceID NOTIFY marketplaceIDChanged) public: FST(QString fstPath, QVariantHash data); @@ -38,10 +36,6 @@ class FST : public QObject { QString getModelPath() const { return _modelPath; } void setModelPath(const QString& modelPath); - Q_INVOKABLE bool getHasMarketplaceID() const { return !_marketplaceID.isNull(); } - QUuid getMarketplaceID() const { return _marketplaceID; } - void setMarketplaceID(QUuid marketplaceID); - QStringList getScriptPaths() const { return _scriptPaths; } void setScriptPaths(QStringList scriptPaths) { _scriptPaths = scriptPaths; } @@ -54,14 +48,12 @@ class FST : public QObject { signals: void nameChanged(const QString& name); void modelPathChanged(const QString& modelPath); - void marketplaceIDChanged(); private: QString _fstPath; QString _name{}; QString _modelPath{}; - QUuid _marketplaceID{}; QStringList _scriptPaths{}; diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index cd3b8d268c5..55febf47055 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -127,7 +127,7 @@ void FSTReader::writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) QByteArray FSTReader::writeMapping(const QVariantHash& mapping) { static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << TYPE_FIELD << SCALE_FIELD << FILENAME_FIELD - << MARKETPLACE_ID_FIELD << TEXDIR_FIELD << SCRIPT_FIELD << JOINT_FIELD + << TEXDIR_FIELD << SCRIPT_FIELD << JOINT_FIELD << BLENDSHAPE_FIELD << JOINT_INDEX_FIELD; QBuffer buffer; buffer.open(QIODevice::WriteOnly); diff --git a/libraries/fbx/src/FSTReader.h b/libraries/fbx/src/FSTReader.h index 3945fe1d8b2..1e48e06c92c 100644 --- a/libraries/fbx/src/FSTReader.h +++ b/libraries/fbx/src/FSTReader.h @@ -20,7 +20,6 @@ static const QString FST_VERSION_FIELD = "version"; static const QString NAME_FIELD = "name"; static const QString TYPE_FIELD = "type"; static const QString FILENAME_FIELD = "filename"; -static const QString MARKETPLACE_ID_FIELD = "marketplaceID"; static const QString TEXDIR_FIELD = "texdir"; static const QString LOD_FIELD = "lod"; static const QString JOINT_INDEX_FIELD = "jointIndex"; diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 735f6dbc742..cddfdbe6fed 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -62,7 +62,6 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, const _location(location), _payload(), _isStatic(false), - _walletUUID(), _nodeVersion(), _dataDirectory(dataDirectory) { @@ -78,7 +77,6 @@ Assignment::Assignment(ReceivedMessage& message) : _pool(), _location(GlobalLocation), _payload(), - _walletUUID(), _nodeVersion() { if (message.getType() == PacketType::RequestAssignment) { @@ -104,7 +102,6 @@ Assignment::Assignment(const Assignment& otherAssignment) : QObject() { _location = otherAssignment._location; _pool = otherAssignment._pool; _payload = otherAssignment._payload; - _walletUUID = otherAssignment._walletUUID; _nodeVersion = otherAssignment._nodeVersion; } @@ -123,7 +120,6 @@ void Assignment::swap(Assignment& otherAssignment) { swap(_location, otherAssignment._location); swap(_pool, otherAssignment._pool); swap(_payload, otherAssignment._payload); - swap(_walletUUID, otherAssignment._walletUUID); swap(_nodeVersion, otherAssignment._nodeVersion); } @@ -167,7 +163,7 @@ QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { out << (quint8) assignment._type << assignment._uuid << assignment._pool << assignment._payload; if (assignment._command == Assignment::RequestCommand) { - out << assignment._nodeVersion << assignment._walletUUID; + out << assignment._nodeVersion; } return out; @@ -179,7 +175,7 @@ QDataStream& operator>>(QDataStream &in, Assignment& assignment) { assignment._type = (Assignment::Type) packedType; if (assignment._command == Assignment::RequestCommand) { - in >> assignment._nodeVersion >> assignment._walletUUID; + in >> assignment._nodeVersion; } return in; diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index e958c84d876..513450d9104 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -84,9 +84,6 @@ class Assignment : public QObject { void setIsStatic(bool isStatic) { _isStatic = isStatic; } bool isStatic() const { return _isStatic; } - void setWalletUUID(const QUuid& walletUUID) { _walletUUID = walletUUID; } - const QUuid& getWalletUUID() const { return _walletUUID; } - const QString& getNodeVersion() const { return _nodeVersion; } const char* getTypeName() const; @@ -104,7 +101,6 @@ class Assignment : public QObject { Assignment::Location _location; /// the location of the assignment, allows a domain to preferentially use local ACs QByteArray _payload; /// an optional payload attached to this assignment, a maximum for 1024 bytes will be packed bool _isStatic; /// defines if this assignment needs to be re-queued in the domain-server if it stops being fulfilled - QUuid _walletUUID; /// the UUID for the wallet that should be paid for this assignment QString _nodeVersion; QString _dataDirectory; }; diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index 8756a0cc4bf..2b7851c47df 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -34,7 +34,6 @@ DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherI _username = otherInfo._username; _xmppPassword = otherInfo._xmppPassword; _discourseApiKey = otherInfo._discourseApiKey; - _walletID = otherInfo._walletID; _privateKey = otherInfo._privateKey; _domainID = otherInfo._domainID; _temporaryDomainID = otherInfo._temporaryDomainID; @@ -54,7 +53,6 @@ void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) { swap(_username, otherInfo._username); swap(_xmppPassword, otherInfo._xmppPassword); swap(_discourseApiKey, otherInfo._discourseApiKey); - swap(_walletID, otherInfo._walletID); swap(_privateKey, otherInfo._privateKey); swap(_domainID, otherInfo._domainID); swap(_temporaryDomainID, otherInfo._temporaryDomainID); @@ -85,12 +83,6 @@ void DataServerAccountInfo::setDiscourseApiKey(const QString& discourseApiKey) { } } -void DataServerAccountInfo::setWalletID(const QUuid& walletID) { - if (_walletID != walletID) { - _walletID = walletID; - } -} - bool DataServerAccountInfo::hasProfile() const { return _username.length() > 0; } @@ -100,7 +92,6 @@ void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject setUsername(user["username"].toString()); setXMPPPassword(user["xmpp_password"].toString()); setDiscourseApiKey(user["discourse_api_key"].toString()); - setWalletID(QUuid(user["wallet_id"].toString())); } QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionToken) { @@ -153,14 +144,14 @@ QByteArray DataServerAccountInfo::signPlaintext(const QByteArray& plaintext) { QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) { out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey - << info._walletID << info._privateKey << info._domainID + << info._privateKey << info._domainID << info._temporaryDomainID << info._temporaryDomainApiKey; return out; } QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info) { in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey - >> info._walletID >> info._privateKey >> info._domainID + >> info._privateKey >> info._domainID >> info._temporaryDomainID >> info._temporaryDomainApiKey; return in; } diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index 8cb416cf34e..31a8dbb7661 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -41,9 +41,6 @@ class DataServerAccountInfo : public QObject { const QString& getDiscourseApiKey() const { return _discourseApiKey; } void setDiscourseApiKey(const QString& discourseApiKey); - const QUuid& getWalletID() const { return _walletID; } - void setWalletID(const QUuid& walletID); - QByteArray getUsernameSignature(const QUuid& connectionToken); bool hasPrivateKey() const { return !_privateKey.isEmpty(); } void setPrivateKey(const QByteArray& privateKey) { _privateKey = privateKey; } @@ -70,7 +67,6 @@ class DataServerAccountInfo : public QObject { QString _username; QString _xmppPassword; QString _discourseApiKey; - QUuid _walletID; QUuid _domainID; QUuid _temporaryDomainID; QString _temporaryDomainApiKey; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index d867b49b30d..42bf2a4c888 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -174,14 +174,6 @@ void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) { newPermissions.can(NodePermissions::Permission::canRezTemporaryEntities)) { emit canRezTmpChanged(_permissions.can(NodePermissions::Permission::canRezTemporaryEntities)); } - if (originalPermissions.can(NodePermissions::Permission::canRezPermanentCertifiedEntities) != - newPermissions.can(NodePermissions::Permission::canRezPermanentCertifiedEntities)) { - emit canRezCertifiedChanged(_permissions.can(NodePermissions::Permission::canRezPermanentCertifiedEntities)); - } - if (originalPermissions.can(NodePermissions::Permission::canRezTemporaryCertifiedEntities) != - newPermissions.can(NodePermissions::Permission::canRezTemporaryCertifiedEntities)) { - emit canRezTmpCertifiedChanged(_permissions.can(NodePermissions::Permission::canRezTemporaryCertifiedEntities)); - } if (originalPermissions.can(NodePermissions::Permission::canWriteToAssetServer) != newPermissions.can(NodePermissions::Permission::canWriteToAssetServer)) { emit canWriteAssetsChanged(_permissions.can(NodePermissions::Permission::canWriteToAssetServer)); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index a61deeef968..d139adaa6cc 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -125,8 +125,6 @@ class LimitedNodeList : public QObject, public Dependency { bool isAllowedEditor() const { return _permissions.can(NodePermissions::Permission::canAdjustLocks); } bool getThisNodeCanRez() const { return _permissions.can(NodePermissions::Permission::canRezPermanentEntities); } bool getThisNodeCanRezTmp() const { return _permissions.can(NodePermissions::Permission::canRezTemporaryEntities); } - bool getThisNodeCanRezCertified() const { return _permissions.can(NodePermissions::Permission::canRezPermanentCertifiedEntities); } - bool getThisNodeCanRezTmpCertified() const { return _permissions.can(NodePermissions::Permission::canRezTemporaryCertifiedEntities); } bool getThisNodeCanWriteAssets() const { return _permissions.can(NodePermissions::Permission::canWriteToAssetServer); } bool getThisNodeCanKick() const { return _permissions.can(NodePermissions::Permission::canKick); } bool getThisNodeCanReplaceContent() const { return _permissions.can(NodePermissions::Permission::canReplaceDomainContent); } @@ -382,8 +380,6 @@ private slots: void isAllowedEditorChanged(bool isAllowedEditor); void canRezChanged(bool canRez); void canRezTmpChanged(bool canRezTmp); - void canRezCertifiedChanged(bool canRez); - void canRezTmpCertifiedChanged(bool canRezTmp); void canWriteAssetsChanged(bool canWriteAssets); void canKickChanged(bool canKick); void canReplaceContentChanged(bool canReplaceContent); diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 07c599913b4..c29750ab331 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -78,8 +78,6 @@ class Node : public NetworkPeer { bool isAllowedEditor() const { return _permissions.can(NodePermissions::Permission::canAdjustLocks); } bool getCanRez() const { return _permissions.can(NodePermissions::Permission::canRezPermanentEntities); } bool getCanRezTmp() const { return _permissions.can(NodePermissions::Permission::canRezTemporaryEntities); } - bool getCanRezCertified() const { return _permissions.can(NodePermissions::Permission::canRezPermanentCertifiedEntities); } - bool getCanRezTmpCertified() const { return _permissions.can(NodePermissions::Permission::canRezTemporaryCertifiedEntities); } bool getCanWriteToAssetServer() const { return _permissions.can(NodePermissions::Permission::canWriteToAssetServer); } bool getCanKick() const { return _permissions.can(NodePermissions::Permission::canKick); } bool getCanReplaceContent() const { return _permissions.can(NodePermissions::Permission::canReplaceDomainContent); } diff --git a/libraries/networking/src/NodePermissions.cpp b/libraries/networking/src/NodePermissions.cpp index e0de649c059..2f75cd1fd5b 100644 --- a/libraries/networking/src/NodePermissions.cpp +++ b/libraries/networking/src/NodePermissions.cpp @@ -60,8 +60,6 @@ NodePermissions::NodePermissions(QMap perms) { permissions |= perms["id_can_adjust_locks"].toBool() ? Permission::canAdjustLocks : Permission::none; permissions |= perms["id_can_rez"].toBool() ? Permission::canRezPermanentEntities : Permission::none; permissions |= perms["id_can_rez_tmp"].toBool() ? Permission::canRezTemporaryEntities : Permission::none; - permissions |= perms["id_can_rez_certified"].toBool() ? Permission::canRezPermanentCertifiedEntities : Permission::none; - permissions |= perms["id_can_rez_tmp_certified"].toBool() ? Permission::canRezTemporaryCertifiedEntities : Permission::none; permissions |= perms["id_can_write_to_asset_server"].toBool() ? Permission::canWriteToAssetServer : Permission::none; permissions |= perms["id_can_connect_past_max_capacity"].toBool() ? Permission::canConnectPastMaxCapacity : Permission::none; @@ -89,8 +87,6 @@ QVariant NodePermissions::toVariant(QHash groupRanks) { values["id_can_adjust_locks"] = can(Permission::canAdjustLocks); values["id_can_rez"] = can(Permission::canRezPermanentEntities); values["id_can_rez_tmp"] = can(Permission::canRezTemporaryEntities); - values["id_can_rez_certified"] = can(Permission::canRezPermanentCertifiedEntities); - values["id_can_rez_tmp_certified"] = can(Permission::canRezTemporaryCertifiedEntities); values["id_can_write_to_asset_server"] = can(Permission::canWriteToAssetServer); values["id_can_connect_past_max_capacity"] = can(Permission::canConnectPastMaxCapacity); values["id_can_kick"] = can(Permission::canKick); @@ -150,12 +146,6 @@ QDebug operator<<(QDebug debug, const NodePermissions& perms) { if (perms.can(NodePermissions::Permission::canRezTemporaryEntities)) { debug << " rez-tmp"; } - if (perms.can(NodePermissions::Permission::canRezPermanentCertifiedEntities)) { - debug << " rez-certified"; - } - if (perms.can(NodePermissions::Permission::canRezTemporaryCertifiedEntities)) { - debug << " rez-tmp-certified"; - } if (perms.can(NodePermissions::Permission::canWriteToAssetServer)) { debug << " asset-server"; } diff --git a/libraries/networking/src/NodePermissions.h b/libraries/networking/src/NodePermissions.h index 82c008feef0..b7262194d32 100644 --- a/libraries/networking/src/NodePermissions.h +++ b/libraries/networking/src/NodePermissions.h @@ -78,8 +78,6 @@ class NodePermissions { canConnectPastMaxCapacity = 32, canKick = 64, canReplaceDomainContent = 128, - canRezPermanentCertifiedEntities = 256, - canRezTemporaryCertifiedEntities = 512, canGetAndSetPrivateUserData = 1024 }; Q_DECLARE_FLAGS(Permissions, Permission) diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp index 2f47ef5e000..8e4e6b8fb57 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp @@ -24,10 +24,6 @@ void UserActivityLoggerScriptingInterface::closedTablet() { doLogAction("closed_tablet"); } -void UserActivityLoggerScriptingInterface::openedMarketplace() { - doLogAction("opened_marketplace"); -} - void UserActivityLoggerScriptingInterface::toggledAway(bool isAway) { doLogAction("toggled_away", { { "is_away", isAway } }); } @@ -88,71 +84,3 @@ void UserActivityLoggerScriptingInterface::doLogAction(QString action, QJsonObje Q_ARG(QString, action), Q_ARG(QJsonObject, details)); } - -void UserActivityLoggerScriptingInterface::commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem) { - QJsonObject payload; - payload["marketplaceID"] = marketplaceID; - payload["contentCreator"] = contentCreator; - payload["cost"] = cost; - payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem; - doLogAction("commercePurchaseSuccess", payload); -} - -void UserActivityLoggerScriptingInterface::commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails) { - QJsonObject payload; - payload["marketplaceID"] = marketplaceID; - payload["contentCreator"] = contentCreator; - payload["cost"] = cost; - payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem; - payload["errorDetails"] = errorDetails; - doLogAction("commercePurchaseFailure", payload); -} - -void UserActivityLoggerScriptingInterface::commerceEntityRezzed(QString marketplaceID, QString source, QString type) { - QJsonObject payload; - payload["marketplaceID"] = marketplaceID; - payload["source"] = source; - payload["type"] = type; - doLogAction("commerceEntityRezzed", payload); -} - -void UserActivityLoggerScriptingInterface::commerceWalletSetupStarted(int timestamp, QString setupAttemptID, int setupFlowVersion, QString referrer, QString currentDomain) { - QJsonObject payload; - payload["timestamp"] = timestamp; - payload["setupAttemptID"] = setupAttemptID; - payload["setupFlowVersion"] = setupFlowVersion; - payload["referrer"] = referrer; - payload["currentDomain"] = currentDomain; - doLogAction("commerceWalletSetupStarted", payload); -} - -void UserActivityLoggerScriptingInterface::commerceWalletSetupProgress(int timestamp, QString setupAttemptID, int secondsElapsed, int currentStepNumber, QString currentStepName) { - QJsonObject payload; - payload["timestamp"] = timestamp; - payload["setupAttemptID"] = setupAttemptID; - payload["secondsElapsed"] = secondsElapsed; - payload["currentStepNumber"] = currentStepNumber; - payload["currentStepName"] = currentStepName; - doLogAction("commerceWalletSetupProgress", payload); -} - -void UserActivityLoggerScriptingInterface::commerceWalletSetupFinished(int timestamp, QString setupAttemptID, int secondsToComplete) { - QJsonObject payload; - payload["timestamp"] = timestamp; - payload["setupAttemptID"] = setupAttemptID; - payload["secondsToComplete"] = secondsToComplete; - doLogAction("commerceWalletSetupFinished", payload); -} - -void UserActivityLoggerScriptingInterface::commercePassphraseEntry(QString source) { - QJsonObject payload; - payload["source"] = source; - doLogAction("commercePassphraseEntry", payload); -} - -void UserActivityLoggerScriptingInterface::commercePassphraseAuthenticationStatus(QString status) { - QJsonObject payload; - payload["status"] = status; - doLogAction("commercePassphraseAuthenticationStatus", payload); - -} diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.h b/libraries/networking/src/UserActivityLoggerScriptingInterface.h index 1cda1235e91..2aefaa16fcb 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.h +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.h @@ -23,7 +23,6 @@ class UserActivityLoggerScriptingInterface : public QObject, public Dependency { Q_INVOKABLE void enabledEdit(); Q_INVOKABLE void openedTablet(bool visibleToOthers); Q_INVOKABLE void closedTablet(); - Q_INVOKABLE void openedMarketplace(); Q_INVOKABLE void toggledAway(bool isAway); Q_INVOKABLE void tutorialProgress(QString stepName, int stepNumber, float secondsToComplete, float tutorialElapsedTime, QString tutorialRunID = "", int tutorialVersion = 0, QString controllerType = ""); @@ -33,14 +32,6 @@ class UserActivityLoggerScriptingInterface : public QObject, public Dependency { Q_INVOKABLE void privacyShieldToggled(bool newValue); Q_INVOKABLE void privacyShieldActivated(); Q_INVOKABLE void logAction(QString action, QVariantMap details = QVariantMap{}); - Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem); - Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails); - Q_INVOKABLE void commerceEntityRezzed(QString marketplaceID, QString source, QString type); - Q_INVOKABLE void commerceWalletSetupStarted(int timestamp, QString setupAttemptID, int setupFlowVersion, QString referrer, QString currentDomain); - Q_INVOKABLE void commerceWalletSetupProgress(int timestamp, QString setupAttemptID, int secondsElapsed, int currentStepNumber, QString currentStepName); - Q_INVOKABLE void commerceWalletSetupFinished(int timestamp, QString setupAttemptID, int secondsToComplete); - Q_INVOKABLE void commercePassphraseEntry(QString source); - Q_INVOKABLE void commercePassphraseAuthenticationStatus(QString status); private: void doLogAction(QString action, QJsonObject details = {}); }; diff --git a/libraries/networking/src/WalletTransaction.cpp b/libraries/networking/src/WalletTransaction.cpp deleted file mode 100644 index 2bb66c67d0c..00000000000 --- a/libraries/networking/src/WalletTransaction.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// -// WalletTransaction.cpp -// libraries/networking/src -// -// Created by Stephen Birarda on 2014-05-20. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "WalletTransaction.h" - -#include - -#include - -WalletTransaction::WalletTransaction() : - _uuid(), - _destinationUUID(), - _amount(0), - _isFinalized(false) -{ - -} - -WalletTransaction::WalletTransaction(const QUuid& destinationUUID, qint64 amount) : - _uuid(QUuid::createUuid()), - _destinationUUID(destinationUUID), - _amount(amount), - _isFinalized(false) -{ - -} - -const QString TRANSACTION_ID_KEY = "id"; -const QString TRANSACTION_DESTINATION_WALLET_ID_KEY = "destination_wallet_id"; -const QString TRANSACTION_AMOUNT_KEY = "amount"; - -const QString ROOT_OBJECT_TRANSACTION_KEY = "transaction"; - -QJsonDocument WalletTransaction::postJson() { - QJsonObject rootObject; - - rootObject.insert(ROOT_OBJECT_TRANSACTION_KEY, toJson()); - - return QJsonDocument(rootObject); -} - -QJsonObject WalletTransaction::toJson() { - QJsonObject transactionObject; - - transactionObject.insert(TRANSACTION_ID_KEY, uuidStringWithoutCurlyBraces(_uuid)); - transactionObject.insert(TRANSACTION_DESTINATION_WALLET_ID_KEY, uuidStringWithoutCurlyBraces(_destinationUUID)); - transactionObject.insert(TRANSACTION_AMOUNT_KEY, _amount); - - return transactionObject; -} - -void WalletTransaction::loadFromJson(const QJsonObject& jsonObject) { - // pull the destination wallet and ID of the transaction to match it - QJsonObject transactionObject = jsonObject.value("data").toObject().value(ROOT_OBJECT_TRANSACTION_KEY).toObject(); - - _uuid = QUuid(transactionObject.value(TRANSACTION_ID_KEY).toString()); - _destinationUUID = QUuid(transactionObject.value(TRANSACTION_DESTINATION_WALLET_ID_KEY).toString()); - _amount = transactionObject.value(TRANSACTION_AMOUNT_KEY).toInt(); -} diff --git a/libraries/networking/src/WalletTransaction.h b/libraries/networking/src/WalletTransaction.h deleted file mode 100644 index 7728eb0f1b5..00000000000 --- a/libraries/networking/src/WalletTransaction.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// WalletTransaction.h -// domain-server/src -// -// Created by Stephen Birarda on 2014-05-20. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_WalletTransaction_h -#define hifi_WalletTransaction_h - -#include -#include -#include - -class WalletTransaction : public QObject { -public: - WalletTransaction(); - WalletTransaction(const QUuid& destinationUUID, qint64 amount); - - const QUuid& getUUID() const { return _uuid; } - - void setDestinationUUID(const QUuid& destinationUUID) { _destinationUUID = destinationUUID; } - const QUuid& getDestinationUUID() const { return _destinationUUID; } - - qint64 getAmount() const { return _amount; } - void setAmount(qint64 amount) { _amount = amount; } - void incrementAmount(qint64 increment) { _amount += increment; } - - bool isFinalized() const { return _isFinalized; } - void setIsFinalized(bool isFinalized) { _isFinalized = isFinalized; } - - QJsonDocument postJson(); - QJsonObject toJson(); - void loadFromJson(const QJsonObject& jsonObject); -protected: - QUuid _uuid; - QUuid _destinationUUID; - qint64 _amount; - bool _isFinalized; -}; - -#endif // hifi_WalletTransaction_h \ No newline at end of file diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index a34be09db7a..7bfbbbe58de 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -122,10 +122,10 @@ class PacketTypeEnum { ReplicatedKillAvatar, ReplicatedBulkAvatarData, DomainContentReplacementFromUrl, - ChallengeOwnership, + DropOnNextProtocolChange_1, EntityScriptCallMethod, - ChallengeOwnershipRequest, - ChallengeOwnershipReply, + DropOnNextProtocolChange_2, + DropOnNextProtocolChange_3, OctreeDataFileRequest, OctreeDataFileReply, OctreeDataPersist, diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 0b399377fe3..2d629b0325b 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -714,26 +714,6 @@ bool Octree::readJSONFromGzippedFile(QString qFileName) { return readJSONFromStream(-1, jsonStream, "", false, relativeURL); } -// hack to get the marketplace id into the entities. We will create a way to get this from a hash of -// the entity later, but this helps us move things along for now -QString getMarketplaceID(const QString& urlString) { - // the url should be http://mpassets.highfidelity.com/-v1/.extension - // a regex for the this is a PITA as there are several valid versions of uuids, and so - // lets strip out the uuid (if any) and try to create a UUID from the string, relying on - // QT to parse it - static const QRegularExpression re("^http:\\/\\/mpassets.highfidelity.com\\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-v[\\d]+\\/.*"); - QRegularExpressionMatch match = re.match(urlString); - if (match.hasMatch()) { - QString matched = match.captured(1); - if (QUuid(matched).isNull()) { - qDebug() << "invalid uuid for marketplaceID"; - } else { - return matched; - } - } - return QString(); -} - bool Octree::readFromURL( const QString& urlString, const bool isObservable, @@ -741,7 +721,6 @@ bool Octree::readFromURL( const bool isImport ) { QString trimmedUrl = urlString.trimmed(); - QString marketplaceID = getMarketplaceID(trimmedUrl); auto request = std::unique_ptr( DependencyManager::get()->createResourceRequest( this, trimmedUrl, isObservable, callerId, "Octree::readFromURL")); @@ -768,11 +747,11 @@ bool Octree::readFromURL( if (wasCompressed) { QDataStream inputStream(uncompressedJsonData); - return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, isImport, relativeURL); + return readFromStream(uncompressedJsonData.size(), inputStream, isImport, relativeURL); } QDataStream inputStream(data); - return readFromStream(data.size(), inputStream, marketplaceID, isImport, relativeURL); + return readFromStream(data.size(), inputStream, isImport, relativeURL); } bool Octree::readFromByteArray( @@ -780,7 +759,6 @@ bool Octree::readFromByteArray( const QByteArray& data ) { QString trimmedUrl = urlString.trimmed(); - QString marketplaceID = getMarketplaceID(trimmedUrl); QByteArray uncompressedJsonData; bool wasCompressed = gunzip(data, uncompressedJsonData); @@ -789,17 +767,16 @@ bool Octree::readFromByteArray( if (wasCompressed) { QDataStream inputStream(uncompressedJsonData); - return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, false, relativeURL); + return readFromStream(uncompressedJsonData.size(), inputStream, false, relativeURL); } QDataStream inputStream(data); - return readFromStream(data.size(), inputStream, marketplaceID, false, relativeURL); + return readFromStream(data.size(), inputStream, false, relativeURL); } bool Octree::readFromStream( uint64_t streamLength, QDataStream& inputStream, - const QString& marketplaceID, const bool isImport, const QUrl& relativeURL ) { @@ -814,37 +791,16 @@ bool Octree::readFromStream( return false; } else { qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; - return readJSONFromStream(streamLength, inputStream, marketplaceID, isImport, relativeURL); + return readJSONFromStream(streamLength, inputStream, isImport, relativeURL); } } -namespace { -// hack to get the marketplace id into the entities. We will create a way to get this from a hash of -// the entity later, but this helps us move things along for now -QVariantMap addMarketplaceIDToDocumentEntities(QVariantMap& doc, const QString& marketplaceID) { - if (!marketplaceID.isEmpty()) { - QVariantList newEntitiesArray; - - // build a new entities array - auto entitiesArray = doc["Entities"].toList(); - for (auto it = entitiesArray.begin(); it != entitiesArray.end(); it++) { - auto entity = (*it).toMap(); - entity["marketplaceID"] = marketplaceID; - newEntitiesArray.append(entity); - } - doc["Entities"] = newEntitiesArray; - } - return doc; -} - -} // Unnamed namepsace const int READ_JSON_BUFFER_SIZE = 2048; bool Octree::readJSONFromStream( uint64_t streamLength, QDataStream& inputStream, - const QString& marketplaceID, /*=""*/ const bool isImport, const QUrl& relativeURL ) { @@ -876,10 +832,6 @@ bool Octree::readJSONFromStream( return false; } - if (!marketplaceID.isEmpty()) { - addMarketplaceIDToDocumentEntities(asMap, marketplaceID); - } - bool success = readFromMap(asMap, isImport); delete[] rawData; return success; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index cb46d5151b6..a5aa57e157a 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -138,9 +138,6 @@ class Octree : public QObject, public std::enable_shared_from_this, publ virtual bool handlesEditPacketType(PacketType packetType) const { return false; } virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, const SharedNodePointer& sourceNode) { return 0; } - virtual void processChallengeOwnershipRequestPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; } - virtual void processChallengeOwnershipReplyPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; } - virtual void processChallengeOwnershipPacket(ReceivedMessage& message, const SharedNodePointer& sourceNode) { return; } virtual bool rootElementHasData() const { return false; } virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { } @@ -218,8 +215,8 @@ class Octree : public QObject, public std::enable_shared_from_this, publ bool readFromFile(const char* filename); bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1, const bool isImport = false); // will support file urls as well... bool readFromByteArray(const QString& url, const QByteArray& byteArray); - bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false, const QUrl& urlString = QUrl()); - bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false, const QUrl& urlString = QUrl()); + bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const bool isImport = false, const QUrl& urlString = QUrl()); + bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const bool isImport = false, const QUrl& urlString = QUrl()); bool readJSONFromGzippedFile(QString qFileName); virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) = 0; diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 5dfdce0c63a..66b9f3961d6 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -49,7 +49,6 @@ #include #include -#include "SecurityImageProvider.h" #include "shared/FileUtils.h" #include "types/FileTypeProfile.h" #include "types/HFWebEngineProfile.h" @@ -252,9 +251,6 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) { qmlRegisterType("Hifi", 1, 0, "SoundEffect"); }); - // Register the pixmap Security Image Provider - engine->addImageProvider(SecurityImageProvider::PROVIDER_NAME, new SecurityImageProvider()); - engine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory); auto importList = engine->importPathList(); importList.insert(importList.begin(), PathUtils::resourcesPath() + "qml/"); @@ -380,7 +376,6 @@ void OffscreenQmlSurface::onRootCreated() { tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", this); QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"); getSurfaceContext()->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership); - getSurfaceContext()->engine()->addImageProvider(SecurityImageProvider::PROVIDER_NAME, new SecurityImageProvider()); } QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); } diff --git a/libraries/ui/src/ui/SecurityImageProvider.cpp b/libraries/ui/src/ui/SecurityImageProvider.cpp deleted file mode 100644 index 190e58d6e86..00000000000 --- a/libraries/ui/src/ui/SecurityImageProvider.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// -// SecurityImageProvider.cpp -// interface/src/ui -// -// Created by David Kelly on 8/23/2017. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "SecurityImageProvider.h" - -#include -#include - -const QString SecurityImageProvider::PROVIDER_NAME = "security"; - -SecurityImageProvider::~SecurityImageProvider() { -} - -void SecurityImageProvider::setSecurityImage(const QPixmap* pixmap) { - // no need to delete old one, that is managed by the wallet - QWriteLocker lock(&_rwLock); - - if (pixmap) { - _securityImage = pixmap->copy(); - } else { - QPixmap greyPixmap(200, 200); - greyPixmap.fill(QColor("darkGrey")); - _securityImage = greyPixmap.copy(); - } -} - -QPixmap SecurityImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) { - - // adjust the internal pixmap to have the requested size - QReadLocker lock(&_rwLock); - if (id == "securityImage") { - *size = _securityImage.size(); - if (requestedSize.width() > 0 && requestedSize.height() > 0) { - return _securityImage.scaled(requestedSize.width(), requestedSize.height(), Qt::KeepAspectRatio); - } else { - return _securityImage.copy(); - } - } - // otherwise just return a grey pixmap. This avoids annoying error messages in qml we would get - // when sending a 'null' pixmap (QPixmap()) - QPixmap greyPixmap(200, 200); - greyPixmap.fill(QColor("darkGrey")); - return greyPixmap; -} diff --git a/libraries/ui/src/ui/SecurityImageProvider.h b/libraries/ui/src/ui/SecurityImageProvider.h deleted file mode 100644 index b12932e225e..00000000000 --- a/libraries/ui/src/ui/SecurityImageProvider.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// SecurityImageProvider.h -// -// Created by David Kelly on 2017/08/23 -// Copyright 2017 High Fidelity, Inc. - -// Distributed under the Apache License, Version 2.0 -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#pragma once -#ifndef hifi_SecurityImageProvider_h -#define hifi_SecurityImageProvider_h - -#include -#include - -class SecurityImageProvider: public QQuickImageProvider { -public: - static const QString PROVIDER_NAME; - - SecurityImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {} - virtual ~SecurityImageProvider(); - QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override; - - void setSecurityImage(const QPixmap* pixmap); -protected: - QReadWriteLock _rwLock; - QPixmap _securityImage; -}; - -#endif //hifi_SecurityImageProvider_h - diff --git a/scripts/+android_questInterface/defaultScripts.js b/scripts/+android_questInterface/defaultScripts.js index c294537419a..69dcef40bb5 100644 --- a/scripts/+android_questInterface/defaultScripts.js +++ b/scripts/+android_questInterface/defaultScripts.js @@ -23,9 +23,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/makeUserConnection.js", "system/tablet-goto.js", "system/notifications.js", - "system/commerce/wallet.js", "system/dialTone.js", - "system/marketplaces/marketplaces.js", "system/quickGoto.js", "system/firstPersonHMD.js", "system/tablet-ui/tabletUI.js", diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 7e7bb124407..d9a86dbd915 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -25,9 +25,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/avatarapp.js", "system/graphicsSettings.js", "system/makeUserConnection.js", - "system/marketplaces/marketplaces.js", "system/notifications.js", - "system/commerce/wallet.js", "system/create/edit.js", "system/dialTone.js", "system/firstPersonHMD.js", diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 6439d300234..4faa9c8913f 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -1,7 +1,7 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ /*global Tablet, Script, Entities, MyAvatar, Camera, Quat, HMD, Account, UserActivityLogger, Messages, print, - AvatarBookmarks, ContextOverlay, AddressManager + AvatarBookmarks, AddressManager */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // @@ -175,8 +175,6 @@ function onAnimGraphUrlChanged(url) { var selectedAvatarEntityID = null; var grabbedAvatarEntityChangeNotifier = null; -var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/wallet/Wallet.qml"; -var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace"; var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("html/js/marketplacesInject.js"); function getWearablesFrozen() { @@ -340,14 +338,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See break; case 'navigate': var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - if(message.url.indexOf('app://') === 0) { - if (message.url === 'app://marketplace') { - tablet.gotoWebScreen(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL); - } else if (message.url === 'app://purchases') { - tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH); - } - - } else if(message.url.indexOf('hifi://') === 0) { + if(message.url.indexOf('hifi://') === 0) { AddressManager.handleLookupString(message.url, false); } else if(message.url.indexOf('https://') === 0 || message.url.indexOf('http://') === 0) { tablet.gotoWebScreen(message.url, MARKETPLACES_INJECT_SCRIPT_URL); @@ -604,7 +595,6 @@ function onTabletButtonClicked() { // for toolbar-mode: go back to home screen, this will close the window. tablet.gotoHomeScreen(); } else { - ContextOverlay.enabled = false; tablet.loadQMLSource(AVATARAPP_QML_SOURCE); } } diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js deleted file mode 100644 index 86806fd8b4f..00000000000 --- a/scripts/system/commerce/wallet.js +++ /dev/null @@ -1,737 +0,0 @@ -"use strict"; -/* jslint vars:true, plusplus:true, forin:true */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ -// -// wallet.js -// -// Created by Zach Fox on 2017-08-17 -// Copyright 2017 High Fidelity, Inc -// -// Distributed under the Apache License, Version 2.0 -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global getConnectionData getControllerWorldLocation openLoginWindow WalletScriptingInterface */ - -(function () { // BEGIN LOCAL_SCOPE -Script.include("/~/system/libraries/accountUtils.js"); -Script.include("/~/system/libraries/connectionUtils.js"); -var AppUi = Script.require('appUi'); - -var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace"; - -// BEGIN AVATAR SELECTOR LOGIC -var UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6 }; -var SELECTED_COLOR = { red: 0xF3, green: 0x91, blue: 0x29 }; -var HOVER_COLOR = { red: 0xD0, green: 0xD0, blue: 0xD0 }; - -var overlays = {}; // Keeps track of all our extended overlay data objects, keyed by target identifier. - -function ExtendedOverlay(key, type, properties) { // A wrapper around overlays to store the key it is associated with. - overlays[key] = this; - this.key = key; - this.selected = false; - this.hovering = false; - this.activeOverlay = Overlays.addOverlay(type, properties); // We could use different overlays for (un)selected... -} -// Instance methods: -ExtendedOverlay.prototype.deleteOverlay = function () { // remove display and data of this overlay - Overlays.deleteOverlay(this.activeOverlay); - delete overlays[this.key]; -}; - -ExtendedOverlay.prototype.editOverlay = function (properties) { // change display of this overlay - Overlays.editOverlay(this.activeOverlay, properties); -}; - -function color(selected, hovering) { - var base = hovering ? HOVER_COLOR : selected ? SELECTED_COLOR : UNSELECTED_COLOR; - function scale(component) { - return component; - } - return { red: scale(base.red), green: scale(base.green), blue: scale(base.blue) }; -} -// so we don't have to traverse the overlays to get the last one -var lastHoveringId = 0; -ExtendedOverlay.prototype.hover = function (hovering) { - this.hovering = hovering; - if (this.key === lastHoveringId) { - if (hovering) { - return; - } - lastHoveringId = 0; - } - this.editOverlay({ color: color(this.selected, hovering) }); - if (hovering) { - // un-hover the last hovering overlay - if (lastHoveringId && lastHoveringId !== this.key) { - ExtendedOverlay.get(lastHoveringId).hover(false); - } - lastHoveringId = this.key; - } -}; -ExtendedOverlay.prototype.select = function (selected) { - if (this.selected === selected) { - return; - } - - this.editOverlay({ color: color(selected, this.hovering) }); - this.selected = selected; -}; -// Class methods: -var selectedId = false; -ExtendedOverlay.isSelected = function (id) { - return selectedId === id; -}; -ExtendedOverlay.get = function (key) { // answer the extended overlay data object associated with the given avatar identifier - return overlays[key]; -}; -ExtendedOverlay.some = function (iterator) { // Bails early as soon as iterator returns truthy. - var key; - for (key in overlays) { - if (iterator(ExtendedOverlay.get(key))) { - return; - } - } -}; -ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId (if any) - if (lastHoveringId) { - ExtendedOverlay.get(lastHoveringId).hover(false); - } -}; - -// hit(overlay) on the one overlay intersected by pickRay, if any. -// noHit() if no ExtendedOverlay was intersected (helps with hover) -ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) { - // Depends on nearer coverOverlays to extend closer to us than farther ones. - var pickedOverlay = Overlays.findRayIntersection(pickRay); - if (!pickedOverlay.intersects) { - if (noHit) { - return noHit(); - } - return; - } - ExtendedOverlay.some(function (overlay) { // See if pickedOverlay is one of ours. - if ((overlay.activeOverlay) === pickedOverlay.overlayID) { - hit(overlay); - return true; - } - }); -}; - -function addAvatarNode(id) { - return new ExtendedOverlay(id, "sphere", { - drawInFront: true, - solid: true, - alpha: 0.8, - color: color(false, false), - ignoreRayIntersection: false - }); -} - -var pingPong = true; -var OVERLAY_SCALE = 0.032; -function updateOverlays() { - var eye = Camera.position; - AvatarList.getAvatarIdentifiers().forEach(function (id) { - if (!id) { - return; // don't update ourself, or avatars we're not interested in - } - var avatar = AvatarList.getAvatar(id); - if (!avatar) { - return; // will be deleted below if there had been an overlay. - } - var overlay = ExtendedOverlay.get(id); - if (!overlay) { // For now, we're treating this as a temporary loss, as from the personal space bubble. Add it back. - overlay = addAvatarNode(id); - } - var target = avatar.position; - var distance = Vec3.distance(target, eye); - var offset = 0.2; - // get diff between target and eye (a vector pointing to the eye from avatar position) - var diff = Vec3.subtract(target, eye); - var headIndex = avatar.getJointIndex("Head"); // base offset on 1/2 distance from hips to head if we can - if (headIndex > 0) { - offset = avatar.getAbsoluteJointTranslationInObjectFrame(headIndex).y / 2; - } - - // move a bit in front, towards the camera - target = Vec3.subtract(target, Vec3.multiply(Vec3.normalize(diff), offset)); - - // now bump it up a bit - target.y = target.y + offset; - - overlay.ping = pingPong; - overlay.editOverlay({ - color: color(ExtendedOverlay.isSelected(id), overlay.hovering), - position: target, - dimensions: OVERLAY_SCALE * distance - }); - }); - pingPong = !pingPong; - ExtendedOverlay.some(function (overlay) { // Remove any that weren't updated. (User is gone.) - if (overlay.ping === pingPong) { - overlay.deleteOverlay(); - } - }); -} -function removeOverlays() { - selectedId = false; - lastHoveringId = 0; - ExtendedOverlay.some(function (overlay) { - overlay.deleteOverlay(); - }); -} - -// -// Clicks. -// -function usernameFromIDReply(id, username, machineFingerprint, isAdmin) { - if (selectedId === id) { - var message = { - method: 'updateSelectedRecipientUsername', - userName: username === "" ? "unknown username" : username - }; - ui.sendMessage(message); - } -} -function handleClick(pickRay) { - ExtendedOverlay.applyPickRay(pickRay, function (overlay) { - var nextSelectedStatus = !overlay.selected; - var avatarId = overlay.key; - selectedId = nextSelectedStatus ? avatarId : false; - if (nextSelectedStatus) { - Users.requestUsernameFromID(avatarId); - } - var message = { - method: 'selectRecipient', - id: avatarId, - isSelected: nextSelectedStatus, - displayName: '"' + AvatarList.getAvatar(avatarId).sessionDisplayName + '"', - userName: '' - }; - ui.sendMessage(message); - - ExtendedOverlay.some(function (overlay) { - var id = overlay.key; - var selected = ExtendedOverlay.isSelected(id); - overlay.select(selected); - }); - - return true; - }); -} -function handleMouseEvent(mousePressEvent) { // handleClick if we get one. - if (!mousePressEvent.isLeftButton) { - return; - } - handleClick(Camera.computePickRay(mousePressEvent.x, mousePressEvent.y)); -} -function handleMouseMove(pickRay) { // given the pickRay, just do the hover logic - ExtendedOverlay.applyPickRay(pickRay, function (overlay) { - overlay.hover(true); - }, function () { - ExtendedOverlay.unHover(); - }); -} - -// handy global to keep track of which hand is the mouse (if any) -var currentHandPressed = 0; -var TRIGGER_CLICK_THRESHOLD = 0.85; -var TRIGGER_PRESS_THRESHOLD = 0.05; - -function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position - var pickRay; - if (HMD.active) { - if (currentHandPressed !== 0) { - pickRay = controllerComputePickRay(currentHandPressed); - } else { - // nothing should hover, so - ExtendedOverlay.unHover(); - return; - } - } else { - pickRay = Camera.computePickRay(event.x, event.y); - } - handleMouseMove(pickRay); -} -function handleTriggerPressed(hand, value) { - // The idea is if you press one trigger, it is the one - // we will consider the mouse. Even if the other is pressed, - // we ignore it until this one is no longer pressed. - var isPressed = value > TRIGGER_PRESS_THRESHOLD; - if (currentHandPressed === 0) { - currentHandPressed = isPressed ? hand : 0; - return; - } - if (currentHandPressed === hand) { - currentHandPressed = isPressed ? hand : 0; - return; - } - // otherwise, the other hand is still triggered - // so do nothing. -} - -// We get mouseMoveEvents from the handControllers, via handControllerPointer. -// But we don't get mousePressEvents. -var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); -var triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press'); -function controllerComputePickRay(hand) { - var controllerPose = getControllerWorldLocation(hand, true); - if (controllerPose.valid) { - return { origin: controllerPose.position, direction: Quat.getUp(controllerPose.orientation) }; - } -} -function makeClickHandler(hand) { - return function (clicked) { - if (clicked > TRIGGER_CLICK_THRESHOLD) { - var pickRay = controllerComputePickRay(hand); - handleClick(pickRay); - } - }; -} -function makePressHandler(hand) { - return function (value) { - handleTriggerPressed(hand, value); - }; -} -triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand)); -triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand)); -triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand)); -triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand)); -// END AVATAR SELECTOR LOGIC - -var sendMoneyRecipient; -var sendMoneyParticleEffectUpdateTimer; -var particleEffectTimestamp; -var sendMoneyParticleEffect; -var SEND_MONEY_PARTICLE_TIMER_UPDATE = 250; -var SEND_MONEY_PARTICLE_EMITTING_DURATION = 3000; -var SEND_MONEY_PARTICLE_LIFETIME_SECONDS = 8; -var SEND_MONEY_PARTICLE_PROPERTIES = { - accelerationSpread: { x: 0, y: 0, z: 0 }, - alpha: 1, - alphaFinish: 1, - alphaSpread: 0, - alphaStart: 1, - azimuthFinish: 0, - azimuthStart: -6, - color: { red: 143, green: 5, blue: 255 }, - colorFinish: { red: 255, green: 0, blue: 204 }, - colorSpread: { red: 0, green: 0, blue: 0 }, - colorStart: { red: 0, green: 136, blue: 255 }, - emitAcceleration: { x: 0, y: 0, z: 0 }, // Immediately gets updated to be accurate - emitDimensions: { x: 0, y: 0, z: 0 }, - emitOrientation: { x: 0, y: 0, z: 0 }, - emitRate: 4, - emitSpeed: 2.1, - emitterShouldTrail: true, - isEmitting: 1, - lifespan: SEND_MONEY_PARTICLE_LIFETIME_SECONDS + 1, // Immediately gets updated to be accurate - lifetime: SEND_MONEY_PARTICLE_LIFETIME_SECONDS + 1, - maxParticles: 20, - name: 'hfc-particles', - particleRadius: 0.2, - polarFinish: 0, - polarStart: 0, - radiusFinish: 0.05, - radiusSpread: 0, - radiusStart: 0.2, - speedSpread: 0, - textures: "http://hifi-content.s3.amazonaws.com/alan/dev/Particles/Bokeh-Particle-HFC.png", - type: 'ParticleEffect' -}; - -var MS_PER_SEC = 1000; -function updateSendMoneyParticleEffect() { - var timestampNow = Date.now(); - if ((timestampNow - particleEffectTimestamp) > (SEND_MONEY_PARTICLE_LIFETIME_SECONDS * MS_PER_SEC)) { - deleteSendMoneyParticleEffect(); - return; - } else if ((timestampNow - particleEffectTimestamp) > SEND_MONEY_PARTICLE_EMITTING_DURATION) { - Entities.editEntity(sendMoneyParticleEffect, { - isEmitting: 0 - }); - } else if (sendMoneyParticleEffect) { - var recipientPosition = AvatarList.getAvatar(sendMoneyRecipient).position; - var distance = Vec3.distance(recipientPosition, MyAvatar.position); - var accel = Vec3.subtract(recipientPosition, MyAvatar.position); - accel.y -= 3.0; - var life = Math.sqrt(2 * distance / Vec3.length(accel)); - Entities.editEntity(sendMoneyParticleEffect, { - emitAcceleration: accel, - lifespan: life - }); - } -} - -function deleteSendMoneyParticleEffect() { - if (sendMoneyParticleEffectUpdateTimer) { - Script.clearInterval(sendMoneyParticleEffectUpdateTimer); - sendMoneyParticleEffectUpdateTimer = null; - } - if (sendMoneyParticleEffect) { - sendMoneyParticleEffect = Entities.deleteEntity(sendMoneyParticleEffect); - } - sendMoneyRecipient = null; -} - -function onUsernameChanged() { - if (ui.checkIsOpen()) { - ui.open(WALLET_QML_SOURCE); - } -} - -var MARKETPLACE_QML_PATH = "hifi/commerce/marketplace/Marketplace.qml"; -function openMarketplace(optionalItem) { - ui.open(MARKETPLACE_QML_PATH); - - if (optionalItem) { - ui.tablet.sendToQml({ - method: 'updateMarketplaceQMLItem', - params: { itemId: optionalItem } - }); - } -} - -function setCertificateInfo(itemCertificateId) { - ui.tablet.sendToQml({ - method: 'inspectionCertificate_setCertificateId', - entityId: "", - certificateId: itemCertificateId - }); -} - -// Function Name: fromQml() -// -// Description: -// -Called when a message is received from SpectatorCamera.qml. The "message" argument is what is sent from the QML -// in the format "{method, params}", like json-rpc. See also sendToQml(). -function fromQml(message) { - switch (message.method) { - case 'passphrasePopup_cancelClicked': - case 'needsLogIn_cancelClicked': - ui.close(); - break; - case 'walletSetup_cancelClicked': - switch (message.referrer) { - case '': // User clicked "Wallet" app - case undefined: - case null: - ui.close(); - break; - case 'purchases': - case 'marketplace cta': - case 'mainPage': - openMarketplace(); - break; - default: - openMarketplace(); - break; - } - break; - case 'needsLogIn_loginClicked': - openLoginWindow(); - break; - case 'disableHmdPreview': - break; // do nothing here, handled in marketplaces.js - case 'maybeEnableHmdPreview': - break; // do nothing here, handled in marketplaces.js - case 'transactionHistory_linkClicked': - openMarketplace(message.itemId); - break; - case 'goToMarketplaceMainPage': - openMarketplace(); - break; - case 'goToMarketplaceItemPage': - openMarketplace(message.itemId); - break; - case 'refreshConnections': - print('Refreshing Connections...'); - getConnectionData(false); - break; - case 'enable_ChooseRecipientNearbyMode': - if (!isUpdateOverlaysWired) { - Script.update.connect(updateOverlays); - isUpdateOverlaysWired = true; - } - break; - case 'disable_ChooseRecipientNearbyMode': - if (isUpdateOverlaysWired) { - Script.update.disconnect(updateOverlays); - isUpdateOverlaysWired = false; - } - removeOverlays(); - break; - case 'sendAsset_sendPublicly': - deleteSendMoneyParticleEffect(); - sendMoneyRecipient = message.recipient; - var props = SEND_MONEY_PARTICLE_PROPERTIES; - props.parentID = MyAvatar.sessionUUID; - props.position = MyAvatar.position; - props.position.y += 0.2; - if (message.effectImage) { - props.textures = message.effectImage; - } - sendMoneyParticleEffect = Entities.addEntity(props, true); - particleEffectTimestamp = Date.now(); - updateSendMoneyParticleEffect(); - sendMoneyParticleEffectUpdateTimer = - Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE); - break; - case 'transactionHistory_goToBank': - if (Account.metaverseServerURL.indexOf("staging") >= 0) { - Window.location = "hifi://hifiqa-master-metaverse-staging"; // So that we can test in staging. - } else { - Window.location = "hifi://BankOfHighFidelity"; - } - break; - case 'purchases_updateWearables': - var currentlyWornWearables = []; - var ATTACHMENT_SEARCH_RADIUS = 100; // meters (just in case) - - var nearbyEntities = Entities.findEntitiesByType('Model', MyAvatar.position, ATTACHMENT_SEARCH_RADIUS); - - for (var i = 0; i < nearbyEntities.length; i++) { - var currentProperties = Entities.getEntityProperties( - nearbyEntities[i], ['certificateID', 'editionNumber', 'parentID'] - ); - if (currentProperties.parentID === MyAvatar.sessionUUID) { - currentlyWornWearables.push({ - entityID: nearbyEntities[i], - entityCertID: currentProperties.certificateID, - entityEdition: currentProperties.editionNumber - }); - } - } - - ui.tablet.sendToQml({ method: 'updateWearables', wornWearables: currentlyWornWearables }); - break; - case 'purchases_walletNotSetUp': - ui.tablet.sendToQml({ - method: 'updateWalletReferrer', - referrer: "purchases" - }); - break; - case 'purchases_openGoTo': - ui.open("hifi/tablet/TabletAddressDialog.qml"); - break; - case 'purchases_itemInfoClicked': - var itemId = message.itemId; - if (itemId && itemId !== "") { - openMarketplace(itemId); - } - break; - case 'purchases_itemCertificateClicked': - setCertificateInfo(message.itemCertificateId); - break; - case 'clearShouldShowDotHistory': - shouldShowDotHistory = false; - ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory); - break; - case 'clearShouldShowDotUpdates': - shouldShowDotUpdates = false; - ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory); - break; - case 'http.request': - // Handled elsewhere, don't log. - break; - case 'closeSendAsset': - ui.close(); - break; - default: - print('wallet.js: Unrecognized message from QML'); - } -} - -var isWired = false; -function walletOpened() { - Users.usernameFromIDReply.connect(usernameFromIDReply); - Controller.mousePressEvent.connect(handleMouseEvent); - Controller.mouseMoveEvent.connect(handleMouseMoveEvent); - triggerMapping.enable(); - triggerPressMapping.enable(); - isWired = true; - - if (shouldShowDotHistory) { - ui.sendMessage({ - method: 'updateRecentActivityMessageLight', - messagesWaiting: shouldShowDotHistory - }); - } -} - -function walletClosed() { - off(); -} - -function notificationDataProcessPageUpdates(data) { - return data.data.updates; -} - -function notificationDataProcessPageHistory(data) { - return data.data.history; -} - -var shouldShowDotUpdates = false; -function notificationPollCallbackUpdates(updatesArray) { - shouldShowDotUpdates = updatesArray.length > 0; - ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory); - - if (updatesArray.length > 0) { - var message; - if (!ui.notificationInitialCallbackMade[0]) { - message = updatesArray.length + " of your purchased items " + - (updatesArray.length === 1 ? "has an update " : "have updates ") + - "available. Open INVENTORY to update."; - ui.notificationDisplayBanner(message); - - ui.notificationPollCaresAboutSince[0] = true; - } else { - for (var i = 0; i < updatesArray.length; i++) { - message = "Update available for \"" + - updatesArray[i].base_item_title + "\"." + - "Open INVENTORY to update."; - ui.notificationDisplayBanner(message); - } - } - } -} -var shouldShowDotHistory = false; -function notificationPollCallbackHistory(historyArray) { - if (!ui.isOpen) { - var notificationCount = historyArray.length; - shouldShowDotHistory = shouldShowDotHistory || notificationCount > 0; - ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory); - - if (notificationCount > 0) { - var message; - if (!ui.notificationInitialCallbackMade[1]) { - message = "You have " + notificationCount + " unread recent " + - "transaction" + (notificationCount === 1 ? "" : "s") + ". Open INVENTORY to see all activity."; - ui.notificationDisplayBanner(message); - } else { - for (var i = 0; i < notificationCount; i++) { - var historyMessage = historyArray[i].message; - var sanitizedHistoryMessage = historyMessage.replace(/<\/?[^>]+(>|$)/g, ""); - message = '"' + sanitizedHistoryMessage + '" ' + - "Open INVENTORY to see all activity."; - ui.notificationDisplayBanner(message); - } - } - } - } -} - -function isReturnedDataEmptyUpdates(data) { - var updatesArray = data.data.updates; - return updatesArray.length === 0; -} - -function isReturnedDataEmptyHistory(data) { - var historyArray = data.data.history; - return historyArray.length === 0; -} - -var DEVELOPER_MENU = "Developer"; -var MARKETPLACE_ITEM_TESTER_LABEL = "Marketplace Item Tester"; -var MARKETPLACE_ITEM_TESTER_QML_SOURCE = "hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml"; -function installMarketplaceItemTester() { - if (!Menu.menuExists(DEVELOPER_MENU)) { - Menu.addMenu(DEVELOPER_MENU); - } - if (!Menu.menuItemExists(DEVELOPER_MENU, MARKETPLACE_ITEM_TESTER_LABEL)) { - Menu.addMenuItem({ - menuName: DEVELOPER_MENU, - menuItemName: MARKETPLACE_ITEM_TESTER_LABEL, - isCheckable: false - }); - } - - Menu.menuItemEvent.connect(function (menuItem) { - if (menuItem === MARKETPLACE_ITEM_TESTER_LABEL) { - ui.open(MARKETPLACE_ITEM_TESTER_QML_SOURCE); - } - }); -} - -function uninstallMarketplaceItemTester() { - if (Menu.menuExists(DEVELOPER_MENU) && - Menu.menuItemExists(DEVELOPER_MENU, MARKETPLACE_ITEM_TESTER_LABEL) - ) { - Menu.removeMenuItem(DEVELOPER_MENU, MARKETPLACE_ITEM_TESTER_LABEL); - } -} - -var BUTTON_NAME = "INVENTORY"; -var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml"; -var SENDASSET_QML_SOURCE = "hifi/commerce/common/sendAsset/SendAsset.qml"; -var NOTIFICATION_POLL_TIMEOUT = 300000; -var ui; -function startup() { - var notificationPollEndpointArray = ["/api/v1/commerce/available_updates?per_page=10"]; - var notificationPollTimeoutMsArray = [NOTIFICATION_POLL_TIMEOUT]; - var notificationDataProcessPageArray = [notificationDataProcessPageUpdates]; - var notificationPollCallbackArray = [notificationPollCallbackUpdates]; - var notificationPollStopPaginatingConditionMetArray = [isReturnedDataEmptyUpdates]; - var notificationPollCaresAboutSinceArray = [false]; - - if (!WalletScriptingInterface.limitedCommerce) { - notificationPollEndpointArray[1] = "/api/v1/commerce/history?per_page=10"; - notificationPollTimeoutMsArray[1] = NOTIFICATION_POLL_TIMEOUT; - notificationDataProcessPageArray[1] = notificationDataProcessPageHistory; - notificationPollCallbackArray[1] = notificationPollCallbackHistory; - notificationPollStopPaginatingConditionMetArray[1] = isReturnedDataEmptyHistory; - notificationPollCaresAboutSinceArray[1] = true; - } - - ui = new AppUi({ - buttonName: BUTTON_NAME, - sortOrder: 10, - home: WALLET_QML_SOURCE, - additionalAppScreens: SENDASSET_QML_SOURCE, - onOpened: walletOpened, - onClosed: walletClosed, - onMessage: fromQml, - notificationPollEndpoint: notificationPollEndpointArray, - notificationPollTimeoutMs: notificationPollTimeoutMsArray, - notificationDataProcessPage: notificationDataProcessPageArray, - notificationPollCallback: notificationPollCallbackArray, - notificationPollStopPaginatingConditionMet: notificationPollStopPaginatingConditionMetArray, - notificationPollCaresAboutSince: notificationPollCaresAboutSinceArray - }); - GlobalServices.myUsernameChanged.connect(onUsernameChanged); - installMarketplaceItemTester(); -} - -var isUpdateOverlaysWired = false; -function off() { - if (isWired) { - Users.usernameFromIDReply.disconnect(usernameFromIDReply); - Controller.mousePressEvent.disconnect(handleMouseEvent); - Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); - triggerMapping.disable(); - triggerPressMapping.disable(); - isWired = false; - } - - if (isUpdateOverlaysWired) { - Script.update.disconnect(updateOverlays); - isUpdateOverlaysWired = false; - } - removeOverlays(); -} - -function shutdown() { - GlobalServices.myUsernameChanged.disconnect(onUsernameChanged); - deleteSendMoneyParticleEffect(); - uninstallMarketplaceItemTester(); - off(); -} - -// -// Run the functions. -// -startup(); -Script.scriptEnding.connect(shutdown); -}()); // END LOCAL_SCOPE diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 8f18be9c276..540668748a8 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -12,7 +12,7 @@ enableDispatcherModule, disableDispatcherModule, entityIsDistanceGrabbable, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic, - getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, + getControllerWorldLocation, projectOntoEntityXYPlane, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, Uuid, Picks, handsAreTracked, Messages */ @@ -80,9 +80,6 @@ Script.include("/~/system/libraries/controllers.js"); this.targetObject = null; this.actionID = null; // action this script created... this.entityToLockOnto = null; - this.potentialEntityWithContextOverlay = false; - this.entityWithContextOverlay = false; - this.contextOverlayTimer = false; this.locked = false; this.reticleMinX = MARGIN; this.reticleMaxX = null; @@ -278,7 +275,6 @@ Script.include("/~/system/libraries/controllers.js"); this.actionID = null; this.grabbedThingID = null; this.targetObject = null; - this.potentialEntityWithContextOverlay = false; }; this.updateRecommendedArea = function() { @@ -356,14 +352,6 @@ Script.include("/~/system/libraries/controllers.js"); this.previousWorldControllerRotation = worldControllerRotation; }; - this.destroyContextOverlay = function(controllerData) { - if (this.entityWithContextOverlay) { - ContextOverlay.destroyContextOverlay(this.entityWithContextOverlay); - this.entityWithContextOverlay = false; - this.potentialEntityWithContextOverlay = false; - } - }; - this.targetIsNull = function() { var properties = Entities.getEntityProperties(this.grabbedThingID, DISPATCHER_PROPERTIES); if (Object.keys(properties).length === 0 && this.distanceHolding) { @@ -388,7 +376,6 @@ Script.include("/~/system/libraries/controllers.js"); this.prepareDistanceRotatingData(controllerData); return makeRunningValues(true, [], []); } else { - this.destroyContextOverlay(); return makeRunningValues(false, [], []); } } @@ -475,15 +462,7 @@ Script.include("/~/system/libraries/controllers.js"); this.targetObject = new TargetObject(entityID, targetProps); this.targetObject.parentProps = getEntityParents(targetProps); - if (this.contextOverlayTimer) { - Script.clearTimeout(this.contextOverlayTimer); - } - this.contextOverlayTimer = false; - if (entityID === this.entityWithContextOverlay) { - this.destroyContextOverlay(); - } else { - Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); - } + Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); var targetEntity = this.targetObject.getTargetEntity(); entityID = targetEntity.id; @@ -509,40 +488,6 @@ Script.include("/~/system/libraries/controllers.js"); this.startFarGrabAction(controllerData, targetProps); } } - } else if (!this.entityWithContextOverlay) { - var _this = this; - - if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) { - if (_this.contextOverlayTimer) { - Script.clearTimeout(_this.contextOverlayTimer); - } - _this.contextOverlayTimer = false; - _this.potentialEntityWithContextOverlay = rayPickInfo.objectID; - } - - if (!_this.contextOverlayTimer) { - _this.contextOverlayTimer = Script.setTimeout(function () { - if (!_this.entityWithContextOverlay && - _this.contextOverlayTimer && - _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var props = Entities.getEntityProperties(rayPickInfo.objectID, DISPATCHER_PROPERTIES); - var pointerEvent = { - type: "Move", - id: _this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, - rayPickInfo.intersection, props), - pos3D: rayPickInfo.intersection, - normal: rayPickInfo.surfaceNormal, - direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), - button: "Secondary" - }; - if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) { - _this.entityWithContextOverlay = rayPickInfo.objectID; - } - } - _this.contextOverlayTimer = false; - }, 500); - } } } else if (this.distanceRotating) { this.distanceRotate(otherFarGrabModule); diff --git a/scripts/system/controllers/controllerModules/farGrabEntity.js b/scripts/system/controllers/controllerModules/farGrabEntity.js index c486d46c333..04ecfde0234 100644 --- a/scripts/system/controllers/controllerModules/farGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farGrabEntity.js @@ -10,7 +10,7 @@ /* global Script, Controller, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Quat, getEnabledModuleByName, makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, - projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager, + projectOntoEntityXYPlane, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, findGrabbableGroupParent, worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, handsAreTracked */ @@ -53,9 +53,6 @@ Script.include("/~/system/libraries/controllers.js"); this.targetEntityID = null; this.targetObject = null; this.previouslyUnhooked = {}; - this.potentialEntityWithContextOverlay = false; - this.entityWithContextOverlay = false; - this.contextOverlayTimer = false; this.reticleMinX = MARGIN; this.reticleMaxX = 0; this.reticleMinY = MARGIN; @@ -333,7 +330,6 @@ Script.include("/~/system/libraries/controllers.js"); })); unhighlightTargetEntity(this.targetEntityID); this.grabbing = false; - this.potentialEntityWithContextOverlay = false; MyAvatar.clearJointData(FAR_GRAB_JOINTS[this.hand]); this.initialEntityRotation = Quat.IDENTITY; this.initialControllerRotation = Quat.IDENTITY; @@ -371,14 +367,6 @@ Script.include("/~/system/libraries/controllers.js"); return false; }; - this.destroyContextOverlay = function (controllerData) { - if (this.entityWithContextOverlay) { - ContextOverlay.destroyContextOverlay(this.entityWithContextOverlay); - this.entityWithContextOverlay = false; - this.potentialEntityWithContextOverlay = false; - } - }; - this.targetIsNull = function () { var properties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); if (Object.keys(properties).length === 0 && this.distanceHolding) { @@ -418,8 +406,6 @@ Script.include("/~/system/libraries/controllers.js"); var otherModule = this.getOtherModule(); otherModule.disabled = true; return makeRunningValues(true, [], []); - } else { - this.destroyContextOverlay(); } } return makeRunningValues(false, [], []); @@ -484,15 +470,7 @@ Script.include("/~/system/libraries/controllers.js"); this.targetObject = new TargetObject(entityID, targetProps); this.targetObject.parentProps = getEntityParents(targetProps); - if (this.contextOverlayTimer) { - Script.clearTimeout(this.contextOverlayTimer); - } - this.contextOverlayTimer = false; - if (entityID === this.entityWithContextOverlay) { - this.destroyContextOverlay(); - } else { - Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); - } + Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); var targetEntity = this.targetObject.getTargetEntity(); entityID = targetEntity.id; @@ -505,41 +483,6 @@ Script.include("/~/system/libraries/controllers.js"); this.distanceHolding = true; this.startFarGrabEntity(controllerData, targetProps); } - } else if (!this.entityWithContextOverlay) { - var _this = this; - - if (_this.potentialEntityWithContextOverlay !== rayPickInfo.objectID) { - if (_this.contextOverlayTimer) { - Script.clearTimeout(_this.contextOverlayTimer); - } - _this.contextOverlayTimer = false; - _this.potentialEntityWithContextOverlay = rayPickInfo.objectID; - } - - if (!_this.contextOverlayTimer) { - _this.contextOverlayTimer = Script.setTimeout(function () { - if (!_this.entityWithContextOverlay && - _this.contextOverlayTimer && - _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { - var cotProps = Entities.getEntityProperties(rayPickInfo.objectID, - DISPATCHER_PROPERTIES); - var pointerEvent = { - type: "Move", - id: _this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, - rayPickInfo.intersection, cotProps), - pos3D: rayPickInfo.intersection, - normal: rayPickInfo.surfaceNormal, - direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), - button: "Secondary" - }; - if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.objectID, pointerEvent)) { - _this.entityWithContextOverlay = rayPickInfo.objectID; - } - } - _this.contextOverlayTimer = false; - }, 500); - } } } } diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index cf700a8ad9f..aadae35ac23 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -7,7 +7,7 @@ /* global Script, Entities, enableDispatcherModule, disableDispatcherModule, makeRunningValues, makeDispatcherModuleParameters, Overlays, HMD, TRIGGER_ON_VALUE, TRIGGER_OFF_VALUE, getEnabledModuleByName, - ContextOverlay, Picks, makeLaserParams, Settings, MyAvatar, RIGHT_HAND, LEFT_HAND, DISPATCHER_PROPERTIES + Picks, makeLaserParams, Settings, MyAvatar, RIGHT_HAND, LEFT_HAND, DISPATCHER_PROPERTIES */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -173,20 +173,6 @@ Script.include("/~/system/libraries/controllers.js"); return intersectionType["None"]; }; - this.deleteContextOverlay = function() { - var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND ? - "RightFarActionGrabEntity" : - "LeftFarActionGrabEntity"); - if (farGrabModule) { - var entityWithContextOverlay = farGrabModule.entityWithContextOverlay; - - if (entityWithContextOverlay) { - ContextOverlay.destroyContextOverlay(entityWithContextOverlay); - farGrabModule.entityWithContextOverlay = false; - } - } - }; - this.updateAlwaysOn = function(type) { var PREFER_STYLUS_OVER_LASER = "preferStylusOverLaser"; this.parameters.handLaser.alwaysOn = (!Settings.getValue(PREFER_STYLUS_OVER_LASER, false) || type === intersectionType["HifiKeyboard"]); @@ -267,7 +253,6 @@ Script.include("/~/system/libraries/controllers.js"); return makeRunningValues(true, [], []); } - this.deleteContextOverlay(); this.running = false; this.dominantHandOverride = false; return makeRunningValues(false, [], []); diff --git a/scripts/system/create/edit.js b/scripts/system/create/edit.js index 0de87e563c0..d241c4a9990 100644 --- a/scripts/system/create/edit.js +++ b/scripts/system/create/edit.js @@ -204,40 +204,6 @@ var importingSVOTextOverlay = Overlays.addOverlay("text", { visible: false }); -var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace"; -var marketplaceWindow = new OverlayWebWindow({ - title: 'Marketplace', - source: "about:blank", - width: 900, - height: 700, - visible: false -}); - -function showMarketplace(marketplaceID) { - var url = MARKETPLACE_URL; - if (marketplaceID) { - url = url + "/items/" + marketplaceID; - } - marketplaceWindow.setURL(url); - marketplaceWindow.setVisible(true); - marketplaceWindow.raise(); - - UserActivityLogger.logAction("opened_marketplace"); -} - -function hideMarketplace() { - marketplaceWindow.setVisible(false); - marketplaceWindow.setURL("about:blank"); -} - -// function toggleMarketplace() { -// if (marketplaceWindow.visible) { -// hideMarketplace(); -// } else { -// showMarketplace(); -// } -// } - function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) { // Adjust the position such that the bounding box (registration, dimensions and orientation) lies behind the original // position in the given direction. @@ -273,7 +239,7 @@ function checkEditPermissionsAndUpdate() { return; } - var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified()); + var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp()); createButton.editProperties({ icon: (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON), captionColor: (hasRezPermissions ? "#ffffff" : "#888888"), @@ -835,9 +801,7 @@ var toolBar = (function () { Entities.canRezChanged.connect(checkEditPermissionsAndUpdate); Entities.canRezTmpChanged.connect(checkEditPermissionsAndUpdate); - Entities.canRezCertifiedChanged.connect(checkEditPermissionsAndUpdate); - Entities.canRezTmpCertifiedChanged.connect(checkEditPermissionsAndUpdate); - var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified()); + var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp()); Entities.deletingEntity.connect(checkDeletedEntityAndUpdate); @@ -862,7 +826,7 @@ var toolBar = (function () { createToolsWindow.fromQml.addListener(fromQml); createButton.clicked.connect(function() { - if ( ! (Entities.canRez() || Entities.canRezTmp() || Entities.canRezCertified() || Entities.canRezTmpCertified()) ) { + if ( ! (Entities.canRez() || Entities.canRezTmp()) ) { Window.notifyEditError(INSUFFICIENT_PERMISSIONS_ERROR_MSG); return; } @@ -970,7 +934,6 @@ var toolBar = (function () { }; that.setActive = function (active) { - ContextOverlay.enabled = !active; Settings.setValue(EDIT_SETTING, active); if (active) { Controller.captureEntityClickEvents(); @@ -982,7 +945,7 @@ var toolBar = (function () { if (active === isActive) { return; } - if (active && !Entities.canRez() && !Entities.canRezTmp() && !Entities.canRezCertified() && !Entities.canRezTmpCertified()) { + if (active && !Entities.canRez() && !Entities.canRezTmp()) { Window.notifyEditError(INSUFFICIENT_PERMISSIONS_ERROR_MSG); return; } @@ -1345,13 +1308,6 @@ function mouseClickEvent(event) { return; } properties = Entities.getEntityProperties(result.entityID); - if (properties.marketplaceID) { - propertyMenu.marketplaceID = properties.marketplaceID; - propertyMenu.updateMenuItemText(showMenuItem, "Show in Marketplace"); - } else { - propertyMenu.marketplaceID = null; - propertyMenu.updateMenuItemText(showMenuItem, "No marketplace info"); - } propertyMenu.setPosition(event.x, event.y); propertyMenu.show(); } else { @@ -1837,7 +1793,7 @@ function onFileOpenChanged(filename) { } } if (importURL) { - if (!isActive && (Entities.canRez() && Entities.canRezTmp() && Entities.canRezCertified() && Entities.canRezTmpCertified())) { + if (!isActive && (Entities.canRez() && Entities.canRezTmp())) { toolBar.toggle(); } importSVO(importURL); @@ -1847,7 +1803,7 @@ function onFileOpenChanged(filename) { function onPromptTextChanged(prompt) { Window.promptTextChanged.disconnect(onPromptTextChanged); if (prompt !== "") { - if (!isActive && (Entities.canRez() && Entities.canRezTmp() && Entities.canRezCertified() && Entities.canRezTmpCertified())) { + if (!isActive && (Entities.canRez() && Entities.canRezTmp())) { toolBar.toggle(); } importSVO(prompt); @@ -1919,8 +1875,7 @@ function getPositionToCreateEntity(extra) { } function importSVO(importURL) { - if (!Entities.canRez() && !Entities.canRezTmp() && - !Entities.canRezCertified() && !Entities.canRezTmpCertified()) { + if (!Entities.canRez() && !Entities.canRezTmp()) { Window.notifyEditError(INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG); return; } @@ -2468,8 +2423,6 @@ var PropertiesTool = function (opts) { data.ids.forEach(function(entityID) { Entities.editEntity(entityID, data.properties); }); - } else if (data.type === "showMarketplace") { - showMarketplace(); } else if (data.type === "action") { if (data.action === "moveSelectionToGrid") { if (selectionManager.hasSelection()) { @@ -2770,7 +2723,6 @@ var PopupMenu = function () { }; function cleanup() { - ContextOverlay.enabled = true; for (var i = 0; i < overlays.length; i++) { Overlays.deleteOverlay(overlays[i]); } @@ -2780,8 +2732,6 @@ var PopupMenu = function () { Entities.canRezChanged.disconnect(checkEditPermissionsAndUpdate); Entities.canRezTmpChanged.disconnect(checkEditPermissionsAndUpdate); - Entities.canRezCertifiedChanged.disconnect(checkEditPermissionsAndUpdate); - Entities.canRezTmpCertifiedChanged.disconnect(checkEditPermissionsAndUpdate); } Controller.mousePressEvent.connect(self.mousePressEvent); @@ -2887,14 +2837,8 @@ keyUpEventFromUIWindow = function(keyUpEvent) { var propertyMenu = new PopupMenu(); propertyMenu.onSelectMenuItem = function (name) { - - if (propertyMenu.marketplaceID) { - showMarketplace(propertyMenu.marketplaceID); - } }; -var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace"); - var propertiesTool = new PropertiesTool(); selectionDisplay.onSpaceModeChange = function(spaceMode) { diff --git a/scripts/system/create/entityList/entityList.js b/scripts/system/create/entityList/entityList.js index b68dcf80ba5..fec72bbbc8e 100644 --- a/scripts/system/create/entityList/entityList.js +++ b/scripts/system/create/entityList/entityList.js @@ -178,7 +178,7 @@ EntityListTool = function(shouldUseEditTabletApp) { var cameraPosition = Camera.position; PROFILE("getMultipleProperties", function () { var multipleProperties = Entities.getMultipleEntityProperties(ids, ['position', 'name', 'type', 'locked', - 'visible', 'renderInfo', 'modelURL', 'materialURL', 'imageURL', 'script', 'certificateID', + 'visible', 'renderInfo', 'modelURL', 'materialURL', 'imageURL', 'script', 'skybox.url', 'ambientLight.url']); for (var i = 0; i < multipleProperties.length; i++) { var properties = multipleProperties[i]; @@ -199,7 +199,6 @@ EntityListTool = function(shouldUseEditTabletApp) { url: url, locked: properties.locked, visible: properties.visible, - certificateID: properties.certificateID, verticesCount: (properties.renderInfo !== undefined ? valueIfDefined(properties.renderInfo.verticesCount) : ""), texturesCount: (properties.renderInfo !== undefined ? diff --git a/scripts/system/create/entityList/html/js/entityList.js b/scripts/system/create/entityList/html/js/entityList.js index b70e53ce15a..d4c01df9554 100644 --- a/scripts/system/create/entityList/html/js/entityList.js +++ b/scripts/system/create/entityList/html/js/entityList.js @@ -22,7 +22,6 @@ const SCROLLBAR_WIDTH = 20; const RESIZER_WIDTH = 10; const DELTA_X_MOVE_COLUMNS_THRESHOLD = 2; const DELTA_X_COLUMN_SWAP_POSITION = 5; -const CERTIFIED_PLACEHOLDER = "** Certified **"; function decimalMegabytes(number) { return number ? (number / BYTES_PER_MEGABYTE).toFixed(1) : ""; @@ -620,11 +619,10 @@ function loaded() { id: entity.id, name: entity.name, type: type, - url: entity.certificateID === "" ? filename : "" + CERTIFIED_PLACEHOLDER + "", - fullUrl: entity.certificateID === "" ? filename : CERTIFIED_PLACEHOLDER, + url: filename, + fullUrl: filename, locked: entity.locked, visible: entity.visible, - certificateID: entity.certificateID, verticesCount: displayIfNonZero(entity.verticesCount), texturesCount: displayIfNonZero(entity.texturesCount), texturesSize: entity.texturesSize, diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index f6dcf10bc81..7cb12a230d7 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -598,7 +598,6 @@ const GROUPS = [ type: "string", placeholder: "URL", propertyID: "modelURL", - hideIfCertified: true, }, { label: "Collision Shape", @@ -612,13 +611,11 @@ const GROUPS = [ label: "Compound Shape", type: "string", propertyID: "compoundShapeURL", - hideIfCertified: true, }, { label: "Animation", type: "string", propertyID: "animation.url", - hideIfCertified: true, }, { label: "Play Automatically", @@ -670,7 +667,6 @@ const GROUPS = [ type: "textarea", propertyID: "originalTextures", readOnly: true, - hideIfCertified: true, }, { label: "Group Culled", @@ -1494,7 +1490,6 @@ const GROUPS = [ buttons: [ { id: "reload", label: "F", className: "glyph", onClick: reloadScripts } ], propertyID: "script", placeholder: "URL", - hideIfCertified: true, }, { label: "Server Script", @@ -1576,7 +1571,6 @@ const GROUPS = [ placeholder: "URL", propertyID: "collisionSoundURL", showPropertyRule: { "collisionless": "false" }, - hideIfCertified: true, }, { label: "Dynamic", @@ -3995,9 +3989,6 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) { disableSaveMaterialDataButton(); } - const certificateIDMultiValue = getMultiplePropertyValue('certificateID'); - const hasCertifiedInSelection = certificateIDMultiValue.isMultiDiffValue || certificateIDMultiValue.value !== ""; - Object.entries(properties).forEach(function([propertyID, property]) { const propertyData = property.data; const propertyName = property.name; @@ -4032,11 +4023,6 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) { return; } - if (propertyData.hideIfCertified && hasCertifiedInSelection) { - propertyValue = "** Certified **"; - property.elInput.disabled = true; - } - if (propertyName === "type") { propertyValue = entityTypes.length > 1 ? "Multiple" : propertyMultiValue.values[0]; } diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index 0c238756a9c..1121e2d8cc3 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -54,7 +54,6 @@ "Tip: Take and share your snapshots with everyone using the Snap app.", "Tip: Did you know you can show websites in-world by creating a web entity?", "Tip: Find out more information about domains by visiting our website!", - "Tip: Did you know you can get cool new apps from the Marketplace?", "Tip: Print your snapshots from the Snap app to share with others!", "Tip: Log in to make friends, visit new domains, and save avatars!" ]; diff --git a/scripts/system/libraries/cloneEntityUtils.js b/scripts/system/libraries/cloneEntityUtils.js index f789e19cd87..0f3390b06fa 100644 --- a/scripts/system/libraries/cloneEntityUtils.js +++ b/scripts/system/libraries/cloneEntityUtils.js @@ -48,8 +48,7 @@ propsAreCloneDynamic = function(props) { cloneEntity = function(props) { var entityIDToClone = props.id; - if (entityIsCloneable(props) && - (Uuid.isNull(props.certificateID) || props.certificateType.indexOf('domainUnlimited') >= 0)) { + if (entityIsCloneable(props)) { var cloneID = Entities.cloneEntity(entityIDToClone); return cloneID; } diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 5cfd899da04..b5879b717d7 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -160,9 +160,7 @@ DISPATCHER_PROPERTIES = [ "grab.equippableIndicatorOffset", "userData", "avatarEntity", - "owningAvatarID", - "certificateID", - "certificateType" + "owningAvatarID" ]; // priority -- a lower priority means the module will be asked sooner than one with a higher priority in a given update step diff --git a/scripts/system/marketplaces/marketplace.js b/scripts/system/marketplaces/marketplace.js deleted file mode 100644 index 70680acd1d5..00000000000 --- a/scripts/system/marketplaces/marketplace.js +++ /dev/null @@ -1,36 +0,0 @@ -// -// marketplace.js -// -// Created by Roxanne Skelly on 1/18/2019 -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function() { // BEGIN LOCAL_SCOPE - -var AppUi = Script.require('appUi'); - -var BUTTON_NAME = "MARKET"; -var MARKETPLACE_QML_SOURCE = "hifi/commerce/marketplace/Marketplace.qml"; -var ui; -function startup() { - - ui = new AppUi({ - buttonName: BUTTON_NAME, - sortOrder: 10, - home: MARKETPLACE_QML_SOURCE - }); -} - -function shutdown() { -} - -// -// Run the functions. -// -startup(); -Script.scriptEnding.connect(shutdown); - -}()); // END LOCAL_SCOPE diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js deleted file mode 100644 index 38287e3af30..00000000000 --- a/scripts/system/marketplaces/marketplaces.js +++ /dev/null @@ -1,830 +0,0 @@ -// -// marketplaces.js -// -// Created by Eric Levin on 8 Jan 2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -/* global Tablet, Script, HMD, UserActivityLogger, Entities, Account, Wallet, ContextOverlay, Settings, Camera, Vec3, - Quat, MyAvatar, Clipboard, Menu, Grid, Uuid, GlobalServices, openLoginWindow, getConnectionData, Overlays, SoundCache, - DesktopPreviewProvider, ResourceRequestObserver */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ - -var selectionDisplay = null; // for gridTool.js to ignore - -(function () { // BEGIN LOCAL_SCOPE -var AppUi = Script.require('appUi'); -Script.include("/~/system/libraries/gridTool.js"); -Script.include("/~/system/libraries/connectionUtils.js"); -Script.include("/~/system/libraries/accountUtils.js"); - -var MARKETPLACE_CHECKOUT_QML_PATH = "hifi/commerce/checkout/Checkout.qml"; -var MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml"; -var MARKETPLACE_ITEM_TESTER_QML_PATH = "hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml"; -var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/wallet/Wallet.qml"; // HRS FIXME "hifi/commerce/purchases/Purchases.qml"; -var MARKETPLACE_WALLET_QML_PATH = "hifi/commerce/wallet/Wallet.qml"; -var MARKETPLACE_QML_PATH = "hifi/commerce/marketplace/Marketplace.qml"; -var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js"); -var MARKETPLACES_URL = Script.resolvePath("../html/marketplaces.html"); -var METAVERSE_SERVER_URL = Account.metaverseServerURL; -var REZZING_SOUND = SoundCache.getSound(Script.resolvePath("../assets/sounds/rezzing.wav")); - -// Event bridge messages. -var CLARA_IO_DOWNLOAD = "CLARA.IO DOWNLOAD"; -var CLARA_IO_STATUS = "CLARA.IO STATUS"; -var CLARA_IO_CANCEL_DOWNLOAD = "CLARA.IO CANCEL DOWNLOAD"; -var CLARA_IO_CANCELLED_DOWNLOAD = "CLARA.IO CANCELLED DOWNLOAD"; -var GOTO_DIRECTORY = "GOTO_DIRECTORY"; -var GOTO_MARKETPLACE = "GOTO_MARKETPLACE"; -var QUERY_CAN_WRITE_ASSETS = "QUERY_CAN_WRITE_ASSETS"; -var CAN_WRITE_ASSETS = "CAN_WRITE_ASSETS"; -var WARN_USER_NO_PERMISSIONS = "WARN_USER_NO_PERMISSIONS"; - -var CLARA_DOWNLOAD_TITLE = "Preparing Download"; -var messageBox = null; -var isDownloadBeingCancelled = false; - -var CANCEL_BUTTON = 4194304; // QMessageBox::Cancel -var NO_BUTTON = 0; // QMessageBox::NoButton - -var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't write to \nthe domain's Asset Server."; - - -var resourceRequestEvents = []; -function signalResourceRequestEvent(data) { - // Once we can tie resource request events to specific resources, - // we will have to update the "0" in here. - var resourceData = "from: " + data.extra + ": " + data.url.toString().replace("__NONE__,", ""); - - if (resourceObjectsInTest[0].resourceDataArray.indexOf(resourceData) === -1) { - resourceObjectsInTest[0].resourceDataArray.push(resourceData); - - resourceObjectsInTest[0].resourceAccessEventText += "[" + data.date.toISOString() + "] " + - resourceData + "\n"; - - ui.tablet.sendToQml({ - method: "resourceRequestEvent", - data: data, - resourceAccessEventText: resourceObjectsInTest[0].resourceAccessEventText - }); - } -} - -function onResourceRequestEvent(data) { - // Once we can tie resource request events to specific resources, - // we will have to update the "0" in here. - if (resourceObjectsInTest[0] && resourceObjectsInTest[0].currentlyRecordingResources) { - var resourceRequestEvent = { - "date": new Date(), - "url": data.url, - "callerId": data.callerId, - "extra": data.extra - }; - resourceRequestEvents.push(resourceRequestEvent); - signalResourceRequestEvent(resourceRequestEvent); - } -} - -function onMessageBoxClosed(id, button) { - if (id === messageBox && button === CANCEL_BUTTON) { - isDownloadBeingCancelled = true; - messageBox = null; - ui.sendToHtml({ - type: CLARA_IO_CANCEL_DOWNLOAD - }); - } -} - -function onCanWriteAssetsChanged() { - ui.sendToHtml({ - type: CAN_WRITE_ASSETS, - canWriteAssets: Entities.canWriteAssets() - }); -} - - -var tabletShouldBeVisibleInSecondaryCamera = false; -function setTabletVisibleInSecondaryCamera(visibleInSecondaryCam) { - if (visibleInSecondaryCam) { - // if we're potentially showing the tablet, only do so if it was visible before - if (!tabletShouldBeVisibleInSecondaryCamera) { - return; - } - } else { - // if we're hiding the tablet, check to see if it was visible in the first place - tabletShouldBeVisibleInSecondaryCamera = Overlays.getProperty(HMD.tabletID, "isVisibleInSecondaryCamera"); - } - - Overlays.editOverlay(HMD.tabletID, { isVisibleInSecondaryCamera: visibleInSecondaryCam }); - Overlays.editOverlay(HMD.homeButtonID, { isVisibleInSecondaryCamera: visibleInSecondaryCam }); - Overlays.editOverlay(HMD.homeButtonHighlightID, { isVisibleInSecondaryCamera: visibleInSecondaryCam }); - Overlays.editOverlay(HMD.tabletScreenID, { isVisibleInSecondaryCamera: visibleInSecondaryCam }); -} - -function openWallet() { - ui.open(MARKETPLACE_WALLET_QML_PATH); -} -function setupWallet(referrer) { - // Needs to be done within the QML page in order to get access to QmlCommerce - openWallet(); - var ALLOWANCE_FOR_EVENT_BRIDGE_SETUP = 0; - Script.setTimeout(function () { - ui.tablet.sendToQml({ - method: 'updateWalletReferrer', - referrer: referrer - }); - }, ALLOWANCE_FOR_EVENT_BRIDGE_SETUP); -} - -function onMarketplaceOpen(referrer) { - var match; - if (Account.loggedIn && walletNeedsSetup()) { - if (referrer === MARKETPLACE_URL_INITIAL) { - setupWallet('marketplace cta'); - } else { - match = referrer.match(/\/item\/(\w+)$/); - if (match && match[1]) { - setupWallet(match[1]); - } else if (referrer.indexOf(METAVERSE_SERVER_URL) === -1) { // not a url - setupWallet(referrer); - } else { - print("WARNING: opening marketplace to", referrer, "without wallet setup."); - } - } - } -} - -function openMarketplace(optionalItem, edition) { - ui.open(MARKETPLACE_QML_PATH); - if (optionalItem) { - ui.tablet.sendToQml({ - method: 'updateMarketplaceQMLItem', - params: { itemId: optionalItem, edition: edition } - }); - } -} - -// Function Name: wireQmlEventBridge() -// -// Description: -// -Used to connect/disconnect the script's response to the tablet's "fromQml" signal. Set the "on" argument to enable or -// disable to event bridge. -// -// Relevant Variables: -// -hasEventBridge: true/false depending on whether we've already connected the event bridge. -var hasEventBridge = false; -function wireQmlEventBridge(on) { - if (!ui.tablet) { - print("Warning in wireQmlEventBridge(): 'tablet' undefined!"); - return; - } - if (on) { - if (!hasEventBridge) { - ui.tablet.fromQml.connect(onQmlMessageReceived); - hasEventBridge = true; - } - } else { - if (hasEventBridge) { - ui.tablet.fromQml.disconnect(onQmlMessageReceived); - hasEventBridge = false; - } - } -} - -var contextOverlayEntity = ""; -function openInspectionCertificateQML(currentEntityWithContextOverlay) { - ui.open(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH); - contextOverlayEntity = currentEntityWithContextOverlay; -} - -function setCertificateInfo(currentEntityWithContextOverlay, itemCertificateId) { - var certificateId = itemCertificateId || - (Entities.getEntityProperties(currentEntityWithContextOverlay, ['certificateID']).certificateID); - ui.tablet.sendToQml({ - method: 'inspectionCertificate_setCertificateId', - entityId: currentEntityWithContextOverlay, - certificateId: certificateId - }); -} - -function onUsernameChanged() { - if (onMarketplaceScreen) { - openMarketplace(); - } -} - -function walletNeedsSetup() { - return WalletScriptingInterface.walletStatus === 1; -} - -function sendCommerceSettings() { - ui.sendToHtml({ - type: "marketplaces", - action: "commerceSetting", - data: { - commerceMode: Settings.getValue("commerce", true), - userIsLoggedIn: Account.loggedIn, - walletNeedsSetup: walletNeedsSetup(), - metaverseServerURL: Account.metaverseServerURL, - limitedCommerce: WalletScriptingInterface.limitedCommerce - } - }); -} - -var grid = new Grid(); -function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) { - // Adjust the position such that the bounding box (registration, dimenions, and orientation) lies behind the original - // position in the given direction. - var CORNERS = [ - { x: 0, y: 0, z: 0 }, - { x: 0, y: 0, z: 1 }, - { x: 0, y: 1, z: 0 }, - { x: 0, y: 1, z: 1 }, - { x: 1, y: 0, z: 0 }, - { x: 1, y: 0, z: 1 }, - { x: 1, y: 1, z: 0 }, - { x: 1, y: 1, z: 1 } - ]; - - // Go through all corners and find least (most negative) distance in front of position. - var distance = 0; - for (var i = 0, length = CORNERS.length; i < length; i++) { - var cornerVector = - Vec3.multiplyQbyV(orientation, Vec3.multiplyVbyV(Vec3.subtract(CORNERS[i], registration), dimensions)); - var cornerDistance = Vec3.dot(cornerVector, direction); - distance = Math.min(cornerDistance, distance); - } - position = Vec3.sum(Vec3.multiply(distance, direction), position); - return position; -} - -var HALF_TREE_SCALE = 16384; -function getPositionToCreateEntity(extra) { - var CREATE_DISTANCE = 2; - var position; - var delta = extra !== undefined ? extra : 0; - if (Camera.mode === "entity" || Camera.mode === "independent") { - position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), CREATE_DISTANCE + delta)); - } else { - position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation), CREATE_DISTANCE + delta)); - position.y += 0.5; - } - - if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) { - return null; - } - return position; -} - -function defaultFor(arg, val) { - return typeof arg !== 'undefined' ? arg : val; -} - -var CERT_ID_URLPARAM_LENGTH = 15; // length of "certificate_id=" -function rezEntity(itemHref, itemType, marketplaceItemTesterId) { - var isWearable = itemType === "wearable"; - var success = Clipboard.importEntities(itemHref, true, marketplaceItemTesterId); - var wearableLocalPosition = null; - var wearableLocalRotation = null; - var wearableLocalDimensions = null; - var wearableDimensions = null; - marketplaceItemTesterId = defaultFor(marketplaceItemTesterId, -1); - - if (itemType === "contentSet") { - console.log("Item is a content set; codepath shouldn't go here."); - return; - } - - if (isWearable) { - var wearableTransforms = Settings.getValue("io.highfidelity.avatarStore.checkOut.transforms"); - if (!wearableTransforms) { - // TODO delete this clause - wearableTransforms = Settings.getValue("io.highfidelity.avatarStore.checkOut.tranforms"); - } - var certPos = itemHref.search("certificate_id="); // TODO how do I parse a URL from here? - if (certPos >= 0) { - certPos += CERT_ID_URLPARAM_LENGTH; - var certURLEncoded = itemHref.substring(certPos); - var certB64Encoded = decodeURIComponent(certURLEncoded); - for (var key in wearableTransforms) { - if (wearableTransforms.hasOwnProperty(key)) { - var certificateTransforms = wearableTransforms[key].certificateTransforms; - if (certificateTransforms) { - for (var certID in certificateTransforms) { - if (certificateTransforms.hasOwnProperty(certID) && - certID === certB64Encoded) { - var certificateTransform = certificateTransforms[certID]; - wearableLocalPosition = certificateTransform.localPosition; - wearableLocalRotation = certificateTransform.localRotation; - wearableLocalDimensions = certificateTransform.localDimensions; - wearableDimensions = certificateTransform.dimensions; - } - } - } - } - } - } - } - - if (success) { - var VERY_LARGE = 10000; - var isLargeImport = Clipboard.getClipboardContentsLargestDimension() >= VERY_LARGE; - var position = Vec3.ZERO; - if (!isLargeImport) { - position = getPositionToCreateEntity(Clipboard.getClipboardContentsLargestDimension() / 2); - } - if (position !== null && position !== undefined) { - var pastedEntityIDs = Clipboard.pasteEntities(position); - if (!isLargeImport) { - // The first entity in Clipboard gets the specified position with the rest being relative to it. Therefore, move - // entities after they're imported so that they're all the correct distance in front of and with geometric mean - // centered on the avatar/camera direction. - var deltaPosition = Vec3.ZERO; - var entityPositions = []; - var entityParentIDs = []; - - var propType = Entities.getEntityProperties(pastedEntityIDs[0], ["type"]).type; - var NO_ADJUST_ENTITY_TYPES = ["Zone", "Light", "ParticleEffect"]; - if (NO_ADJUST_ENTITY_TYPES.indexOf(propType) === -1) { - var targetDirection; - if (Camera.mode === "entity" || Camera.mode === "independent") { - targetDirection = Camera.orientation; - } else { - targetDirection = MyAvatar.orientation; - } - targetDirection = Vec3.multiplyQbyV(targetDirection, Vec3.UNIT_Z); - - var targetPosition = getPositionToCreateEntity(); - // Distance to move entities parallel to targetDirection. - var deltaParallel = HALF_TREE_SCALE; - // Distance to move entities perpendicular to targetDirection. - var deltaPerpendicular = Vec3.ZERO; - for (var i = 0, length = pastedEntityIDs.length; i < length; i++) { - var curLoopEntityProps = Entities.getEntityProperties(pastedEntityIDs[i], ["position", "dimensions", - "registrationPoint", "rotation", "parentID"]); - var adjustedPosition = adjustPositionPerBoundingBox(targetPosition, targetDirection, - curLoopEntityProps.registrationPoint, curLoopEntityProps.dimensions, curLoopEntityProps.rotation); - var delta = Vec3.subtract(adjustedPosition, curLoopEntityProps.position); - var distance = Vec3.dot(delta, targetDirection); - deltaParallel = Math.min(distance, deltaParallel); - deltaPerpendicular = Vec3.sum(Vec3.subtract(delta, Vec3.multiply(distance, targetDirection)), - deltaPerpendicular); - entityPositions[i] = curLoopEntityProps.position; - entityParentIDs[i] = curLoopEntityProps.parentID; - } - deltaPerpendicular = Vec3.multiply(1 / pastedEntityIDs.length, deltaPerpendicular); - deltaPosition = Vec3.sum(Vec3.multiply(deltaParallel, targetDirection), deltaPerpendicular); - } - - if (grid.getSnapToGrid()) { - var firstEntityProps = Entities.getEntityProperties(pastedEntityIDs[0], ["position", "dimensions", - "registrationPoint"]); - var positionPreSnap = Vec3.sum(deltaPosition, firstEntityProps.position); - position = grid.snapToSurface(grid.snapToGrid(positionPreSnap, false, firstEntityProps.dimensions, - firstEntityProps.registrationPoint), firstEntityProps.dimensions, firstEntityProps.registrationPoint); - deltaPosition = Vec3.subtract(position, firstEntityProps.position); - } - - if (!Vec3.equal(deltaPosition, Vec3.ZERO)) { - for (var editEntityIndex = 0, - numEntities = pastedEntityIDs.length; editEntityIndex < numEntities; editEntityIndex++) { - if (Uuid.isNull(entityParentIDs[editEntityIndex])) { - Entities.editEntity(pastedEntityIDs[editEntityIndex], { - position: Vec3.sum(deltaPosition, entityPositions[editEntityIndex]) - }); - } - } - } - } - - if (isWearable) { - // apply the relative offsets saved during checkout - var offsets = {}; - if (wearableLocalPosition) { - offsets.localPosition = wearableLocalPosition; - } - if (wearableLocalRotation) { - offsets.localRotation = wearableLocalRotation; - } - if (wearableLocalDimensions) { - offsets.localDimensions = wearableLocalDimensions; - } else if (wearableDimensions) { - offsets.dimensions = wearableDimensions; - } - // we currently assume a wearable is a single entity - Entities.editEntity(pastedEntityIDs[0], offsets); - } - - var rezPosition = Entities.getEntityProperties(pastedEntityIDs[0], "position").position; - - Audio.playSound(REZZING_SOUND, { - volume: 1.0, - position: rezPosition, - localOnly: true - }); - - } else { - Window.notifyEditError("Can't import entities: entities would be out of bounds."); - } - } else { - Window.notifyEditError("There was an error importing the entity file."); - } -} - -var referrerURL; // Used for updating Purchases QML -var filterText; // Used for updating Purchases QML -function onWebEventReceived(message) { - message = JSON.parse(message); - if (message.type === GOTO_MARKETPLACE) { - openMarketplace(message.itemId); - } else if (message.type === GOTO_DIRECTORY) { - // This is the chooser between marketplaces. Only OUR markteplace - // requires/makes-use-of wallet, so doesn't go through openMarketplace bottleneck. - ui.open(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL); - } else if (message.type === QUERY_CAN_WRITE_ASSETS) { - ui.sendToHtml(CAN_WRITE_ASSETS + " " + Entities.canWriteAssets()); - } else if (message.type === WARN_USER_NO_PERMISSIONS) { - Window.alert(NO_PERMISSIONS_ERROR_MESSAGE); - } else if (message.type === CLARA_IO_STATUS) { - if (isDownloadBeingCancelled) { - return; - } - - var text = message.status; - if (messageBox === null) { - messageBox = Window.openMessageBox(CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON); - } else { - Window.updateMessageBox(messageBox, CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON); - } - return; - } else if (message.type === CLARA_IO_DOWNLOAD) { - if (messageBox !== null) { - Window.closeMessageBox(messageBox); - messageBox = null; - } - return; - } else if (message.type === CLARA_IO_CANCELLED_DOWNLOAD) { - isDownloadBeingCancelled = false; - } else if (message.type === "CHECKOUT") { - wireQmlEventBridge(true); - ui.open(MARKETPLACE_CHECKOUT_QML_PATH); - ui.tablet.sendToQml({ - method: 'updateCheckoutQMLItemID', - params: message - }); - } else if (message.type === "REQUEST_SETTING") { - sendCommerceSettings(); - } else if (message.type === "PURCHASES") { - referrerURL = message.referrerURL; - filterText = ""; - ui.open(MARKETPLACE_PURCHASES_QML_PATH); - } else if (message.type === "LOGIN") { - openLoginWindow(); - } else if (message.type === "WALLET_SETUP") { - setupWallet('marketplace cta'); - } else if (message.type === "MY_ITEMS") { - filterText = ""; - ui.open(MARKETPLACE_PURCHASES_QML_PATH); - wireQmlEventBridge(true); - ui.tablet.sendToQml({ - method: 'purchases_showMyItems' - }); - } -} - -var savedDisablePreviewOption = Menu.isOptionChecked("Disable Preview"); -var UI_FADE_TIMEOUT_MS = 150; -function maybeEnableHMDPreview() { - // Set a small timeout to prevent sensitive data from being shown during UI fade - Script.setTimeout(function () { - setTabletVisibleInSecondaryCamera(true); - DesktopPreviewProvider.setPreviewDisabledReason("USER"); - Menu.setIsOptionChecked("Disable Preview", savedDisablePreviewOption); - }, UI_FADE_TIMEOUT_MS); -} - -var resourceObjectsInTest = []; -function signalNewResourceObjectInTest(resourceObject) { - ui.tablet.sendToQml({ - method: "newResourceObjectInTest", - resourceObject: resourceObject - }); -} - -var onQmlMessageReceived = function onQmlMessageReceived(message) { - if (message.messageSrc === "HTML") { - return; - } - switch (message.method) { - case 'gotoBank': - ui.close(); - if (Account.metaverseServerURL.indexOf("staging") >= 0) { - Window.location = "hifi://hifiqa-master-metaverse-staging"; // So that we can test in staging. - } else { - Window.location = "hifi://BankOfHighFidelity"; - } - break; - case 'checkout_openRecentActivity': - ui.open(MARKETPLACE_WALLET_QML_PATH); - wireQmlEventBridge(true); - ui.tablet.sendToQml({ - method: 'checkout_openRecentActivity' - }); - break; - case 'checkout_setUpClicked': - openWallet(); - break; - case 'checkout_walletNotSetUp': - wireQmlEventBridge(true); - ui.tablet.sendToQml({ - method: 'updateWalletReferrer', - referrer: message.referrer === "itemPage" ? message.itemId : message.referrer - }); - openWallet(); - break; - case 'checkout_cancelClicked': - openMarketplace(message.itemId); - break; - case 'header_goToPurchases': - case 'checkout_goToPurchases': - filterText = message.filterText; - ui.open(MARKETPLACE_PURCHASES_QML_PATH); - break; - case 'checkout_itemLinkClicked': - openMarketplace(message.itemId); - break; - case 'checkout_continue': - openMarketplace(); - break; - case 'marketplace_checkout': - ui.open(MARKETPLACE_CHECKOUT_QML_PATH); - ui.tablet.sendToQml({ - method: 'updateCheckoutQMLItemID', - params: message - }); - break; - case 'marketplace_marketplaces': - // This is the chooser between marketplaces. Only OUR markteplace - // requires/makes-use-of wallet, so doesn't go through openMarketplace bottleneck. - var url = MARKETPLACES_URL; - if(message.itemId) { - url = url + "?itemId=" + message.itemId - } - ui.open(url, MARKETPLACES_INJECT_SCRIPT_URL); - break; - case 'marketplace_open_link': - ui.open(message.link); - break; - case 'checkout_rezClicked': - case 'purchases_rezClicked': - case 'tester_rezClicked': - rezEntity(message.itemHref, message.itemType, message.itemId); - break; - case 'tester_newResourceObject': - var resourceObject = message.resourceObject; - resourceObjectsInTest = []; // REMOVE THIS once we support specific referrers - resourceObject.currentlyRecordingResources = false; - resourceObject.resourceAccessEventText = ""; - resourceObjectsInTest[resourceObject.resourceObjectId] = resourceObject; - resourceObjectsInTest[resourceObject.resourceObjectId].resourceDataArray = []; - signalNewResourceObjectInTest(resourceObject); - break; - case 'tester_updateResourceObjectAssetType': - resourceObjectsInTest[message.objectId].assetType = message.assetType; - break; - case 'tester_deleteResourceObject': - delete resourceObjectsInTest[message.objectId]; - break; - case 'tester_updateResourceRecordingStatus': - resourceObjectsInTest[message.objectId].currentlyRecordingResources = message.status; - if (message.status) { - resourceObjectsInTest[message.objectId].resourceDataArray = []; - resourceObjectsInTest[message.objectId].resourceAccessEventText = ""; - } - break; - case 'header_marketplaceImageClicked': - openMarketplace(); - break; - case 'purchases_goToMarketplaceClicked': - openMarketplace(); - break; - case 'updateItemClicked': - openMarketplace(message.itemId, message.itemEdition); - break; - case 'passphrasePopup_cancelClicked': - // Should/must NOT check for wallet setup. - openMarketplace(); - break; - case 'marketplace_loginClicked': - openLoginWindow(); - break; - case 'disableHmdPreview': - if (!savedDisablePreviewOption) { - DesktopPreviewProvider.setPreviewDisabledReason("SECURE_SCREEN"); - Menu.setIsOptionChecked("Disable Preview", true); - setTabletVisibleInSecondaryCamera(false); - } - break; - case 'maybeEnableHmdPreview': - maybeEnableHMDPreview(); - break; - case 'checkout_openGoTo': - ui.open("hifi/tablet/TabletAddressDialog.qml"); - break; - case 'inspectionCertificate_closeClicked': - ui.close(); - break; - case 'inspectionCertificate_requestOwnershipVerification': - ContextOverlay.requestOwnershipVerification(message.entity); - break; - case 'inspectionCertificate_showInMarketplaceClicked': - console.log("INSPECTION CERTIFICATE SHOW IN MARKETPLACE CLICKED: " + message.itemId); - openMarketplace(message.itemId); - break; - case 'header_myItemsClicked': - filterText = ""; - ui.open(MARKETPLACE_PURCHASES_QML_PATH); - wireQmlEventBridge(true); - ui.tablet.sendToQml({ - method: 'purchases_showMyItems' - }); - break; - case 'http.request': - // Handled elsewhere, don't log. - break; - // All of these are handled by wallet.js - case 'purchases_updateWearables': - case 'enable_ChooseRecipientNearbyMode': - case 'disable_ChooseRecipientNearbyMode': - case 'sendAsset_sendPublicly': - case 'refreshConnections': - case 'transactionHistory_goToBank': - case 'purchases_walletNotSetUp': - case 'purchases_openGoTo': - case 'purchases_itemInfoClicked': - case 'purchases_itemCertificateClicked': - case 'clearShouldShowDotHistory': - case 'giftAsset': - break; - default: - print('marketplaces.js: Unrecognized message from Checkout.qml'); - } -}; - -function pushResourceObjectsInTest() { - var maxResourceObjectId = -1; - var length = resourceObjectsInTest.length; - for (var i = 0; i < length; i++) { - if (i in resourceObjectsInTest) { - signalNewResourceObjectInTest(resourceObjectsInTest[i]); - var resourceObjectId = resourceObjectsInTest[i].resourceObjectId; - maxResourceObjectId = (maxResourceObjectId < resourceObjectId) ? parseInt(resourceObjectId) : maxResourceObjectId; - } - } - // N.B. Thinking about removing the following sendToQml? Be sure - // that the marketplace item tester QML has heard from us, at least - // so that it can indicate to the user that all of the resoruce - // objects in test have been transmitted to it. - //ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxResourceObjectId + 1 }); - // Since, for now, we only support 1 object in test, always send id: 0 - ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: 0 }); -} - -// Function Name: onTabletScreenChanged() -// -// Description: -// -Called when the TabletScriptingInterface::screenChanged() signal is emitted. The "type" argument can be either the string -// value of "Home", "Web", "Menu", "QML", or "Closed". The "url" argument is only valid for Web and QML. - -var onCommerceScreen = false; -var onInspectionCertificateScreen = false; -var onMarketplaceItemTesterScreen = false; -var onMarketplaceScreen = false; -var onWalletScreen = false; -var onTabletScreenChanged = function onTabletScreenChanged(type, url) { - ui.setCurrentVisibleScreenMetadata(type, url); - onMarketplaceScreen = type === "QML" && url.indexOf(MARKETPLACE_QML_PATH) !== -1; - onInspectionCertificateScreen = type === "QML" && url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1; - var onWalletScreenNow = url.indexOf(MARKETPLACE_WALLET_QML_PATH) !== -1; - var onCommerceScreenNow = type === "QML" && ( - url.indexOf(MARKETPLACE_CHECKOUT_QML_PATH) !== -1 || - url === MARKETPLACE_PURCHASES_QML_PATH || - url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1); - var onMarketplaceItemTesterScreenNow = ( - url.indexOf(MARKETPLACE_ITEM_TESTER_QML_PATH) !== -1 || - url === MARKETPLACE_ITEM_TESTER_QML_PATH); - var onMarketplaceScreenNow = ( - url.indexOf(MARKETPLACE_QML_PATH) !== -1 || - url === MARKETPLACE_QML_PATH); - if ((!onWalletScreenNow && onWalletScreen) || - (!onCommerceScreenNow && onCommerceScreen) || - (!onMarketplaceItemTesterScreenNow && onMarketplaceScreen) - ) { - // exiting wallet, commerce, or marketplace item tester screen - maybeEnableHMDPreview(); - } - - onCommerceScreen = onCommerceScreenNow; - onWalletScreen = onWalletScreenNow; - onMarketplaceItemTesterScreen = onMarketplaceItemTesterScreenNow; - wireQmlEventBridge(onCommerceScreen || onWalletScreen || onMarketplaceItemTesterScreen || onMarketplaceScreenNow); - - if (url === MARKETPLACE_PURCHASES_QML_PATH) { - // FIXME? Is there a race condition here in which the event - // bridge may not be up yet? If so, Script.setTimeout(..., 750) - // may help avoid the condition. - ui.tablet.sendToQml({ - method: 'updatePurchases', - referrerURL: referrerURL, - filterText: filterText - }); - referrerURL = ""; - filterText = ""; - } - - var wasIsOpen = ui.isOpen; - ui.isOpen = (onMarketplaceScreen || onCommerceScreen) && !onWalletScreen; - ui.buttonActive(ui.isOpen); - - if (wasIsOpen !== ui.isOpen && Keyboard.raised) { - Keyboard.raised = false; - } - - ContextOverlay.isInMarketplaceInspectionMode = false; - - - if (onInspectionCertificateScreen) { - setCertificateInfo(contextOverlayEntity); - } - - if (onCommerceScreen) { - WalletScriptingInterface.refreshWalletStatus(); - } else { - if (onMarketplaceScreen) { - onMarketplaceOpen('marketplace cta'); - } - ui.tablet.sendToQml({ - method: 'inspectionCertificate_resetCert' - }); - off(); - } - - if (onMarketplaceItemTesterScreen) { - // Why setTimeout? The QML event bridge, wired above, requires a - // variable amount of time to come up, in practice less than - // 750ms. - Script.setTimeout(pushResourceObjectsInTest, 750); - } - - console.debug(ui.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type + - "\nNew screen URL: " + url + "\nCurrent app open status: " + ui.isOpen + "\n"); -}; - - -var BUTTON_NAME = "MARKET"; - -var ui; -function startup() { - ui = new AppUi({ - buttonName: BUTTON_NAME, - sortOrder: 9, - home: MARKETPLACE_QML_PATH, - onScreenChanged: onTabletScreenChanged, - onMessage: onQmlMessageReceived - }); - ContextOverlay.contextOverlayClicked.connect(openInspectionCertificateQML); - Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged); - GlobalServices.myUsernameChanged.connect(onUsernameChanged); - ui.tablet.webEventReceived.connect(onWebEventReceived); - WalletScriptingInterface.walletStatusChanged.connect(sendCommerceSettings); - Window.messageBoxClosed.connect(onMessageBoxClosed); - ResourceRequestObserver.resourceRequestEvent.connect(onResourceRequestEvent); - - WalletScriptingInterface.refreshWalletStatus(); -} - -function off() { -} -function shutdown() { - maybeEnableHMDPreview(); - - Window.messageBoxClosed.disconnect(onMessageBoxClosed); - WalletScriptingInterface.walletStatusChanged.disconnect(sendCommerceSettings); - ui.tablet.webEventReceived.disconnect(onWebEventReceived); - GlobalServices.myUsernameChanged.disconnect(onUsernameChanged); - Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged); - ContextOverlay.contextOverlayClicked.disconnect(openInspectionCertificateQML); - ResourceRequestObserver.resourceRequestEvent.disconnect(onResourceRequestEvent); - - off(); -} - -// -// Run the functions. -// -startup(); -Script.scriptEnding.connect(shutdown); -}()); // END LOCAL_SCOPE diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 7fdb863a831..5698d9343aa 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -89,14 +89,12 @@ EDIT_ERROR: 3, TABLET: 4, CONNECTION: 5, - WALLET: 6, properties: [ { text: "Snapshot" }, { text: "Connection Refused" }, { text: "Edit error" }, { text: "Tablet" }, - { text: "Connection" }, - { text: "Wallet" } + { text: "Connection" } ], getTypeFromMenuItem: function (menuItemName) { var type; @@ -565,10 +563,6 @@ createNotification("Processing GIF snapshot...", NotificationType.SNAPSHOT); } - function walletNotSetup() { - createNotification("Your wallet isn't activated yet. Open the WALLET app.", NotificationType.WALLET); - } - function connectionAdded(connectionName) { createNotification(connectionName, NotificationType.CONNECTION); } @@ -636,7 +630,6 @@ Window.notifyEditError = onEditError; Window.notify = onNotify; Tablet.tabletNotification.connect(tabletNotification); - WalletScriptingInterface.walletNotSetup.connect(walletNotSetup); Messages.subscribe(NOTIFICATIONS_MESSAGE_CHANNEL); Messages.messageReceived.connect(onMessageReceived); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 4cf6ef1c34e..9881caec1e7 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -731,7 +731,6 @@ function createUpdateInterval() { }, UPDATE_INTERVAL_MS); } -var previousContextOverlay = ContextOverlay.enabled; var previousRequestsDomainListData = Users.requestsDomainListData; function palOpened() { ui.sendMessage({ @@ -739,9 +738,7 @@ function palOpened() { shouldShowDot: shouldShowDot }); - previousContextOverlay = ContextOverlay.enabled; previousRequestsDomainListData = Users.requestsDomainListData; - ContextOverlay.enabled = false; Users.requestsDomainListData = true; ui.tablet.tabletShownChanged.connect(tabletVisibilityChanged); @@ -922,7 +919,6 @@ function off() { } removeOverlays(); - ContextOverlay.enabled = previousContextOverlay; Users.requestsDomainListData = previousRequestsDomainListData; } diff --git a/tools/jsdoc/plugins/hifi.js b/tools/jsdoc/plugins/hifi.js index 3c1ec08bb01..99df1060555 100644 --- a/tools/jsdoc/plugins/hifi.js +++ b/tools/jsdoc/plugins/hifi.js @@ -28,7 +28,6 @@ exports.handlers = { '../../interface/src/assets', //'../../interface/src/audio', Exclude AudioScope API from output. '../../interface/src/avatar', - '../../interface/src/commerce', '../../interface/src/java', '../../interface/src/networking', '../../interface/src/raypick',