diff --git a/interface/resources/qml/hifi/avatarapp/MessageBoxes.qml b/interface/resources/qml/hifi/avatarapp/MessageBoxes.qml index 2c02272b46..89a8eff025 100644 --- a/interface/resources/qml/hifi/avatarapp/MessageBoxes.qml +++ b/interface/resources/qml/hifi/avatarapp/MessageBoxes.qml @@ -89,7 +89,7 @@ MessageBox { function showDeleteFavorite(favoriteName, callback) { popup.titleText = 'Delete Favorite: {AvatarName}'.replace('{AvatarName}', favoriteName) - popup.bodyText = 'This will delete your favorite. You will retain access to the wearables and avatar that made up the favorite from My Purchases.' + popup.bodyText = 'This will delete your favorite. You will retain access to the wearables and avatar that made up the favorite from Inventory.' popup.imageSource = null; popup.button1text = 'CANCEL' popup.button2text = 'DELETE' diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index f88a70ff05..95b040eceb 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -559,7 +559,7 @@ Rectangle { } } - // "View in My Purchases" button + // "View in Inventory" button HifiControlsUit.Button { id: viewInMyPurchasesButton; visible: false; @@ -833,7 +833,7 @@ Rectangle { } lightboxPopup.button2text = "OPEN GOTO"; lightboxPopup.button2method = function() { - sendToScript({method: 'purchases_openGoTo'}); + sendToScript({method: 'checkout_openGoTo'}); lightboxPopup.visible = false; }; lightboxPopup.visible = true; @@ -886,7 +886,8 @@ Rectangle { RalewaySemiBold { id: walletLink; - text: 'View receipt in Wallet'; + visible: !WalletScriptingInterface.limitedCommerce; + text: 'View receipt in Recent Activity'; // Text size size: 18; // Anchors @@ -902,18 +903,18 @@ Rectangle { horizontalAlignment: Text.AlignLeft; verticalAlignment: Text.AlignVCenter; onLinkActivated: { - sendToScript({method: 'purchases_openWallet'}); + sendToScript({method: 'checkout_openWallet'}); } } RalewayRegular { id: pendingText; - text: 'Your item is marked "pending" while it is being confirmed. ' + + text: 'Your item is marked "pending" while the transfer is being confirmed. ' + 'Learn More'; // Text size size: 18; // Anchors - anchors.top: walletLink.bottom; + anchors.top: walletLink.visible ? walletLink.bottom : myPurchasesLink.bottom; anchors.topMargin: 32; height: paintedHeight; anchors.left: parent.left; @@ -926,7 +927,7 @@ Rectangle { verticalAlignment: Text.AlignVCenter; onLinkActivated: { lightboxPopup.titleText = "Confirmations"; - lightboxPopup.bodyText = 'Your item is marked "pending" while it is being confirmed.

' + + 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() { diff --git a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml index de9c62c197..4b0166425a 100644 --- a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml +++ b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml @@ -27,7 +27,6 @@ Item { property string referrerURL: (Account.metaverseServerURL + "/marketplace?"); readonly property int additionalDropdownHeight: usernameDropdown.height - myUsernameButton.anchors.bottomMargin; property alias usernameDropdownVisible: usernameDropdown.visible; - property bool messagesWaiting: false; height: mainContainer.height + additionalDropdownHeight; @@ -38,7 +37,6 @@ Item { if (walletStatus === 0) { sendToParent({method: "needsLogIn"}); } else if (walletStatus === 5) { - Commerce.getAvailableUpdates(); Commerce.getSecurityImage(); } else if (walletStatus > 5) { console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus); @@ -59,14 +57,6 @@ Item { securityImage.source = "image://security/securityImage"; } } - - onAvailableUpdatesResult: { - if (result.status !== 'success') { - console.log("Failed to get Available Updates", result.data.message); - } else { - root.messagesWaiting = result.data.updates.length > 0; - } - } } Component.onCompleted: { @@ -118,50 +108,6 @@ Item { anchors.right: securityImage.left; anchors.rightMargin: 6; - Rectangle { - id: myPurchasesLink; - anchors.right: myUsernameButton.left; - anchors.rightMargin: 8; - anchors.verticalCenter: parent.verticalCenter; - height: 40; - width: myPurchasesText.paintedWidth + 10; - - RalewaySemiBold { - id: myPurchasesText; - text: "Inventory"; - // Text size - size: 18; - // Style - color: hifi.colors.blueAccent; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - // Anchors - anchors.centerIn: parent; - } - - MouseArea { - anchors.fill: parent; - hoverEnabled: enabled; - onClicked: { - sendToParent({ method: 'header_goToPurchases', hasUpdates: root.messagesWaiting }); - } - onEntered: myPurchasesText.color = hifi.colors.blueHighlight; - onExited: myPurchasesText.color = hifi.colors.blueAccent; - } - } - - Rectangle { - id: messagesWaitingLight; - visible: root.messagesWaiting; - anchors.right: myPurchasesLink.left; - anchors.rightMargin: -2; - anchors.verticalCenter: parent.verticalCenter; - height: 10; - width: height; - radius: height/2; - color: "red"; - } - TextMetrics { id: textMetrics; font.family: "Raleway" diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml index 0a5c3e8053..bb4bb624bc 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml @@ -73,6 +73,10 @@ Item { } onTransferAssetToNodeResult: { + if (!root.visible) { + return; + } + root.isCurrentlySendingAsset = false; if (result.status === 'success') { @@ -92,6 +96,10 @@ Item { } onTransferAssetToUsernameResult: { + if (!root.visible) { + return; + } + root.isCurrentlySendingAsset = false; if (result.status === 'success') { @@ -1309,13 +1317,13 @@ Item { Rectangle { anchors.top: parent.top; - anchors.topMargin: root.assetName === "" ? 15 : 150; + anchors.topMargin: root.assetName === "" ? 15 : 125; anchors.left: parent.left; anchors.leftMargin: root.assetName === "" ? 15 : 50; anchors.right: parent.right; anchors.rightMargin: root.assetName === "" ? 15 : 50; anchors.bottom: parent.bottom; - anchors.bottomMargin: root.assetName === "" ? 15 : 240; + anchors.bottomMargin: root.assetName === "" ? 15 : 125; color: "#FFFFFF"; RalewaySemiBold { diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index eeb9ac3c54..d13473af22 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -345,6 +345,7 @@ Item { Rectangle { id: permissionExplanationCard; + visible: false; anchors.left: parent.left; anchors.leftMargin: 30; anchors.top: parent.top; diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 655af79e68..eeb98eeb8c 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -19,7 +19,6 @@ 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 "../inspectionCertificate" as HifiInspectionCertificate import "../common/sendAsset" as HifiSendAsset import "../.." as HifiCommon @@ -118,19 +117,6 @@ Rectangle { } } - HifiInspectionCertificate.InspectionCertificate { - id: inspectionCertificate; - z: 998; - visible: false; - anchors.fill: parent; - - Connections { - onSendToScript: { - sendToScript(message); - } - } - } - HifiCommerceCommon.CommerceLightbox { id: lightboxPopup; z: 999; @@ -200,11 +186,6 @@ Rectangle { lightboxPopup.button1method = function() { lightboxPopup.visible = false; } - lightboxPopup.button2text = "GO TO WALLET"; - lightboxPopup.button2method = function() { - sendToScript({method: 'purchases_openWallet'}); - lightboxPopup.visible = false; - }; lightboxPopup.visible = true; } else { sendToScript(msg); @@ -627,8 +608,6 @@ Rectangle { sendToScript({ method: 'purchases_updateWearables' }); } } else if (msg.method === 'purchases_itemCertificateClicked') { - inspectionCertificate.visible = true; - inspectionCertificate.isLightbox = true; sendToScript(msg); } else if (msg.method === "showInvalidatedLightbox") { lightboxPopup.titleText = "Item Invalidated"; @@ -641,7 +620,7 @@ Rectangle { lightboxPopup.visible = true; } else if (msg.method === "showPendingLightbox") { lightboxPopup.titleText = "Item Pending"; - lightboxPopup.bodyText = 'Your item is marked "pending" while your purchase is being confirmed. ' + + 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() { @@ -1066,9 +1045,6 @@ Rectangle { titleBarContainer.referrerURL = message.referrerURL || ""; filterBar.text = message.filterText ? message.filterText : ""; break; - case 'inspectionCertificate_setCertificateId': - inspectionCertificate.fromScript(message); - break; case 'purchases_showMyItems': root.isShowingMyItems = true; break; diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index ee86844aaa..a958e62aad 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -21,6 +21,7 @@ import "../common" as HifiCommerceCommon import "../common/sendAsset" import "../.." as HifiCommon import "../purchases" as HifiPurchases +import "../inspectionCertificate" as HifiInspectionCertificate Rectangle { HifiConstants { id: hifi; } @@ -30,7 +31,6 @@ Rectangle { property string activeView: "initialize"; property bool keyboardRaised: false; property bool isPassword: false; - property bool limitedCommerce: true; anchors.fill: (typeof parent === undefined) ? undefined : parent; @@ -67,6 +67,7 @@ Rectangle { } else if (walletStatus === 5) { if (root.activeView !== "walletSetup") { root.activeView = "walletInventory"; + Commerce.getAvailableUpdates(); Commerce.getSecurityImage(); } } else { @@ -88,6 +89,14 @@ Rectangle { 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; + } + } } HifiCommerceCommon.CommerceLightbox { @@ -339,6 +348,10 @@ Rectangle { if (msg.method === 'transactionHistory_usernameLinkClicked') { userInfoViewer.url = msg.usernameLink; userInfoViewer.visible = true; + } else if (msg.method === 'goToPurchases_fromWalletHome') { + root.activeView = "walletInventory"; + walletInventory.isShowingMyItems = false; + tabButtonsContainer.resetTabButtonColors(); } else { sendToScript(msg); } @@ -346,7 +359,20 @@ Rectangle { } } - HifiPurchases.Purchases { + 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; @@ -355,10 +381,15 @@ Rectangle { anchors.right: parent.right; Connections { onSendToScript: { - sendToScript(message); + if (message.method === 'purchases_itemCertificateClicked') { + inspectionCertificate.visible = true; + inspectionCertificate.isLightbox = true; + sendToScript(message); + } else { + sendToScript(message); + } } } - } HifiCommon.RootHttpRequest { @@ -480,7 +511,7 @@ Rectangle { anchors.top: parent.top; anchors.topMargin: -2; // Style - color: root.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); + color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); } RalewaySemiBold { @@ -495,7 +526,7 @@ Rectangle { anchors.right: parent.right; anchors.rightMargin: 4; // Style - color: root.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); + color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); wrapMode: Text.WordWrap; // Alignment horizontalAlignment: Text.AlignHCenter; @@ -504,7 +535,7 @@ Rectangle { MouseArea { id: walletHomeTabMouseArea; anchors.fill: parent; - enabled: !root.limitedCommerce; + enabled: !WalletScriptingInterface.limitedCommerce; hoverEnabled: enabled; onClicked: { root.activeView = "walletHome"; @@ -518,6 +549,8 @@ Rectangle { // "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; @@ -535,7 +568,20 @@ Rectangle { anchors.top: parent.top; anchors.topMargin: -2; // Style - color: root.activeView === "walletInventory" || walletHomeTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight; + color: root.activeView === "walletInventory" || inventoryTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight; + } + + Rectangle { + id: messagesWaitingLight; + visible: parent.messagesWaiting; + anchors.right: exchangeMoneyTabIcon.left; + anchors.rightMargin: -4; + anchors.top: exchangeMoneyTabIcon.top; + anchors.topMargin: 16; + height: 10; + width: height; + radius: height/2; + color: "red"; } RalewaySemiBold { @@ -550,7 +596,7 @@ Rectangle { anchors.right: parent.right; anchors.rightMargin: 4; // Style - color: root.activeView === "walletInventory" || walletHomeTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight; + color: root.activeView === "walletInventory" || inventoryTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight; wrapMode: Text.WordWrap; // Alignment horizontalAlignment: Text.AlignHCenter; @@ -592,7 +638,7 @@ Rectangle { anchors.top: parent.top; anchors.topMargin: -2; // Style - color: root.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); + color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); } RalewaySemiBold { @@ -607,7 +653,7 @@ Rectangle { anchors.right: parent.right; anchors.rightMargin: 4; // Style - color: root.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); + color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight); wrapMode: Text.WordWrap; // Alignment horizontalAlignment: Text.AlignHCenter; @@ -617,7 +663,7 @@ Rectangle { MouseArea { id: sendMoneyTabMouseArea; anchors.fill: parent; - enabled: !root.limitedCommerce; + enabled: !WalletScriptingInterface.limitedCommerce; hoverEnabled: enabled; onClicked: { root.activeView = "sendMoney"; @@ -825,17 +871,26 @@ Rectangle { 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 'setLimitedCommerce': - root.limitedCommerce = message.limitedCommerce; - break; - default: - // HRS FIXME console.log('Unrecognized message from wallet.js:', JSON.stringify(message)); + case 'inspectionCertificate_setCertificateId': + inspectionCertificate.fromScript(message); + break; + case 'updatePurchases': + case 'purchases_showMyItems': + case 'updateConnections': + case 'selectRecipient': + case 'updateSelectedRecipientUsername': + case 'updateWearables': walletInventory.fromScript(message); + break; + default: + console.log('Unrecognized message from wallet.js:', JSON.stringify(message)); } } signal sendToScript(var message); @@ -881,7 +936,9 @@ Rectangle { root.activeView = "initialize"; Commerce.getWalletStatus(); } else if (msg.referrer === 'purchases') { - sendToScript({method: 'goToPurchases'}); + root.activeView = "walletInventory"; + walletInventory.isShowingMyItems = false; + tabButtonsContainer.resetTabButtonColors(); } else if (msg.referrer === 'marketplace cta' || msg.referrer === 'mainPage') { sendToScript({method: 'goToMarketplaceMainPage', itemId: msg.referrer}); } else { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3f354f64b5..70c25ce823 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3154,7 +3154,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); surfaceContext->setContextProperty("Selection", DependencyManager::get().data()); surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get().data()); - surfaceContext->setContextProperty("Wallet", DependencyManager::get().data()); + surfaceContext->setContextProperty("WalletScriptingInterface", DependencyManager::get().data()); surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance()); surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get().data()); @@ -6876,7 +6876,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance()); scriptEngine->registerGlobalObject("Selection", DependencyManager::get().data()); scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("Wallet", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("WalletScriptingInterface", DependencyManager::get().data()); scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get().data()); scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance()); scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get().data()); @@ -7881,6 +7881,10 @@ void Application::loadAvatarBrowser() const { auto tablet = dynamic_cast(DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); // construct the url to the marketplace item QString url = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace?category=avatars"; + if (DependencyManager::get()->getLimitedCommerce()) { + url += "&isFree=1"; + } + QString MARKETPLACES_INJECT_SCRIPT_PATH = "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js"; tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_PATH); DependencyManager::get()->openTablet(); diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 67303f2a9b..f4bd7a84b3 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -240,7 +240,6 @@ QString transactionString(const QJsonObject& valueObject) { return result; } -static const QString MARKETPLACE_ITEMS_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/"; 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 diff --git a/interface/src/scripting/WalletScriptingInterface.h b/interface/src/scripting/WalletScriptingInterface.h index c4ab0da851..8aebb68a47 100644 --- a/interface/src/scripting/WalletScriptingInterface.h +++ b/interface/src/scripting/WalletScriptingInterface.h @@ -36,29 +36,29 @@ public: * @hifi-client-entity * * @property {number} walletStatus + * @property {bool} limitedCommerce */ 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) + Q_PROPERTY(bool limitedCommerce READ getLimitedCommerce WRITE setLimitedCommerce NOTIFY limitedCommerceChanged) public: /**jsdoc - * @function Wallet.refreshWalletStatus + * @function WalletScriptingInterface.refreshWalletStatus */ Q_INVOKABLE void refreshWalletStatus(); /**jsdoc - * @function Wallet.getWalletStatus + * @function WalletScriptingInterface.getWalletStatus * @returns {number} */ Q_INVOKABLE uint getWalletStatus() { return _walletStatus; } /**jsdoc - * @function Wallet.proveAvatarEntityOwnershipVerification + * @function WalletScriptingInterface.proveAvatarEntityOwnershipVerification * @param {Uuid} entityID */ Q_INVOKABLE void proveAvatarEntityOwnershipVerification(const QUuid& entityID); @@ -67,32 +67,38 @@ public: // scripts could cause the Wallet to incorrectly report its status. void setWalletStatus(const uint& status); - bool getLimitedCommerce() { return _limitedCommerce; } - void setLimitedCommerce(bool isLimited) { _limitedCommerce = isLimited; } + bool getLimitedCommerce() { return _limitedCommerce; } + void setLimitedCommerce(bool isLimited) { _limitedCommerce = isLimited; } signals: /**jsdoc - * @function Wallet.walletStatusChanged + * @function WalletScriptingInterface.walletStatusChanged * @returns {Signal} */ void walletStatusChanged(); /**jsdoc - * @function Wallet.walletNotSetup + * @function WalletScriptingInterface.limitedCommerceChanged + * @returns {Signal} + */ + void limitedCommerceChanged(); + + /**jsdoc + * @function WalletScriptingInterface.walletNotSetup * @returns {Signal} */ void walletNotSetup(); /**jsdoc - * @function Wallet.ownershipVerificationSuccess + * @function WalletScriptingInterface.ownershipVerificationSuccess * @param {Uuid} entityID * @returns {Signal} */ void ownershipVerificationSuccess(const QUuid& entityID); /**jsdoc - * @function Wallet.ownershipVerificationFailed + * @function WalletScriptingInterface.ownershipVerificationFailed * @param {Uuid} entityID * @returns {Signal} */ diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 1a1bd00655..f13d25f22c 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -96,7 +96,6 @@ Web3DOverlay::Web3DOverlay() { _webSurface->getSurfaceContext()->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED _webSurface->getSurfaceContext()->setContextProperty("AccountServices", AccountServicesScriptingInterface::getInstance()); _webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get().data()); - _webSurface->getSurfaceContext()->setContextProperty("Wallet", DependencyManager::get().data()); } Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) : @@ -271,8 +270,8 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) { _webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this); _webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface()); - _webSurface->getSurfaceContext()->setContextProperty("Wallet", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance()); + _webSurface->getSurfaceContext()->setContextProperty("WalletScriptingInterface", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("ResourceRequestObserver", DependencyManager::get().data()); // Override min fps for tablet UI, for silky smooth scrolling diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index ece35acce7..2f05b1b337 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -159,8 +159,8 @@ var selectedAvatarEntityGrabbable = false; var selectedAvatarEntityID = null; var grabbedAvatarEntityChangeNotifier = null; -var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml"; -var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace"; +var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/wallet/Wallet.qml"; +var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace" + (WalletScriptingInterface.limitedCommerce ? "?isFree=1" : ""); var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("html/js/marketplacesInject.js"); function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. @@ -285,9 +285,9 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See case 'navigate': var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system") if(message.url.indexOf('app://') === 0) { - if(message.url === 'app://marketplace') { + if (message.url === 'app://marketplace') { tablet.gotoWebScreen(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL); - } else if(message.url === 'app://purchases') { + } else if (message.url === 'app://purchases') { tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH); } diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 58f39ca54c..353145035e 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -11,15 +11,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global getConnectionData */ +/* 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"; - +var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace" + + (WalletScriptingInterface.limitedCommerce ? "?isFree=1" : ""); // BEGIN AVATAR SELECTOR LOGIC var UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6 }; @@ -48,7 +48,6 @@ ExtendedOverlay.prototype.editOverlay = function (properties) { // change displa function color(selected, hovering) { var base = hovering ? HOVER_COLOR : selected ? SELECTED_COLOR : UNSELECTED_COLOR; function scale(component) { - var delta = 0xFF - component; return component; } return { red: scale(base.red), green: scale(base.green), blue: scale(base.blue) }; @@ -105,7 +104,8 @@ ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId // 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) { - var pickedOverlay = Overlays.findRayIntersection(pickRay); // Depends on nearer coverOverlays to extend closer to us than farther ones. + // Depends on nearer coverOverlays to extend closer to us than farther ones. + var pickedOverlay = Overlays.findRayIntersection(pickRay); if (!pickedOverlay.intersects) { if (noHit) { return noHit(); @@ -131,6 +131,7 @@ function addAvatarNode(id) { } var pingPong = true; +var OVERLAY_SCALE = 0.032; function updateOverlays() { var eye = Camera.position; AvatarList.getAvatarIdentifiers().forEach(function (id) { @@ -148,7 +149,8 @@ function updateOverlays() { var target = avatar.position; var distance = Vec3.distance(target, eye); var offset = 0.2; - var diff = Vec3.subtract(target, eye); // get diff between target and eye (a vector pointing to the eye from avatar position) + // 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; @@ -164,7 +166,7 @@ function updateOverlays() { overlay.editOverlay({ color: color(ExtendedOverlay.isSelected(id), overlay.hovering), position: target, - dimensions: 0.032 * distance + dimensions: OVERLAY_SCALE * distance }); }); pingPong = !pingPong; @@ -380,6 +382,23 @@ function onUsernameChanged() { Settings.setValue("wallet/autoLogout", false); Settings.setValue("wallet/savedUsername", ""); } +} + +var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js"); +var METAVERSE_SERVER_URL = Account.metaverseServerURL; +var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page. +function openMarketplace(optionalItemOrUrl) { + // This is a bit of a kluge, but so is the whole file. + // If given a whole path, use it with no cta. + // If given an id, build the appropriate url and use the id as the cta. + // Otherwise, use home and 'marketplace cta'. + // AND... if call onMarketplaceOpen to setupWallet if we need to. + var url = optionalItemOrUrl || MARKETPLACE_URL_INITIAL; + // If optionalItemOrUrl contains the metaverse base, then it's a url, not an item id. + if (optionalItemOrUrl && optionalItemOrUrl.indexOf(METAVERSE_SERVER_URL) === -1) { + url = MARKETPLACE_URL + '/items/' + optionalItemOrUrl; + } + ui.open(url, MARKETPLACES_INJECT_SCRIPT_URL); } // Function Name: fromQml() @@ -387,8 +406,6 @@ function onUsernameChanged() { // 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(). -var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml"; -var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js"); function fromQml(message) { switch (message.method) { case 'passphrasePopup_cancelClicked': @@ -422,10 +439,6 @@ function fromQml(message) { case 'transactionHistory_linkClicked': ui.open(message.marketplaceLink, MARKETPLACES_INJECT_SCRIPT_URL); break; - case 'goToPurchases_fromWalletHome': - case 'goToPurchases': - ui.open(MARKETPLACE_PURCHASES_QML_PATH); - break; case 'goToMarketplaceMainPage': ui.open(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL); break; @@ -450,22 +463,20 @@ function fromQml(message) { removeOverlays(); break; case 'sendAsset_sendPublicly': - if (message.assetName === "") { - deleteSendMoneyParticleEffect(); - sendMoneyRecipient = message.recipient; - var amount = message.amount; - 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); + 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) { @@ -474,6 +485,46 @@ function fromQml(message) { 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_availableUpdatesReceived': + shouldShowDot = message.numUpdates > 0; + ui.messagesWaiting(shouldShowDot && !ui.isOpen); + 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 'http.request': // Handled elsewhere, don't log. break; @@ -482,23 +533,28 @@ function fromQml(message) { } } +var isWired = false; function walletOpened() { Users.usernameFromIDReply.connect(usernameFromIDReply); Controller.mousePressEvent.connect(handleMouseEvent); Controller.mouseMoveEvent.connect(handleMouseMoveEvent); triggerMapping.enable(); triggerPressMapping.enable(); + isWired = true; shouldShowDot = false; ui.messagesWaiting(shouldShowDot); - ui.sendMessage({method: 'setLimitedCommerce', limitedCommerce: Wallet.limitedCommerce}); // HRS FIXME Wallet should be accessible in qml. Why isn't it? } function walletClosed() { off(); } -function notificationDataProcessPage(data) { - return data.data.updates; // HRS FIXME .history; +function notificationDataProcessPageUpdates(data) { + return data.data.updates; +} + +function notificationDataProcessPageHistory(data) { + return data.data.history; } var shouldShowDot = false; @@ -511,7 +567,7 @@ function notificationPollCallbackUpdates(updatesArray) { if (!ui.notificationInitialCallbackMade) { message = updatesArray.length + " of your purchased items " + (updatesArray.length === 1 ? "has an update " : "have updates ") + - "available. Open MARKET to update."; + "available. Open WALLET to update."; ui.notificationDisplayBanner(message); ui.notificationPollCaresAboutSince = true; @@ -519,13 +575,13 @@ function notificationPollCallbackUpdates(updatesArray) { for (var i = 0; i < updatesArray.length; i++) { message = "Update available for \"" + updatesArray[i].base_item_title + "\"." + - "Open MARKET to update."; + "Open WALLET to update."; ui.notificationDisplayBanner(message); } } } } -function notificationPollCallback(historyArray) { +function notificationPollCallbackHistory(historyArray) { if (!ui.isOpen) { var notificationCount = historyArray.length; shouldShowDot = shouldShowDot || notificationCount > 0; @@ -548,7 +604,12 @@ function notificationPollCallback(historyArray) { } } -function isReturnedDataEmpty(data) { +function isReturnedDataEmptyUpdates(data) { + var historyArray = data.data.history; + return historyArray.length === 0; +} + +function isReturnedDataEmptyHistory(data) { var historyArray = data.data.history; return historyArray.length === 0; } @@ -585,6 +646,7 @@ function uninstallMarketplaceItemTester() { var BUTTON_NAME = "ASSETS"; var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml"; +var NOTIFICATION_POLL_TIMEOUT = 300000; var ui; function startup() { ui = new AppUi({ @@ -595,13 +657,20 @@ function startup() { onOpened: walletOpened, onClosed: walletClosed, onMessage: fromQml, - // How are we going to handle two polls when --limitedCommerce is false? - notificationPollEndpoint: "/api/v1/commerce/available_updates?per_page=10", // HRS FIXME "/api/v1/commerce/history?per_page=10", +/* Gotta re-add all this stuff once I get it working + notificationPollEndpoint: ["/api/v1/commerce/available_updates?per_page=10", "/api/v1/commerce/history?per_page=10"], + notificationPollTimeoutMs: [NOTIFICATION_POLL_TIMEOUT, NOTIFICATION_POLL_TIMEOUT], + notificationDataProcessPage: [notificationDataProcessPageUpdates, notificationDataProcessPageHistory], + notificationPollCallback: [notificationPollCallbackUpdates, notificationPollCallbackHistory], + notificationPollStopPaginatingConditionMet: [isReturnedDataEmptyUpdates, isReturnedDataEmptyHistory], + notificationPollCaresAboutSince: [false, true] +*/ + notificationPollEndpoint: "/api/v1/commerce/available_updates?per_page=10", notificationPollTimeoutMs: 300000, - notificationDataProcessPage: notificationDataProcessPage, + notificationDataProcessPage: notificationDataProcessPageUpdates, notificationPollCallback: notificationPollCallbackUpdates, - notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, - notificationPollCaresAboutSince: false // HRS FIXME true + notificationPollStopPaginatingConditionMet: isReturnedDataEmptyUpdates, + notificationPollCaresAboutSince: false }); GlobalServices.myUsernameChanged.connect(onUsernameChanged); installMarketplaceItemTester(); @@ -609,11 +678,13 @@ function startup() { var isUpdateOverlaysWired = false; function off() { - Users.usernameFromIDReply.disconnect(usernameFromIDReply); - Controller.mousePressEvent.disconnect(handleMouseEvent); - Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); - triggerMapping.disable(); - triggerPressMapping.disable(); + if (isWired) { + Users.usernameFromIDReply.disconnect(usernameFromIDReply); + Controller.mousePressEvent.disconnect(handleMouseEvent); + Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); + triggerMapping.disable(); + triggerPressMapping.disable(); + } if (isUpdateOverlaysWired) { Script.update.disconnect(updateOverlays); diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 6425806771..ee1f5ecbec 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -193,7 +193,7 @@ var importingSVOTextOverlay = Overlays.addOverlay("text", { visible: false }); -var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace"; +var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace" + (WalletScriptingInterface.limitedCommerce ? "?isFree=1" : ""); var marketplaceWindow = new OverlayWebWindow({ title: 'Marketplace', source: "about:blank", diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 43fd9ab935..fd228e2596 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -60,7 +60,7 @@ ); // Footer. - var isInitialHiFiPage = location.href === marketplaceBaseURL + "/marketplace?"; + var isInitialHiFiPage = location.href === (marketplaceBaseURL + "/marketplace" + (limitedCommerce ? "?isFree=1" : "?")); $("body").append( '
' + (!isInitialHiFiPage ? '' : '') + @@ -72,7 +72,7 @@ // Footer actions. $("#back-button").on("click", function () { - (document.referrer !== "") ? window.history.back() : window.location = (marketplaceBaseURL + "/marketplace?"); + (document.referrer !== "") ? window.history.back() : window.location = (marketplaceBaseURL + "/marketplace?") + (limitedCommerce ? "isFree=1" : ""); }); $("#all-markets").on("click", function () { EventBridge.emitWebEvent(JSON.stringify({ @@ -93,7 +93,7 @@ window.location = "https://clara.io/library?gameCheck=true&public=true"; }); $('#exploreHifiMarketplace').on('click', function () { - window.location = marketplaceBaseURL + "/marketplace"; + window.location = marketplaceBaseURL + "/marketplace" + (limitedCommerce ? "?isFree=1" : "?"); }); } @@ -196,43 +196,6 @@ } } - function maybeAddPurchasesButton() { - if (userIsLoggedIn) { - // Why isn't this an id?! This really shouldn't be a class on the website, but it is. - var navbarBrandElement = document.getElementsByClassName('navbar-brand')[0]; - var purchasesElement = document.createElement('a'); - var dropDownElement = document.getElementById('user-dropdown'); - - $('#user-dropdown').find('.username')[0].style = "max-width:80px;white-space:nowrap;overflow:hidden;" + - "text-overflow:ellipsis;display:inline-block;position:relative;top:4px;"; - $('#user-dropdown').find('.caret')[0].style = "position:relative;top:-3px;"; - - purchasesElement.id = "purchasesButton"; - purchasesElement.setAttribute('href', "#"); - purchasesElement.innerHTML = ""; - if (messagesWaiting) { - purchasesElement.innerHTML += " "; - } - purchasesElement.innerHTML += "My Purchases"; - // FRONTEND WEBDEV RANT: The username dropdown should REALLY not be programmed to be on the same - // line as the search bar, overlaid on top of the search bar, floated right, and then relatively bumped up using "top:-50px". - $('.navbar-brand').css('margin-right', '10px'); - purchasesElement.style = "height:100%;margin-top:18px;font-weight:bold;float:right;margin-right:" + (dropDownElement.offsetWidth + 30) + - "px;position:relative;z-index:999;"; - navbarBrandElement.parentNode.insertAdjacentElement('beforeend', purchasesElement); - if (limitedCommerce) { - $('#purchasesButton').css('display', 'none'); - } - $('#purchasesButton').on('click', function () { - EventBridge.emitWebEvent(JSON.stringify({ - type: "PURCHASES", - referrerURL: window.location.href, - hasUpdates: messagesWaiting - })); - }); - } - } - function changeDropdownMenu() { var logInOrOutButton = document.createElement('a'); logInOrOutButton.id = "logInOrOutButton"; @@ -409,7 +372,6 @@ // Try this here in case it works (it will if the user just pressed the "back" button, // since that doesn't trigger another AJAX request. injectBuyButtonOnMainPage(); - maybeAddPurchasesButton(); } } @@ -458,7 +420,7 @@ if (isUpdating) { purchaseButton.html('UPDATE FOR FREE'); } else if (availability !== 'available') { - purchaseButton.html('UNAVAILABLE' + (availability ? ('(' + availability + ')') : '')); + purchaseButton.html('UNAVAILABLE ' + (availability ? ('(' + availability + ')') : '')); } else if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) { purchaseButton.html('PURCHASE ' + cost); @@ -476,7 +438,6 @@ type); } }); - maybeAddPurchasesButton(); } } diff --git a/scripts/system/marketplaces/marketplace.js b/scripts/system/marketplaces/marketplace.js index d90695c767..2f749656d3 100644 --- a/scripts/system/marketplaces/marketplace.js +++ b/scripts/system/marketplaces/marketplace.js @@ -15,7 +15,7 @@ Script.include("../libraries/WebTablet.js"); var toolIconUrl = Script.resolvePath("../assets/images/tools/"); -var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace"; +var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace" + (WalletScriptingInterface.limitedCommerce ? "?isFree=1" : ""); var marketplaceWindow = new OverlayWebWindow({ title: "Marketplace", source: "about:blank", diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 5b1d5c8897..9f55bade6a 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -10,7 +10,7 @@ /* global Tablet, Script, HMD, UserActivityLogger, Entities, Account, Wallet, ContextOverlay, Settings, Camera, Vec3, Quat, MyAvatar, Clipboard, Menu, Grid, Uuid, GlobalServices, openLoginWindow, getConnectionData, Overlays, SoundCache, - DesktopPreviewProvider */ + DesktopPreviewProvider, ResourceRequestObserver */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ var selectionDisplay = null; // for gridTool.js to ignore @@ -115,10 +115,10 @@ function setTabletVisibleInSecondaryCamera(visibleInSecondaryCam) { 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 }); + 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() { @@ -137,7 +137,7 @@ function setupWallet(referrer) { } function onMarketplaceOpen(referrer) { - var cta = referrer, match; + var match; if (Account.loggedIn && walletNeedsSetup()) { if (referrer === MARKETPLACE_URL_INITIAL) { setupWallet('marketplace cta'); @@ -165,6 +165,9 @@ function openMarketplace(optionalItemOrUrl) { if (optionalItemOrUrl && optionalItemOrUrl.indexOf(METAVERSE_SERVER_URL) === -1) { url = MARKETPLACE_URL + '/items/' + optionalItemOrUrl; } + if (WalletScriptingInterface.limitedCommerce) { + url += "?isFree=1"; + } ui.open(url, MARKETPLACES_INJECT_SCRIPT_URL); } @@ -218,7 +221,7 @@ function onUsernameChanged() { } function walletNeedsSetup() { - return Wallet.walletStatus === 1; + return WalletScriptingInterface.walletStatus === 1; } function sendCommerceSettings() { @@ -230,290 +233,11 @@ function sendCommerceSettings() { userIsLoggedIn: Account.loggedIn, walletNeedsSetup: walletNeedsSetup(), metaverseServerURL: Account.metaverseServerURL, - messagesWaiting: shouldShowDot, - limitedCommerce: Wallet.limitedCommerce + limitedCommerce: WalletScriptingInterface.limitedCommerce } }); } -// 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) { - var pickedOverlay = Overlays.findRayIntersection(pickRay); // Depends on nearer coverOverlays to extend closer to us than farther ones. - 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; -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; - var diff = Vec3.subtract(target, eye); // get diff between target and eye (a vector pointing to the eye from avatar position) - 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: 0.032 * 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.tablet.sendToQml(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.tablet.sendToQml(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 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 @@ -563,6 +287,7 @@ 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); @@ -585,7 +310,7 @@ function rezEntity(itemHref, itemType, marketplaceItemTesterId) { } var certPos = itemHref.search("certificate_id="); // TODO how do I parse a URL from here? if (certPos >= 0) { - certPos += 15; // length of "certificate_id=" + certPos += CERT_ID_URLPARAM_LENGTH; var certURLEncoded = itemHref.substring(certPos); var certB64Encoded = decodeURIComponent(certURLEncoded); for (var key in wearableTransforms) { @@ -594,7 +319,7 @@ function rezEntity(itemHref, itemType, marketplaceItemTesterId) { if (certificateTransforms) { for (var certID in certificateTransforms) { if (certificateTransforms.hasOwnProperty(certID) && - certID == certB64Encoded) { + certID === certB64Encoded) { var certificateTransform = certificateTransforms[certID]; wearableLocalPosition = certificateTransform.localPosition; wearableLocalRotation = certificateTransform.localRotation; @@ -637,8 +362,10 @@ function rezEntity(itemHref, itemType, marketplaceItemTesterId) { targetDirection = Vec3.multiplyQbyV(targetDirection, Vec3.UNIT_Z); var targetPosition = getPositionToCreateEntity(); - var deltaParallel = HALF_TREE_SCALE; // Distance to move entities parallel to targetDirection. - var deltaPerpendicular = Vec3.ZERO; // Distance to move entities perpendicular to targetDirection. + // 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"]); @@ -666,7 +393,8 @@ function rezEntity(itemHref, itemType, marketplaceItemTesterId) { } if (!Vec3.equal(deltaPosition, Vec3.ZERO)) { - for (var editEntityIndex = 0, numEntities = pastedEntityIDs.length; editEntityIndex < numEntities; editEntityIndex++) { + 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]) @@ -769,79 +497,6 @@ function onWebEventReceived(message) { }); } } -var sendAssetRecipient; -var sendAssetParticleEffectUpdateTimer; -var particleEffectTimestamp; -var sendAssetParticleEffect; -var SEND_ASSET_PARTICLE_TIMER_UPDATE = 250; -var SEND_ASSET_PARTICLE_EMITTING_DURATION = 3000; -var SEND_ASSET_PARTICLE_LIFETIME_SECONDS = 8; -var SEND_ASSET_PARTICLE_PROPERTIES = { - accelerationSpread: { x: 0, y: 0, z: 0 }, - alpha: 1, - alphaFinish: 1, - alphaSpread: 0, - alphaStart: 1, - azimuthFinish: 0, - azimuthStart: -6, - color: { red: 255, green: 222, blue: 255 }, - colorFinish: { red: 255, green: 229, blue: 225 }, - colorSpread: { red: 0, green: 0, blue: 0 }, - colorStart: { red: 243, green: 255, 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_ASSET_PARTICLE_LIFETIME_SECONDS + 1, // Immediately gets updated to be accurate - lifetime: SEND_ASSET_PARTICLE_LIFETIME_SECONDS + 1, - maxParticles: 20, - name: 'asset-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' -}; - -function updateSendAssetParticleEffect() { - var timestampNow = Date.now(); - if ((timestampNow - particleEffectTimestamp) > (SEND_ASSET_PARTICLE_LIFETIME_SECONDS * 1000)) { - deleteSendAssetParticleEffect(); - return; - } else if ((timestampNow - particleEffectTimestamp) > SEND_ASSET_PARTICLE_EMITTING_DURATION) { - Entities.editEntity(sendAssetParticleEffect, { - isEmitting: 0 - }); - } else if (sendAssetParticleEffect) { - var recipientPosition = AvatarList.getAvatar(sendAssetRecipient).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(sendAssetParticleEffect, { - emitAcceleration: accel, - lifespan: life - }); - } -} - -function deleteSendAssetParticleEffect() { - if (sendAssetParticleEffectUpdateTimer) { - Script.clearInterval(sendAssetParticleEffectUpdateTimer); - sendAssetParticleEffectUpdateTimer = null; - } - if (sendAssetParticleEffect) { - sendAssetParticleEffect = Entities.deleteEntity(sendAssetParticleEffect); - } - sendAssetRecipient = null; -} var savedDisablePreviewOption = Menu.isOptionChecked("Disable Preview"); var UI_FADE_TIMEOUT_MS = 150; @@ -868,26 +523,17 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { } switch (message.method) { case 'gotoBank': - ui.close(); + 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 'purchases_openWallet': + break; case 'checkout_openWallet': case 'checkout_setUpClicked': openWallet(); break; - case 'purchases_walletNotSetUp': - wireQmlEventBridge(true); - ui.tablet.sendToQml({ - method: 'updateWalletReferrer', - referrer: "purchases" - }); - openWallet(); - break; case 'checkout_walletNotSetUp': wireQmlEventBridge(true); ui.tablet.sendToQml({ @@ -911,12 +557,6 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { case 'checkout_continueShopping': openMarketplace(); break; - case 'purchases_itemInfoClicked': - var itemId = message.itemId; - if (itemId && itemId !== "") { - openMarketplace(itemId); - } - break; case 'checkout_rezClicked': case 'purchases_rezClicked': case 'tester_rezClicked': @@ -945,7 +585,6 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { } break; case 'header_marketplaceImageClicked': - case 'purchases_backClicked': openMarketplace(message.referrerURL); break; case 'purchases_goToMarketplaceClicked': @@ -975,13 +614,9 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { case 'maybeEnableHmdPreview': maybeEnableHMDPreview(); break; - case 'purchases_openGoTo': + case 'checkout_openGoTo': ui.open("hifi/tablet/TabletAddressDialog.qml"); break; - case 'purchases_itemCertificateClicked': - contextOverlayEntity = ""; - setCertificateInfo(contextOverlayEntity, message.itemCertificateId); - break; case 'inspectionCertificate_closeClicked': ui.close(); break; @@ -1000,85 +635,11 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { method: 'purchases_showMyItems' }); break; - case 'refreshConnections': - // Guard to prevent this code from being executed while sending money -- - // we only want to execute this while sending non-HFC gifts - if (!onWalletScreen) { - print('Refreshing Connections...'); - getConnectionData(false); - } - break; - case 'enable_ChooseRecipientNearbyMode': - // Guard to prevent this code from being executed while sending money -- - // we only want to execute this while sending non-HFC gifts - if (!onWalletScreen) { - if (!isUpdateOverlaysWired) { - Script.update.connect(updateOverlays); - isUpdateOverlaysWired = true; - } - } - break; - case 'disable_ChooseRecipientNearbyMode': - // Guard to prevent this code from being executed while sending money -- - // we only want to execute this while sending non-HFC gifts - if (!onWalletScreen) { - if (isUpdateOverlaysWired) { - Script.update.disconnect(updateOverlays); - isUpdateOverlaysWired = false; - } - removeOverlays(); - } - break; - case 'purchases_availableUpdatesReceived': - shouldShowDot = message.numUpdates > 0; - ui.messagesWaiting(shouldShowDot && !ui.isOpen); - 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 'sendAsset_sendPublicly': - if (message.assetName !== "") { - deleteSendAssetParticleEffect(); - sendAssetRecipient = message.recipient; - var props = SEND_ASSET_PARTICLE_PROPERTIES; - props.parentID = MyAvatar.sessionUUID; - props.position = MyAvatar.position; - props.position.y += 0.2; - if (message.effectImage) { - props.textures = message.effectImage; - } - sendAssetParticleEffect = Entities.addEntity(props, true); - particleEffectTimestamp = Date.now(); - updateSendAssetParticleEffect(); - sendAssetParticleEffectUpdateTimer = Script.setInterval(updateSendAssetParticleEffect, - SEND_ASSET_PARTICLE_TIMER_UPDATE); - } - break; case 'http.request': // Handled elsewhere, don't log. break; - case 'goToPurchases_fromWalletHome': // HRS FIXME What's this about? - break; default: - print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message)); + print('Unrecognized message from Checkout.qml: ' + JSON.stringify(message)); } }; @@ -1163,15 +724,7 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) { } if (onCommerceScreen) { - if (!isWired) { - Users.usernameFromIDReply.connect(usernameFromIDReply); - Controller.mousePressEvent.connect(handleMouseEvent); - Controller.mouseMoveEvent.connect(handleMouseMoveEvent); - triggerMapping.enable(); - triggerPressMapping.enable(); - } - isWired = true; - Wallet.refreshWalletStatus(); + WalletScriptingInterface.refreshWalletStatus(); } else { if (onMarketplaceScreen) { onMarketplaceOpen('marketplace cta'); @@ -1193,44 +746,11 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) { "\nNew screen URL: " + url + "\nCurrent app open status: " + ui.isOpen + "\n"); }; -function notificationDataProcessPage(data) { - return data.data.updates; -} - -var shouldShowDot = false; -function notificationPollCallback(updatesArray) { - shouldShowDot = shouldShowDot || updatesArray.length > 0; - ui.messagesWaiting(shouldShowDot && !ui.isOpen); - - if (updatesArray.length > 0) { - var message; - if (!ui.notificationInitialCallbackMade) { - message = updatesArray.length + " of your purchased items " + - (updatesArray.length === 1 ? "has an update " : "have updates ") + - "available. Open MARKET to update."; - ui.notificationDisplayBanner(message); - - ui.notificationPollCaresAboutSince = true; - } else { - for (var i = 0; i < updatesArray.length; i++) { - message = "Update available for \"" + - updatesArray[i].base_item_title + "\"." + - "Open MARKET to update."; - ui.notificationDisplayBanner(message); - } - } - } -} - -function isReturnedDataEmpty(data) { - var historyArray = data.data.updates; - return historyArray.length === 0; -} - var BUTTON_NAME = "MARKET"; -var MARKETPLACE_URL = METAVERSE_SERVER_URL + "/marketplace"; -var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page. +var MARKETPLACE_URL = METAVERSE_SERVER_URL + "/marketplace" + (WalletScriptingInterface.limitedCommerce ? "?isFree=1" : ""); +// Append "?" if necessary to signal injected script that it's the initial page. +var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + (MARKETPLACE_URL.indexOf("?") > -1 ? "" : "?"); var ui; function startup() { ui = new AppUi({ @@ -1239,50 +759,26 @@ function startup() { inject: MARKETPLACES_INJECT_SCRIPT_URL, home: MARKETPLACE_URL_INITIAL, onScreenChanged: onTabletScreenChanged, - onMessage: onQmlMessageReceived, - // notificationPollEndpoint: "/api/v1/commerce/available_updates?per_page=10", - // notificationPollTimeoutMs: 300000, - // notificationDataProcessPage: notificationDataProcessPage, - // notificationPollCallback: notificationPollCallback, - // notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, - // notificationPollCaresAboutSince: false // Changes to true after first poll + onMessage: onQmlMessageReceived }); ContextOverlay.contextOverlayClicked.connect(openInspectionCertificateQML); Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged); GlobalServices.myUsernameChanged.connect(onUsernameChanged); ui.tablet.webEventReceived.connect(onWebEventReceived); - Wallet.walletStatusChanged.connect(sendCommerceSettings); + WalletScriptingInterface.walletStatusChanged.connect(sendCommerceSettings); Window.messageBoxClosed.connect(onMessageBoxClosed); ResourceRequestObserver.resourceRequestEvent.connect(onResourceRequestEvent); - Wallet.refreshWalletStatus(); + WalletScriptingInterface.refreshWalletStatus(); } -var isWired = false; -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() { maybeEnableHMDPreview(); - deleteSendAssetParticleEffect(); Window.messageBoxClosed.disconnect(onMessageBoxClosed); - Wallet.walletStatusChanged.disconnect(sendCommerceSettings); + WalletScriptingInterface.walletStatusChanged.disconnect(sendCommerceSettings); ui.tablet.webEventReceived.disconnect(onWebEventReceived); GlobalServices.myUsernameChanged.disconnect(onUsernameChanged); Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged); diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 36fe264274..9558b99310 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -634,7 +634,7 @@ Window.notifyEditError = onEditError; Window.notify = onNotify; Tablet.tabletNotification.connect(tabletNotification); - Wallet.walletNotSetup.connect(walletNotSetup); + WalletScriptingInterface.walletNotSetup.connect(walletNotSetup); Messages.subscribe(NOTIFICATIONS_MESSAGE_CHANNEL); Messages.messageReceived.connect(onMessageReceived);