diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index dd0c341412..562ceb1cc1 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -137,11 +137,27 @@ Rectangle { console.log("Failed to get Available Updates", result.data.message); } else { root.availableUpdatesReceived = true; - if (result.data.updates.indexOf(root.itemId) > -1) { - root.isUpdating = true; + for (var i = 0; i < result.data.updates.length; i++) { + if (result.data.updates[i].item_id === root.itemId) { + root.isUpdating = true; + break; + } } } } + + onUpdateItemResult: { + if (result.status !== 'success') { + failureErrorText.text = result.message; + root.activeView = "checkoutFailure"; + } else { + root.itemHref = result.data.download_url; + if (result.data.categories.indexOf("Wearables") > -1) { + root.itemType = "wearable"; + } + root.activeView = "checkoutSuccess"; + } + } } onItemIdChanged: { @@ -447,7 +463,7 @@ Rectangle { id: itemPriceText; text: root.isUpdating ? "FREE\nUPGRADE" : ((root.itemPrice === -1) ? "--" : root.itemPrice); // Text size - size: 26; + size: root.isUpdating ? 20 : 26; // Anchors anchors.top: parent.top; anchors.right: parent.right; @@ -569,7 +585,9 @@ Rectangle { text: root.isUpdating ? "CONFIRM UPDATE" : (((root.isCertified) ? ((ownershipStatusReceived && balanceReceived && availableUpdatesReceived) ? (viewInMyPurchasesButton.visible ? "Buy It Again" : "Confirm Purchase") : "--") : "Get Item")); onClicked: { - if (root.isCertified) { + if (root.isUpdating) { + Commerce.updateItem(root.itemId); + } else if (root.isCertified) { if (!root.shouldBuyWithControlledFailure) { if (root.itemType === "contentSet" && !Entities.canReplaceContent()) { lightboxPopup.titleText = "Purchase Content Set"; @@ -1020,12 +1038,12 @@ Rectangle { switch (message.method) { case 'updateCheckoutQML': root.isUpdating = message.params.isUpdating; - itemId = message.params.itemId; - itemName = message.params.itemName; + root.itemId = message.params.itemId; + root.itemName = message.params.itemName.trim(); root.itemPrice = message.params.itemPrice; - itemHref = message.params.itemHref; - referrer = message.params.referrer; - itemAuthor = message.params.itemAuthor; + root.itemHref = message.params.itemHref; + root.referrer = message.params.referrer; + root.itemAuthor = message.params.itemAuthor; refreshBuyUI(); break; default: @@ -1056,11 +1074,9 @@ Rectangle { } if (root.isUpdating) { - buyText.text = "By agreeing to update, you agree to trade in your old item for the update that replaces it."; - buyTextContainer.color = "#FFC3CD"; - buyTextContainer.border.color = "#F3808F"; - buyGlyph.text = hifi.glyphs.alert; - buyGlyph.size = 54; + 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 (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 + ""; diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index d8e02b08e5..df36bfd753 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -50,11 +50,12 @@ Item { property bool isInstalled; property string upgradeUrl; property string upgradeTitle; + property bool isShowingMyItems; property string originalStatusText; property string originalStatusColor; - height: root.upgradeUrl === "" ? 110 : 150; + height: (root.upgradeUrl === "" || root.isShowingMyItems) ? 110 : 150; width: parent.width; Connections { @@ -647,7 +648,7 @@ Item { Rectangle { id: upgradeAvailableContainer; - visible: root.upgradeUrl !== ""; + visible: root.upgradeUrl !== "" && !root.isShowingMyItems; anchors.top: itemContainer.bottom; anchors.bottom: parent.bottom; anchors.left: parent.left; diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 8952aad0cf..485ae81305 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -400,6 +400,7 @@ Rectangle { isInstalled: model.isInstalled; upgradeUrl: model.upgrade_url; upgradeTitle: model.upgrade_title; + isShowingMyItems: root.isShowingMyItems; itemType: { if (model.root_file_url.indexOf(".fst") > -1) { "avatar"; diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 62411a095a..c9b6bf3523 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -53,6 +53,7 @@ Handler(transferHfcToNode) Handler(transferHfcToUsername) 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(); @@ -372,3 +373,14 @@ void Ledger::getAvailableUpdates() { request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); send(endpoint, "availableUpdatesSuccess", "availableUpdatesFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request); } + +void Ledger::updateItem(const QString& hfc_key, const QString& asset_id, const QString& inventory_key) { + QJsonObject transaction; + transaction["hfc_key"] = hfc_key; + transaction["cost"] = 0; + transaction["asset_id"] = asset_id; + transaction["inventory_key"] = inventory_key; + 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 index 04c618d665..c68ed8493b 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -37,6 +37,7 @@ public: void transferHfcToUsername(const QString& hfc_key, const QString& username, const int& amount, const QString& optionalMessage); void alreadyOwned(const QString& marketplaceId); void getAvailableUpdates(); + void updateItem(const QString& hfc_key, const QString& asset_id, const QString& inventory_key); enum CertificateStatus { CERTIFICATE_STATUS_UNKNOWN = 0, @@ -59,6 +60,7 @@ signals: void transferHfcToUsernameResult(QJsonObject result); void alreadyOwnedResult(QJsonObject result); void availableUpdatesResult(QJsonObject result); + void updateItemResult(QJsonObject result); void updateCertificateStatus(const QString& certID, uint certStatus); @@ -87,6 +89,8 @@ public slots: 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); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 57d5e53794..701f2403d4 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -39,6 +39,7 @@ QmlCommerce::QmlCommerce() { connect(ledger.data(), &Ledger::transferHfcToNodeResult, this, &QmlCommerce::transferHfcToNodeResult); connect(ledger.data(), &Ledger::transferHfcToUsernameResult, this, &QmlCommerce::transferHfcToUsernameResult); 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, [&]() { @@ -349,3 +350,16 @@ void QmlCommerce::getAvailableUpdates() { auto ledger = DependencyManager::get(); ledger->getAvailableUpdates(); } + +void QmlCommerce::updateItem(const QString& marketplaceId) { + 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]; + // For now, we receive at the same key that pays for it. + ledger->updateItem(key, marketplaceId, key); +} diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index f3615cc8a5..fdca17e557 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -44,6 +44,7 @@ signals: void certificateInfoResult(QJsonObject result); void alreadyOwnedResult(QJsonObject result); void availableUpdatesResult(QJsonObject result); + void updateItemResult(QJsonObject result); void updateCertificateStatus(const QString& certID, uint certStatus); @@ -90,6 +91,7 @@ protected: Q_INVOKABLE bool openApp(const QString& appHref); Q_INVOKABLE void getAvailableUpdates(); + Q_INVOKABLE void updateItem(const QString& marketplaceId); private: QString _appsPath; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 1546c2e6d5..d033e6988d 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -262,6 +262,7 @@ isUpdating: true, itemId: id, itemName: name, + itemPrice: 0, itemHref: href, referrer: referrer, itemAuthor: author @@ -436,7 +437,7 @@ var cost = $('.item-cost').text(); if (availability !== 'available') { purchaseButton.html('UNAVAILABLE (' + availability + ')'); - } else if (url.indexOf('edition=' != -1)) { + } else if (window.location.href.indexOf('edition=' != -1)) { purchaseButton.html('UPDATE FOR FREE'); } else if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) { purchaseButton.html('PURCHASE