diff --git a/interface/resources/icons/tablet-icons/market-msg-a.svg b/interface/resources/icons/tablet-icons/market-msg-a.svg new file mode 100644 index 0000000000..bf9aa9335f --- /dev/null +++ b/interface/resources/icons/tablet-icons/market-msg-a.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/interface/resources/icons/tablet-icons/market-msg-i.svg b/interface/resources/icons/tablet-icons/market-msg-i.svg new file mode 100644 index 0000000000..bf9aa9335f --- /dev/null +++ b/interface/resources/icons/tablet-icons/market-msg-i.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml index 8a7e809b3d..f6fb28b08a 100644 --- a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml +++ b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml @@ -28,6 +28,7 @@ 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,6 +39,7 @@ 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); @@ -58,6 +60,14 @@ 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: { @@ -109,6 +119,17 @@ Item { anchors.right: securityImage.left; anchors.rightMargin: 6; + Rectangle { + id: messagesWaitingLight; + visible: root.messagesWaiting; + anchors.right: myPurchasesLink.left; + anchors.rightMargin: 4; + anchors.verticalCenter: parent.verticalCenter; + height: 10; + width: height; + radius: height/2; + } + Rectangle { id: myPurchasesLink; anchors.right: myUsernameButton.left; diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 8089818ba6..31c0ba73c0 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -64,6 +64,7 @@ Rectangle { root.activeView = "purchasesMain"; root.installedApps = Commerce.getInstalledApps(); Commerce.inventory(); + Commerce.getAvailableUpdates(); } } else { console.log("ERROR in Purchases.qml: Unknown wallet status: " + walletStatus); @@ -119,6 +120,14 @@ Rectangle { root.pendingInventoryReply = false; } + + onAvailableUpdatesResult: { + if (result.status !== 'success') { + console.log("Failed to get Available Updates", result.data.message); + } else { + sendToScript({method: 'purchases_availableUpdatesReceived', numUpdates: result.data.updates.length }); + } + } } Timer { @@ -273,6 +282,7 @@ Rectangle { root.activeView = "purchasesMain"; root.installedApps = Commerce.getInstalledApps(); Commerce.inventory(); + Commerce.getAvailableUpdates(); break; } } @@ -617,6 +627,7 @@ Rectangle { console.log("Refreshing Purchases..."); root.pendingInventoryReply = true; Commerce.inventory(); + Commerce.getAvailableUpdates(); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 27660b5e9e..7a14ee060f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -39,6 +39,7 @@ Item { root.noMoreHistoryData = false; root.historyRequestPending = true; Commerce.history(root.currentHistoryPage); + Commerce.getAvailableUpdates(); } else { refreshTimer.stop(); } @@ -133,6 +134,14 @@ Item { refreshTimer.start(); } } + + onAvailableUpdatesResult: { + if (result.status !== 'success') { + console.log("Failed to get Available Updates", result.data.message); + } else { + sendToScript({method: 'wallet_availableUpdatesReceived', numUpdates: result.data.updates.length }); + } + } } Connections { diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 2565a998f1..9376ed9823 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -30,6 +30,7 @@ var userIsLoggedIn = false; var walletNeedsSetup = false; var marketplaceBaseURL = "https://highfidelity.com"; + var messagesWaiting = false; function injectCommonCode(isDirectoryPage) { @@ -205,7 +206,11 @@ purchasesElement.id = "purchasesButton"; purchasesElement.setAttribute('href', "#"); - purchasesElement.innerHTML = "My Purchases"; + 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". purchasesElement.style = "height:100%;margin-top:18px;font-weight:bold;float:right;margin-right:" + (dropDownElement.offsetWidth + 30) + @@ -705,6 +710,7 @@ if (marketplaceBaseURL.indexOf('metaverse.') !== -1) { marketplaceBaseURL = marketplaceBaseURL.replace('metaverse.', ''); } + messagesWaiting = parsedJsonMessage.data.messagesWaiting; injectCode(); } } diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index d3620968c7..3d878ef948 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -86,13 +86,24 @@ var selectionDisplay = null; // for gridTool.js to ignore } var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var NORMAL_ICON = "icons/tablet-icons/market-i.svg"; + var NORMAL_ACTIVE = "icons/tablet-icons/market-a.svg"; + var WAITING_ICON = "icons/tablet-icons/market-msg-i.svg"; + var WAITING_ACTIVE = "icons/tablet-icons/market-msg-a.svg"; var marketplaceButton = tablet.addButton({ - icon: "icons/tablet-icons/market-i.svg", - activeIcon: "icons/tablet-icons/market-a.svg", + icon: NORMAL_ICON, + activeIcon: NORMAL_ACTIVE, text: "MARKET", sortOrder: 9 }); + function messagesWaiting(isWaiting) { + button.editProperties({ + icon: (isWaiting ? WAITING_ICON : NORMAL_ICON), + activeIcon: (isWaiting ? WAITING_ACTIVE : NORMAL_ACTIVE) + }); + } + function onCanWriteAssetsChanged() { var message = CAN_WRITE_ASSETS + " " + Entities.canWriteAssets(); tablet.emitScriptEvent(message); @@ -178,6 +189,7 @@ var selectionDisplay = null; // for gridTool.js to ignore } } + var userHasUpdates = false; function sendCommerceSettings() { tablet.emitScriptEvent(JSON.stringify({ type: "marketplaces", @@ -186,7 +198,8 @@ var selectionDisplay = null; // for gridTool.js to ignore commerceMode: Settings.getValue("commerce", true), userIsLoggedIn: Account.loggedIn, walletNeedsSetup: Wallet.walletStatus === 1, - metaverseServerURL: Account.metaverseServerURL + metaverseServerURL: Account.metaverseServerURL, + messagesWaiting: userHasUpdates } })); } @@ -619,6 +632,11 @@ var selectionDisplay = null; // for gridTool.js to ignore case 'sendMoney_sendPublicly': // NOP break; + case 'wallet_availableUpdatesReceived': + case 'purchases_availableUpdatesReceived': + userHasUpdates = message.numUpdates > 0; + messagesWaiting(userHasUpdates); + break; default: print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message)); }