diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 5329099df5..109e357206 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -28,19 +28,31 @@ Rectangle { property string activeView: "initialize"; property bool purchasesReceived: false; property bool balanceReceived: false; + property bool securityImageResultReceived: false; + property bool keyFilePathIfExistsResultReceived: false; property string itemId: ""; property string itemHref: ""; property double balanceAfterPurchase: 0; property bool alreadyOwned: false; property int itemPriceFull: 0; property bool itemIsJson: true; - property bool securityImageResultReceived: false; - property bool keyFilePathIfExistsResultReceived: false; // Style color: hifi.colors.baseGray; Hifi.QmlCommerce { id: commerce; + onLoginStatusResult: { + if (!isLoggedIn && root.activeView !== "needsLogIn") { + root.activeView = "needsLogIn"; + } else if (isLoggedIn) { + root.activeView = "initialize"; + commerce.getSecurityImage(); + commerce.getKeyFilePathIfExists(); + commerce.balance(); + commerce.inventory(); + } + } + onSecurityImageResult: { securityImageResultReceived = true; if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up" @@ -107,6 +119,7 @@ Rectangle { // Item { id: titleBarContainer; + visible: !needsLogIn.visible; // Size width: parent.width; height: 50; @@ -147,6 +160,16 @@ Rectangle { cache: false; source: "image://security/securityImage"; } + Image { + id: securityImageOverlay; + source: "../wallet/images/lockOverlay.png"; + width: securityImage.width * 0.45; + height: securityImage.height * 0.45; + anchors.bottom: securityImage.bottom; + anchors.right: securityImage.right; + mipmap: true; + opacity: 0.9; + } // Separator HifiControlsUit.Separator { @@ -169,10 +192,36 @@ Rectangle { color: hifi.colors.baseGray; Component.onCompleted: { - commerce.getSecurityImage(); - commerce.getKeyFilePathIfExists(); + securityImageResultReceived = false; + purchasesReceived = false; + balanceReceived = false; + keyFilePathIfExistsResultReceived = false; + commerce.getLoginStatus(); } } + + 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(); + } + } + + // // "WALLET NOT SET UP" START @@ -268,13 +317,6 @@ Rectangle { anchors.left: parent.left; anchors.right: parent.right; - onVisibleChanged: { - if (visible) { - commerce.balance(); - commerce.inventory(); - } - } - // // ITEM DESCRIPTION START // @@ -877,7 +919,7 @@ Rectangle { if (root.purchasesReceived && root.balanceReceived) { if (root.balanceAfterPurchase < 0) { if (root.alreadyOwned) { - buyText.text = "You do not have enough HFC to purchase this item again. Go to your Purchases to view the copy you own."; + buyText.text = "You do not have enough HFC to purchase this item again. Go to your Purchases to view the copy you own."; } else { buyText.text = "You do not have enough HFC to purchase this item."; } diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 5060b65e0b..bc843a140d 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -29,12 +29,24 @@ Rectangle { property string referrerURL: ""; property bool securityImageResultReceived: false; property bool keyFilePathIfExistsResultReceived: false; + property bool purchasesReceived: false; property bool punctuationMode: false; // Style color: hifi.colors.baseGray; Hifi.QmlCommerce { id: commerce; + onLoginStatusResult: { + if (!isLoggedIn && root.activeView !== "needsLogIn") { + root.activeView = "needsLogIn"; + } else if (isLoggedIn) { + root.activeView = "initialize"; + commerce.getSecurityImage(); + commerce.getKeyFilePathIfExists(); + commerce.inventory(); + } + } + onSecurityImageResult: { securityImageResultReceived = true; if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up" @@ -58,10 +70,13 @@ Rectangle { } onInventoryResult: { + purchasesReceived = true; if (result.status !== 'success') { console.log("Failed to get purchases", result.message); } else { + purchasesModel.clear(); purchasesModel.append(result.data.assets); + filteredPurchasesModel.clear(); filteredPurchasesModel.append(result.data.assets); } } @@ -76,6 +91,7 @@ Rectangle { // Item { id: titleBarContainer; + visible: !needsLogIn.visible; // Size height: 50; // Anchors @@ -116,6 +132,16 @@ Rectangle { cache: false; source: "image://security/securityImage"; } + Image { + id: securityImageOverlay; + source: "../wallet/images/lockOverlay.png"; + width: securityImage.width * 0.45; + height: securityImage.height * 0.45; + anchors.bottom: securityImage.bottom; + anchors.right: securityImage.right; + mipmap: true; + opacity: 0.9; + } // Separator HifiControlsUit.Separator { @@ -138,8 +164,31 @@ Rectangle { color: hifi.colors.baseGray; Component.onCompleted: { - commerce.getSecurityImage(); - commerce.getKeyFilePathIfExists(); + securityImageResultReceived = false; + purchasesReceived = false; + keyFilePathIfExistsResultReceived = false; + commerce.getLoginStatus(); + } + } + + 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(); } } @@ -240,14 +289,7 @@ Rectangle { anchors.top: titleBarContainer.bottom; anchors.topMargin: 8; anchors.bottom: actionButtonsContainer.top; - anchors.bottomMargin: 8; - - onVisibleChanged: { - if (visible) { - commerce.balance(); - commerce.inventory(); - } - } + anchors.bottomMargin: 8; // // FILTER BAR START @@ -258,7 +300,9 @@ Rectangle { height: 40; // Anchors anchors.left: parent.left; + anchors.leftMargin: 8; anchors.right: parent.right; + anchors.rightMargin: 8; anchors.top: parent.top; anchors.topMargin: 4; @@ -304,6 +348,7 @@ Rectangle { ListView { id: purchasesContentsList; + visible: purchasesModel.count !== 0; clip: true; model: filteredPurchasesModel; // Anchors @@ -329,6 +374,52 @@ Rectangle { } } } + + Item { + id: noPurchasesAlertContainer; + visible: !purchasesContentsList.visible && root.purchasesReceived; + 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 purchased anything yet!

Get an item from Marketplace to add it to your Purchases."; + // 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.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + } + + // "Set Up" 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 diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml index 2252cbfb59..47b3f6daf6 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Help.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Help.qml @@ -31,6 +31,7 @@ Item { // "Unavailable" RalewayRegular { + id: helpText; text: "Help me!"; // Anchors anchors.fill: parent; @@ -43,6 +44,19 @@ Item { horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter; } + HifiControlsUit.Button { + color: hifi.buttons.black; + colorScheme: hifi.colorSchemes.dark; + anchors.bottom: helpText.bottom; + anchors.horizontalCenter: parent.horizontalCenter; + height: 50; + width: 250; + text: "Testing: Reset Wallet!"; + onClicked: { + commerce.reset(); + sendSignalToWallet({method: 'walletReset'}); + } + } // // FUNCTION DEFINITIONS START diff --git a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml new file mode 100644 index 0000000000..1e95aaa297 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml @@ -0,0 +1,188 @@ +// +// 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 QtQuick.Controls 1.4 +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit +import "../../../controls" as HifiControls + +// references XXX from root context + +Item { + HifiConstants { id: hifi; } + + id: root; + Hifi.QmlCommerce { + id: 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: "HIFI COMMERCE - LOGIN"; + // 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 buy/sell items on the Marketplace, or to use your Wallet, 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: 'needsLogIn_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: 'needsLogIn_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('Unrecognized message from wallet.js:', JSON.stringify(message)); + } + } + signal sendSignalToWallet(var msg); + // + // FUNCTION DEFINITIONS END + // +} diff --git a/interface/resources/qml/hifi/commerce/wallet/NotSetUp.qml b/interface/resources/qml/hifi/commerce/wallet/NotSetUp.qml index 3efb592ba1..42b8526a8a 100644 --- a/interface/resources/qml/hifi/commerce/wallet/NotSetUp.qml +++ b/interface/resources/qml/hifi/commerce/wallet/NotSetUp.qml @@ -80,7 +80,7 @@ Item { // "Set Up" button HifiControlsUit.Button { - color: hifi.buttons.black; + color: hifi.buttons.blue; colorScheme: hifi.colorSchemes.dark; anchors.bottom: parent.bottom; anchors.bottomMargin: 150; diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index 89ef851b06..39d07315d5 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -45,9 +45,16 @@ Item { } } + // 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.focus = true; + sendMessageToLightbox({method: 'disableHmdPreview'}); + } else { + sendMessageToLightbox({method: 'maybeEnableHmdPreview'}); } } @@ -66,11 +73,25 @@ Item { echoMode: TextInput.Password; placeholderText: "passphrase"; - onVisibleChanged: { - if (visible) { - text = ""; + onFocusChanged: { + if (focus) { + sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'}); + } else if (!passphraseFieldAgain.focus) { + sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'}); } } + + MouseArea { + anchors.fill: parent; + onClicked: { + parent.focus = true; + sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'}); + } + } + + onAccepted: { + passphraseFieldAgain.focus = true; + } } HifiControlsUit.TextField { id: passphraseFieldAgain; @@ -82,11 +103,25 @@ Item { echoMode: TextInput.Password; placeholderText: "re-enter passphrase"; - onVisibleChanged: { - if (visible) { - text = ""; + onFocusChanged: { + if (focus) { + sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'}); + } else if (!passphraseField.focus) { + sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'}); } } + + MouseArea { + anchors.fill: parent; + onClicked: { + parent.focus = true; + sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'}); + } + } + + onAccepted: { + focus = false; + } } // Security Image @@ -111,9 +146,19 @@ Item { commerce.getSecurityImage(); } } - // "Security picture" text below pic + Image { + id: topSecurityImageOverlay; + source: "images/lockOverlay.png"; + width: passphrasePageSecurityImage.width * 0.45; + height: passphrasePageSecurityImage.height * 0.45; + anchors.bottom: passphrasePageSecurityImage.bottom; + anchors.right: passphrasePageSecurityImage.right; + mipmap: true; + opacity: 0.9; + } + // "Security image" text below pic RalewayRegular { - text: "security picture"; + text: "security image"; // Text size size: 12; // Anchors @@ -228,5 +273,11 @@ Item { errorText.text = text; } + function clearPassphraseFields() { + passphraseField.text = ""; + passphraseFieldAgain.text = ""; + setErrorText(""); + } + signal sendMessageToLightbox(var msg); } diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelectionLightbox.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelectionLightbox.qml index 862d1894db..608cb229b0 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelectionLightbox.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelectionLightbox.qml @@ -27,29 +27,6 @@ Rectangle { // Style color: hifi.colors.baseGray; - onVisibleChanged: { - if (visible) { - root.resetSubmitButton(); - } - } - - Connections { - target: passphraseSelection; - onSendMessageToLightbox: { - if (msg.method === 'statusResult') { - if (msg.status) { - // Success submitting new passphrase - root.resetSubmitButton(); - root.visible = false; - } else { - // Error submitting new passphrase - root.resetSubmitButton(); - passphraseSelection.setErrorText("Backend error"); - } - } - } - } - // // SECURE PASSPHRASE SELECTION START // @@ -113,6 +90,24 @@ Rectangle { 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 + root.resetSubmitButton(); + root.visible = false; + } else { + // Error submitting new passphrase + root.resetSubmitButton(); + passphraseSelection.setErrorText("Backend error"); + } + } else { + sendSignalToWallet(msg); + } + } + } } // Navigation Bar @@ -168,8 +163,14 @@ Rectangle { // 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/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index d0a96db3f2..b5d52d57e2 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -13,6 +13,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 +import QtGraphicalEffects 1.0 import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit @@ -35,8 +36,6 @@ Item { topSecurityImage.source = path; changeSecurityImageImage.source = ""; changeSecurityImageImage.source = path; - changePassphraseImage.source = ""; - changePassphraseImage.source = path; } } @@ -92,9 +91,19 @@ Item { source: "image://security/securityImage"; cache: false; } - // "Security picture" text below pic + Image { + id: topSecurityImageMask; + source: "images/lockOverlay.png"; + width: topSecurityImage.width * 0.45; + height: topSecurityImage.height * 0.45; + anchors.bottom: topSecurityImage.bottom; + anchors.right: topSecurityImage.right; + mipmap: true; + opacity: 0.9; + } + // "Security image" text below pic RalewayRegular { - text: "security picture"; + text: "security image"; // Text size size: 12; // Anchors @@ -148,10 +157,16 @@ Item { anchors.left: parent.left; height: parent.height; width: height; - source: "image://security/securityImage"; + source: "images/lockOverlay.png"; fillMode: Image.PreserveAspectFit; mipmap: true; cache: false; + visible: false; + } + ColorOverlay { + anchors.fill: changePassphraseImage; + source: changePassphraseImage; + color: "white" } // "Change Passphrase" button HifiControlsUit.Button { diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageModel.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageModel.qml index b49f16857b..7b1434aa3c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageModel.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageModel.qml @@ -16,27 +16,27 @@ import QtQuick 2.5 ListModel { id: root; ListElement{ - sourcePath: "images/01cat.jpg" + sourcePath: "images/01.jpg" securityImageEnumValue: 1; } ListElement{ - sourcePath: "images/02car.jpg" + sourcePath: "images/02.jpg" securityImageEnumValue: 2; } ListElement{ - sourcePath: "images/03dog.jpg" + sourcePath: "images/03.jpg" securityImageEnumValue: 3; } ListElement{ - sourcePath: "images/04stars.jpg" + sourcePath: "images/04.jpg" securityImageEnumValue: 4; } ListElement{ - sourcePath: "images/05plane.jpg" + sourcePath: "images/05.jpg" securityImageEnumValue: 5; } ListElement{ - sourcePath: "images/06gingerbread.jpg" + sourcePath: "images/06.jpg" securityImageEnumValue: 6; } diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml index 7ab52b7551..5f5a3e8247 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml @@ -24,16 +24,16 @@ Item { HifiConstants { id: hifi; } id: root; - - Hifi.QmlCommerce { - id: commerce; - onSecurityImageResult: { - } - } - + + // This will cause a bug -- if you bring up security image 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) { - commerce.getSecurityImage(); + sendSignalToWallet({method: 'disableHmdPreview'}); + } else { + sendSignalToWallet({method: 'maybeEnableHmdPreview'}); } } @@ -83,7 +83,7 @@ Item { // // FUNCTION DEFINITIONS START // - signal sendToScript(var message); + signal sendSignalToWallet(var msg); function getImagePathFromImageID(imageID) { return (imageID ? gridModel.getImagePathFromImageID(imageID) : ""); diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml index d4b0b82ed3..ff7156dd6c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml @@ -28,12 +28,6 @@ Rectangle { // Style color: hifi.colors.baseGray; - onVisibleChanged: { - if (visible) { - root.resetSubmitButton(); - } - } - Hifi.QmlCommerce { id: commerce; @@ -116,6 +110,12 @@ Rectangle { anchors.right: parent.right; anchors.rightMargin: 16; height: 280; + + Connections { + onSendSignalToWallet: { + sendSignalToWallet(msg); + } + } } // Text below security images @@ -193,6 +193,8 @@ Rectangle { // SECURITY IMAGE SELECTION END // + signal sendSignalToWallet(var msg); + function resetSubmitButton() { securityImageSubmitButton.enabled = true; securityImageSubmitButton.text = "Submit"; diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index ae2606c0f6..53838fa58c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -28,12 +28,23 @@ Rectangle { property string activeView: "initialize"; property bool securityImageResultReceived: false; property bool keyFilePathIfExistsResultReceived: false; + property bool keyboardRaised: false; // Style color: hifi.colors.baseGray; Hifi.QmlCommerce { id: commerce; + onLoginStatusResult: { + if (!isLoggedIn && root.activeView !== "needsLogIn") { + root.activeView = "needsLogIn"; + } else if (isLoggedIn) { + root.activeView = "initialize"; + commerce.getSecurityImage(); + commerce.getKeyFilePathIfExists(); + } + } + onSecurityImageResult: { securityImageResultReceived = true; if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up" @@ -57,27 +68,6 @@ Rectangle { id: securityImageModel; } - Connections { - target: walletSetupLightbox; - onSendSignalToWallet: { - if (msg.method === 'walletSetup_cancelClicked') { - walletSetupLightbox.visible = false; - } else if (msg.method === 'walletSetup_finished') { - root.activeView = "walletHome"; - } else { - sendToScript(msg); - } - } - } - Connections { - target: notSetUp; - onSendSignalToWallet: { - if (msg.method === 'setUpClicked') { - walletSetupLightbox.visible = true; - } - } - } - Rectangle { id: walletSetupLightboxContainer; visible: walletSetupLightbox.visible || passphraseSelectionLightbox.visible || securityImageSelectionLightbox.visible; @@ -89,26 +79,60 @@ Rectangle { WalletSetupLightbox { id: walletSetupLightbox; visible: false; - z: 999; + z: 998; anchors.centerIn: walletSetupLightboxContainer; width: walletSetupLightboxContainer.width - 50; height: walletSetupLightboxContainer.height - 50; + + Connections { + onSendSignalToWallet: { + if (msg.method === 'walletSetup_cancelClicked') { + walletSetupLightbox.visible = false; + } else if (msg.method === 'walletSetup_finished') { + root.activeView = "walletHome"; + } else if (msg.method === 'walletSetup_raiseKeyboard') { + root.keyboardRaised = true; + } else if (msg.method === 'walletSetup_lowerKeyboard') { + root.keyboardRaised = false; + } else { + sendToScript(msg); + } + } + } } PassphraseSelectionLightbox { id: passphraseSelectionLightbox; visible: false; - z: 999; + z: 998; anchors.centerIn: walletSetupLightboxContainer; width: walletSetupLightboxContainer.width - 50; height: walletSetupLightboxContainer.height - 50; + + Connections { + onSendSignalToWallet: { + if (msg.method === 'walletSetup_raiseKeyboard') { + root.keyboardRaised = true; + } else if (msg.method === 'walletSetup_lowerKeyboard') { + root.keyboardRaised = false; + } else { + sendToScript(msg); + } + } + } } SecurityImageSelectionLightbox { id: securityImageSelectionLightbox; visible: false; - z: 999; + z: 998; anchors.centerIn: walletSetupLightboxContainer; width: walletSetupLightboxContainer.width - 50; height: walletSetupLightboxContainer.height - 50; + + Connections { + onSendSignalToWallet: { + sendToScript(msg); + } + } } @@ -117,6 +141,7 @@ Rectangle { // Item { id: titleBarContainer; + visible: !needsLogIn.visible; // Size width: parent.width; height: 50; @@ -168,8 +193,28 @@ Rectangle { color: hifi.colors.baseGray; Component.onCompleted: { - commerce.getSecurityImage(); - commerce.getKeyFilePathIfExists(); + commerce.getLoginStatus(); + } + } + + 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(); } } @@ -180,6 +225,14 @@ Rectangle { anchors.bottom: tabButtonsContainer.top; anchors.left: parent.left; anchors.right: parent.right; + + Connections { + onSendSignalToWallet: { + if (msg.method === 'setUpClicked') { + walletSetupLightbox.visible = true; + } + } + } } WalletHome { @@ -219,14 +272,15 @@ Rectangle { anchors.leftMargin: 16; anchors.right: parent.right; anchors.rightMargin: 16; - } - Connections { - target: security; - onSendSignalToWallet: { - if (msg.method === 'walletSecurity_changePassphrase') { - passphraseSelectionLightbox.visible = true; - } else if (msg.method === 'walletSecurity_changeSecurityImage') { - securityImageSelectionLightbox.visible = true; + + Connections { + onSendSignalToWallet: { + if (msg.method === 'walletSecurity_changePassphrase') { + passphraseSelectionLightbox.visible = true; + passphraseSelectionLightbox.clearPassphraseFields(); + } else if (msg.method === 'walletSecurity_changeSecurityImage') { + securityImageSelectionLightbox.visible = true; + } } } } @@ -242,6 +296,14 @@ Rectangle { anchors.leftMargin: 16; anchors.right: parent.right; anchors.rightMargin: 16; + + Connections { + onSendSignalToWallet: { + if (msg.method === 'walletReset') { + sendToScript(msg); + } + } + } } @@ -254,6 +316,7 @@ Rectangle { // Item { id: tabButtonsContainer; + visible: !needsLogIn.visible; property int numTabs: 5; // Size width: root.width; @@ -457,6 +520,46 @@ Rectangle { // TAB BUTTONS END // + Item { + id: keyboardContainer; + z: 999; + visible: keyboard.raised; + property bool punctuationMode: false; + anchors { + bottom: parent.bottom; + left: parent.left; + right: parent.right; + } + + Image { + id: lowerKeyboardButton; + source: "images/lowerKeyboard.png"; + anchors.horizontalCenter: parent.horizontalCenter; + anchors.bottom: keyboard.top; + height: 30; + width: 120; + + MouseArea { + anchors.fill: parent; + + onClicked: { + root.keyboardRaised = false; + } + } + } + + HifiControlsUit.Keyboard { + id: keyboard; + raised: HMD.mounted && root.keyboardRaised; + numeric: parent.punctuationMode; + anchors { + bottom: parent.bottom; + left: parent.left; + right: parent.right; + } + } + } + // // FUNCTION DEFINITIONS START // diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 33faacd0ab..b55f7f800a 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -24,6 +24,7 @@ Item { HifiConstants { id: hifi; } id: root; + property bool historyReceived: false; Hifi.QmlCommerce { id: commerce; @@ -41,9 +42,10 @@ Item { } onHistoryResult : { + historyReceived = true; if (result.status === 'success') { - var txt = result.data.history.map(function (h) { return h.text; }).join("
"); - transactionHistoryText.text = txt; + transactionHistoryModel.clear(); + transactionHistoryModel.append(result.data.history); } } } @@ -111,6 +113,7 @@ Item { onVisibleChanged: { if (visible) { + historyReceived = false; commerce.balance(); commerce.history(); } @@ -182,9 +185,19 @@ Item { cache: false; source: "image://security/securityImage"; } - // "Security picture" text below pic + Image { + id: securityImageOverlay; + source: "images/lockOverlay.png"; + width: securityImage.width * 0.45; + height: securityImage.height * 0.45; + anchors.bottom: securityImage.bottom; + anchors.right: securityImage.right; + mipmap: true; + opacity: 0.9; + } + // "Security image" text below pic RalewayRegular { - text: "security picture"; + text: "security image"; // Text size size: 12; // Anchors @@ -208,8 +221,7 @@ Item { anchors.topMargin: 8; anchors.left: parent.left; anchors.right: parent.right; - anchors.bottom: homeMessage.visible ? homeMessage.top : root.bottom; - anchors.bottomMargin: 10; + anchors.bottom: parent.bottom; RalewayRegular { id: recentActivityText; @@ -224,111 +236,66 @@ Item { // Style color: hifi.colors.faintGray; } - + ListModel { + id: transactionHistoryModel; + } Rectangle { - id: transactionHistory; anchors.top: recentActivityText.bottom; anchors.topMargin: 4; - anchors.bottom: toggleFullHistoryButton.top; - anchors.bottomMargin: 8; - anchors.left: parent.left; - anchors.right: parent.right; - - // some placeholder stuff - TextArea { - id: transactionHistoryText; - text: "
history unavailable
"; - textFormat: TextEdit.AutoText; - font.pointSize: 10; - anchors.fill: parent; - horizontalAlignment: Text.AlignLeft; - verticalAlignment: Text.AlignTop; - } - } - - HifiControlsUit.Button { - id: toggleFullHistoryButton; - color: hifi.buttons.black; - colorScheme: hifi.colorSchemes.dark; anchors.bottom: parent.bottom; - anchors.right: parent.right; - width: 250; - height: 40; - text: homeMessage.visible ? "See Full Transaction History" : "Collapse Transaction History"; - onClicked: { - if (homeMessage.visible) { - homeMessage.visible = false; - } else { - homeMessage.visible = true; - } - } - } - } - - // Item for "messages" - like "Welcome" - Item { - id: homeMessage; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: childrenRect.height; - - RalewayRegular { - id: messageText; - text: "Welcome! Let's get you some spending money.

" + - "Now that your account is all set up, click the button below to request your starter money. " + - "A robot will promptly review your request and put money into your account."; - // Text size - size: 16; - // Anchors - anchors.top: parent.top; anchors.left: parent.left; anchors.right: parent.right; - height: 130; - // Style - color: hifi.colors.faintGray; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } + color: "white"; - Item { - id: homeMessageButtons; - anchors.top: messageText.bottom; - anchors.topMargin: 4; - anchors.left: parent.left; - anchors.right: parent.right; - height: 40; - HifiControlsUit.Button { - id: noThanksButton; - color: hifi.buttons.black; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: parent.left; - width: 100; - text: "No Thanks" - onClicked: { - messageText.text = "Okay...weird. Who doesn't like free money? If you change your mind, too bad. Sorry." - homeMessageButtons.visible = false; + ListView { + id: transactionHistory; + anchors.centerIn: parent; + width: parent.width - 12; + height: parent.height - 12; + visible: transactionHistoryModel.count !== 0; + clip: true; + model: transactionHistoryModel; + delegate: Item { + width: parent.width; + height: transactionText.height + 30; + RalewayRegular { + id: transactionText; + text: model.text; + // Style + size: 18; + width: parent.width; + height: paintedHeight; + anchors.verticalCenter: parent.verticalCenter; + color: "black"; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignVCenter; + } + + HifiControlsUit.Separator { + anchors.left: parent.left; + anchors.right: parent.right; + anchors.bottom: parent.bottom; + } + } + onAtYEndChanged: { + if (transactionHistory.atYEnd) { + console.log("User scrolled to the bottom of 'Recent Activity'."); + // Grab next page of results and append to model + } } } - HifiControlsUit.Button { - id: freeMoneyButton; - color: hifi.buttons.black; - colorScheme: hifi.colorSchemes.dark; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.right: parent.right; - width: 210; - text: "Free Money Please" - onClicked: { - messageText.text = "Go, MoneyRobots, Go!" - homeMessageButtons.visible = false; - } + + // This should never be visible (since you immediately get 100 HFC) + RalewayRegular { + id: emptyTransationHistory; + size: 24; + visible: !transactionHistory.visible && root.historyReceived; + text: "Recent Activity Unavailable"; + anchors.fill: parent; + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml index bbeb77f6fa..4470ec7a75 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml @@ -24,21 +24,13 @@ Rectangle { HifiConstants { id: hifi; } id: root; - property string lastPage: "login"; + property string lastPage: "initialize"; // Style color: hifi.colors.baseGray; Hifi.QmlCommerce { id: commerce; - onLoginStatusResult: { - if (isLoggedIn) { - securityImageContainer.visible = true; - } else { - loginPageContainer.visible = true; - } - } - onSecurityImageResult: { if (!exists && root.lastPage === "securityImage") { // ERROR! Invalid security image. @@ -61,151 +53,14 @@ Rectangle { } } - // - // LOGIN PAGE START - // - Item { - id: loginPageContainer; - visible: false; - // Anchors - anchors.fill: parent; - - Component.onCompleted: { - commerce.getLoginStatus(); - } - - Item { - id: loginTitle; - // Size - width: parent.width; - height: 50; - // Anchors - anchors.left: parent.left; - anchors.top: parent.top; - - // Title Bar text - RalewaySemiBold { - text: "WALLET SETUP - LOGIN"; - // 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.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: 50; - // Style - color: hifi.colors.faintGray; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - - // Text below helper text - RalewaySemiBold { - id: loginDetailText; - text: "To set up your wallet, 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.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - - // "Cancel" button - HifiControlsUit.Button { - color: hifi.buttons.black; - colorScheme: hifi.colorSchemes.dark; - anchors.top: loginDetailText.bottom; - anchors.topMargin: 25; - anchors.left: parent.left; - anchors.leftMargin: 16; - width: 150; - height: 50; - text: "Log In" - onClicked: { - sendSignalToWallet({method: 'walletSetup_loginClicked'}); - } - } - - // Navigation Bar - Item { - // Size - width: parent.width; - height: 100; - // Anchors: - anchors.left: parent.left; - anchors.bottom: parent.bottom; - - // "Cancel" button - HifiControlsUit.Button { - 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: 100; - text: "Cancel" - onClicked: { - sendSignalToWallet({method: 'walletSetup_cancelClicked'}); - } - } - } - } - // - // LOGIN PAGE END - // - // // SECURITY IMAGE SELECTION START // Item { id: securityImageContainer; - visible: false; // Anchors anchors.fill: parent; - onVisibleChanged: { - if (visible) { - commerce.getSecurityImage(); - } - } - Item { id: securityImageTitle; // Size @@ -262,6 +117,12 @@ Rectangle { anchors.right: parent.right; anchors.rightMargin: 16; height: 280; + + Connections { + onSendSignalToWallet: { + sendSignalToWallet(msg); + } + } } // Text below security images @@ -329,6 +190,7 @@ Rectangle { commerce.chooseSecurityImage(securityImagePath); securityImageContainer.visible = false; choosePassphraseContainer.visible = true; + passphraseSelection.clearPassphraseFields(); } } } @@ -407,6 +269,15 @@ Rectangle { anchors.left: parent.left; anchors.right: parent.right; anchors.bottom: passphraseNavBar.top; + + Connections { + onSendMessageToLightbox: { + if (msg.method === 'statusResult') { + } else { + sendSignalToWallet(msg); + } + } + } } // Navigation Bar diff --git a/interface/resources/qml/hifi/commerce/wallet/images/01cat.jpg b/interface/resources/qml/hifi/commerce/wallet/images/01.jpg similarity index 100% rename from interface/resources/qml/hifi/commerce/wallet/images/01cat.jpg rename to interface/resources/qml/hifi/commerce/wallet/images/01.jpg diff --git a/interface/resources/qml/hifi/commerce/wallet/images/02.jpg b/interface/resources/qml/hifi/commerce/wallet/images/02.jpg new file mode 100644 index 0000000000..e210d0dc82 Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/02.jpg differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/02car.jpg b/interface/resources/qml/hifi/commerce/wallet/images/02car.jpg deleted file mode 100644 index 5dd8091e57..0000000000 Binary files a/interface/resources/qml/hifi/commerce/wallet/images/02car.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/03dog.jpg b/interface/resources/qml/hifi/commerce/wallet/images/03.jpg similarity index 100% rename from interface/resources/qml/hifi/commerce/wallet/images/03dog.jpg rename to interface/resources/qml/hifi/commerce/wallet/images/03.jpg diff --git a/interface/resources/qml/hifi/commerce/wallet/images/04.jpg b/interface/resources/qml/hifi/commerce/wallet/images/04.jpg new file mode 100644 index 0000000000..e2358b4dbc Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/04.jpg differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/04stars.jpg b/interface/resources/qml/hifi/commerce/wallet/images/04stars.jpg deleted file mode 100644 index 8f2bf62f83..0000000000 Binary files a/interface/resources/qml/hifi/commerce/wallet/images/04stars.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/05.jpg b/interface/resources/qml/hifi/commerce/wallet/images/05.jpg new file mode 100644 index 0000000000..796acac167 Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/05.jpg differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/05plane.jpg b/interface/resources/qml/hifi/commerce/wallet/images/05plane.jpg deleted file mode 100644 index 6504459d8b..0000000000 Binary files a/interface/resources/qml/hifi/commerce/wallet/images/05plane.jpg and /dev/null differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/06gingerbread.jpg b/interface/resources/qml/hifi/commerce/wallet/images/06.jpg similarity index 100% rename from interface/resources/qml/hifi/commerce/wallet/images/06gingerbread.jpg rename to interface/resources/qml/hifi/commerce/wallet/images/06.jpg diff --git a/interface/resources/qml/hifi/commerce/wallet/images/lockOverlay.png b/interface/resources/qml/hifi/commerce/wallet/images/lockOverlay.png new file mode 100644 index 0000000000..09b2011e58 Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/lockOverlay.png differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/lowerKeyboard.png b/interface/resources/qml/hifi/commerce/wallet/images/lowerKeyboard.png new file mode 100644 index 0000000000..9fc88262db Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/lowerKeyboard.png differ diff --git a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml index 3d4231ced7..bbf2d019fb 100644 --- a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml +++ b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml @@ -4,6 +4,7 @@ import QtQuick.Controls 1.4 StateImage { id: button + property string captionColorOverride: "" property bool buttonEnabled: true property bool isActive: false property bool isEntered: false @@ -97,7 +98,7 @@ StateImage { Text { id: caption - color: button.isActive ? "#000000" : "#ffffff" + color: captionColorOverride !== "" ? captionColorOverride: (button.isActive ? "#000000" : "#ffffff") text: button.isActive ? (button.isEntered ? button.activeHoverText : button.activeText) : (button.isEntered ? button.hoverText : button.text) font.bold: false font.pixelSize: 9 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 901b300277..458026c6a8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -166,6 +166,7 @@ #include "scripting/WindowScriptingInterface.h" #include "scripting/ControllerScriptingInterface.h" #include "scripting/RatesScriptingInterface.h" +#include "scripting/SelectionScriptingInterface.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) #include "SpeechRecognizer.h" #endif @@ -183,7 +184,6 @@ #include "ui/UpdateDialog.h" #include "ui/overlays/Overlays.h" #include "ui/DomainConnectionModel.h" -#include "ui/ImageProvider.h" #include "Util.h" #include "InterfaceParentFinder.h" #include "ui/OctreeStatsProvider.h" @@ -264,7 +264,7 @@ private: switch ((int)event->type()) { case ApplicationEvent::Render: render(); - // Ensure we never back up the render events. Each render should be triggered only in response + // Ensure we never back up the render events. Each render should be triggered only in response // to the NEXT render event after the last render occured QCoreApplication::removePostedEvents(this, ApplicationEvent::Render); return true; @@ -676,6 +676,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -2246,8 +2247,6 @@ void Application::initializeUi() { qApp->quit(); }); - // register the pixmap image provider (used only for security image, for now) - engine->addImageProvider(ImageProvider::PROVIDER_NAME, new ImageProvider()); setupPreferences(); @@ -2321,6 +2320,7 @@ void Application::initializeUi() { surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor()); surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); + surfaceContext->setContextProperty("Selection", DependencyManager::get().data()); surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { @@ -5187,7 +5187,7 @@ void Application::update(float deltaTime) { } } else { // update the rendering without any simulation - getEntities()->update(false); + getEntities()->update(false); } // AvatarManager update @@ -5661,17 +5661,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se } renderArgs->_debugFlags = renderDebugFlags; //ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, transaction); - - RenderArgs::OutlineFlags renderOutlineFlags = RenderArgs::RENDER_OUTLINE_NONE; - auto contextOverlayInterface = DependencyManager::get(); - if (contextOverlayInterface->getEnabled()) { - if (DependencyManager::get()->getIsInMarketplaceInspectionMode()) { - renderOutlineFlags = RenderArgs::RENDER_OUTLINE_MARKETPLACE_MODE; - } else { - renderOutlineFlags = RenderArgs::RENDER_OUTLINE_WIREFRAMES; - } - } - renderArgs->_outlineFlags = renderOutlineFlags; } } @@ -6138,6 +6127,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri auto entityScriptServerLog = DependencyManager::get(); scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data()); scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance()); + scriptEngine->registerGlobalObject("Selection", DependencyManager::get().data()); scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get().data()); qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue); diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index dddfae6455..08eb79017f 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -111,3 +111,10 @@ void Ledger::inventory(const QStringList& keys) { void Ledger::history(const QStringList& keys) { keysQuery("history", "historySuccess", "historyFailure"); } + +// The api/failResponse is called just for the side effect of logging. +void Ledger::resetSuccess(QNetworkReply& reply) { apiResponse("reset", reply); } +void Ledger::resetFailure(QNetworkReply& reply) { failResponse("reset", reply); } +void Ledger::reset() { + send("reset_user_hfc_account", "resetSuccess", "resetFailure", QNetworkAccessManager::PutOperation, QJsonObject()); +} \ No newline at end of file diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index 7d3fdef0c0..55b648aa4c 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -29,6 +29,7 @@ public: void balance(const QStringList& keys); void inventory(const QStringList& keys); void history(const QStringList& keys); + void reset(); signals: void buyResult(QJsonObject result); @@ -48,6 +49,8 @@ public slots: void inventoryFailure(QNetworkReply& reply); void historySuccess(QNetworkReply& reply); void historyFailure(QNetworkReply& reply); + void resetSuccess(QNetworkReply& reply); + void resetFailure(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 bf6bcc221c..655f228672 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -85,3 +85,10 @@ void QmlCommerce::getKeyFilePathIfExists() { auto wallet = DependencyManager::get(); wallet->sendKeyFilePathIfExists(); } + +void QmlCommerce::reset() { + auto ledger = DependencyManager::get(); + auto wallet = DependencyManager::get(); + ledger->reset(); + wallet->reset(); +} \ No newline at end of file diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index fd913ae4b7..deb11b7714 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -50,6 +50,7 @@ protected: Q_INVOKABLE void setPassphrase(const QString& passphrase); Q_INVOKABLE void getPassphraseSetupStatus(); Q_INVOKABLE void getKeyFilePathIfExists(); + Q_INVOKABLE void reset(); }; #endif // hifi_QmlCommerce_h diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 9e04694a24..32852602d7 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -14,6 +14,7 @@ #include "Wallet.h" #include "Application.h" #include "ui/ImageProvider.h" +#include "scripting/HMDScriptingInterface.h" #include #include @@ -224,6 +225,12 @@ void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArra memcpy(ckey, hash.data(), 32); } +Wallet::~Wallet() { + if (_securityImage) { + delete _securityImage; + } +} + void Wallet::setPassphrase(const QString& passphrase) { if (_passphrase) { delete _passphrase; @@ -411,6 +418,13 @@ QString Wallet::signWithKey(const QByteArray& text, const QString& key) { return QString(); } +void Wallet::updateImageProvider() { + // inform the image provider. Note it doesn't matter which one you inform, as the + // images are statics + auto engine = DependencyManager::get()->getSurfaceContext()->engine(); + auto imageProvider = reinterpret_cast(engine->imageProvider(ImageProvider::PROVIDER_NAME)); + imageProvider->setSecurityImage(_securityImage); +} void Wallet::chooseSecurityImage(const QString& filename) { @@ -431,10 +445,7 @@ void Wallet::chooseSecurityImage(const QString& filename) { if (encryptFile(path, imageFilePath())) { qCDebug(commerce) << "emitting pixmap"; - // inform the image provider - auto engine = DependencyManager::get()->getSurfaceContext()->engine(); - auto imageProvider = reinterpret_cast(engine->imageProvider(ImageProvider::PROVIDER_NAME)); - imageProvider->setSecurityImage(_securityImage); + updateImageProvider(); emit securityImageResult(true); } else { @@ -454,16 +465,15 @@ void Wallet::getSecurityImage() { } // decrypt and return - if (decryptFile(imageFilePath(), &data, &dataLen)) { + QString filePath(imageFilePath()); + QFileInfo fileInfo(filePath); + if (fileInfo.exists() && decryptFile(filePath, &data, &dataLen)) { // create the pixmap _securityImage = new QPixmap(); _securityImage->loadFromData(data, dataLen, "jpg"); qCDebug(commerce) << "created pixmap from encrypted file"; - // inform the image provider - auto engine = DependencyManager::get()->getSurfaceContext()->engine(); - auto imageProvider = reinterpret_cast(engine->imageProvider(ImageProvider::PROVIDER_NAME)); - imageProvider->setSecurityImage(_securityImage); + updateImageProvider(); delete[] data; emit securityImageResult(true); @@ -481,3 +491,24 @@ void Wallet::sendKeyFilePathIfExists() { emit keyFilePathIfExistsResult(""); } } + +void Wallet::reset() { + _publicKeys.clear(); + + delete _securityImage; + _securityImage = nullptr; + + // tell the provider we got nothing + updateImageProvider(); + delete _passphrase; + + // for now we need to maintain the hard-coded passphrase. + // FIXME: remove this line as part of wiring up the passphrase + // and probably set it to nullptr + _passphrase = new QString("pwd"); + + QFile keyFile(keyFilePath()); + QFile imageFile(imageFilePath()); + keyFile.remove(); + imageFile.remove(); +} diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index b13d4368d9..4acd913181 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -23,6 +23,8 @@ class Wallet : public QObject, public Dependency { SINGLETON_DEPENDENCY public: + + ~Wallet(); // These are currently blocking calls, although they might take a moment. bool createIfNeeded(); bool generateKeyPair(); @@ -38,27 +40,19 @@ public: void setPassphrase(const QString& passphrase); QString* getPassphrase() { return _passphrase; } + void reset(); + signals: void securityImageResult(bool exists) ; void keyFilePathIfExistsResult(const QString& path); -protected: - enum SecurityImage { - NONE = 0, - Cat, - Car, - Dog, - Stars, - Plane, - Gingerbread - }; - private: QStringList _publicKeys{}; QPixmap* _securityImage { nullptr }; QByteArray _salt {"iamsalt!"}; QString* _passphrase { new QString("pwd") }; + void updateImageProvider(); bool encryptFile(const QString& inputFilePath, const QString& outputFilePath); bool decryptFile(const QString& inputFilePath, unsigned char** outputBufferPtr, int* outputBufferLen); }; diff --git a/interface/src/scripting/SelectionScriptingInterface.cpp b/interface/src/scripting/SelectionScriptingInterface.cpp new file mode 100644 index 0000000000..808396c901 --- /dev/null +++ b/interface/src/scripting/SelectionScriptingInterface.cpp @@ -0,0 +1,195 @@ +// +// SelectionScriptingInterface.cpp +// interface/src/scripting +// +// Created by Zach Fox on 2017-08-22. +// 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 "SelectionScriptingInterface.h" +#include +#include "Application.h" + +GameplayObjects::GameplayObjects() { +} + +bool GameplayObjects::addToGameplayObjects(const QUuid& avatarID) { + containsData = true; + _avatarIDs.push_back(avatarID); + return true; +} +bool GameplayObjects::removeFromGameplayObjects(const QUuid& avatarID) { + _avatarIDs.erase(std::remove(_avatarIDs.begin(), _avatarIDs.end(), avatarID), _avatarIDs.end()); + return true; +} + +bool GameplayObjects::addToGameplayObjects(const EntityItemID& entityID) { + containsData = true; + _entityIDs.push_back(entityID); + return true; +} +bool GameplayObjects::removeFromGameplayObjects(const EntityItemID& entityID) { + _entityIDs.erase(std::remove(_entityIDs.begin(), _entityIDs.end(), entityID), _entityIDs.end()); + return true; +} + +bool GameplayObjects::addToGameplayObjects(const OverlayID& overlayID) { + containsData = true; + _overlayIDs.push_back(overlayID); + return true; +} +bool GameplayObjects::removeFromGameplayObjects(const OverlayID& overlayID) { + _overlayIDs.erase(std::remove(_overlayIDs.begin(), _overlayIDs.end(), overlayID), _overlayIDs.end()); + return true; +} + + +SelectionScriptingInterface::SelectionScriptingInterface() { +} + +bool SelectionScriptingInterface::addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) { + if (itemType == "avatar") { + return addToGameplayObjects(listName, (QUuid)id); + } else if (itemType == "entity") { + return addToGameplayObjects(listName, (EntityItemID)id); + } else if (itemType == "overlay") { + return addToGameplayObjects(listName, (OverlayID)id); + } + return false; +} +bool SelectionScriptingInterface::removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) { + if (itemType == "avatar") { + return removeFromGameplayObjects(listName, (QUuid)id); + } else if (itemType == "entity") { + return removeFromGameplayObjects(listName, (EntityItemID)id); + } else if (itemType == "overlay") { + return removeFromGameplayObjects(listName, (OverlayID)id); + } + return false; +} + +template bool SelectionScriptingInterface::addToGameplayObjects(const QString& listName, T idToAdd) { + GameplayObjects currentList = _selectedItemsListMap.value(listName); + currentList.addToGameplayObjects(idToAdd); + _selectedItemsListMap.insert(listName, currentList); + + emit selectedItemsListChanged(listName); + return true; +} +template bool SelectionScriptingInterface::removeFromGameplayObjects(const QString& listName, T idToRemove) { + GameplayObjects currentList = _selectedItemsListMap.value(listName); + if (currentList.getContainsData()) { + currentList.removeFromGameplayObjects(idToRemove); + _selectedItemsListMap.insert(listName, currentList); + + emit selectedItemsListChanged(listName); + return true; + } else { + return false; + } +} +// +// END HANDLING GENERIC ITEMS +// + +GameplayObjects SelectionScriptingInterface::getList(const QString& listName) { + return _selectedItemsListMap.value(listName); +} + +void SelectionScriptingInterface::printList(const QString& listName) { + GameplayObjects currentList = _selectedItemsListMap.value(listName); + if (currentList.getContainsData()) { + + qDebug() << "Avatar IDs:"; + for (auto i : currentList.getAvatarIDs()) { + qDebug() << i << ';'; + } + qDebug() << ""; + + qDebug() << "Entity IDs:"; + for (auto j : currentList.getEntityIDs()) { + qDebug() << j << ';'; + } + qDebug() << ""; + + qDebug() << "Overlay IDs:"; + for (auto k : currentList.getOverlayIDs()) { + qDebug() << k << ';'; + } + qDebug() << ""; + } else { + qDebug() << "List named" << listName << "doesn't exist."; + } +} + +bool SelectionScriptingInterface::removeListFromMap(const QString& listName) { + if (_selectedItemsListMap.remove(listName)) { + emit selectedItemsListChanged(listName); + return true; + } else { + return false; + } +} + + +SelectionToSceneHandler::SelectionToSceneHandler() { +} + +void SelectionToSceneHandler::initialize(const QString& listName) { + _listName = listName; +} + +void SelectionToSceneHandler::selectedItemsListChanged(const QString& listName) { + if (listName == _listName) { + updateSceneFromSelectedList(); + } +} + +void SelectionToSceneHandler::updateSceneFromSelectedList() { + auto mainScene = qApp->getMain3DScene(); + if (mainScene) { + GameplayObjects thisList = DependencyManager::get()->getList(_listName); + render::Transaction transaction; + render::ItemIDs finalList; + render::ItemID currentID; + auto entityTreeRenderer = DependencyManager::get(); + auto& overlays = qApp->getOverlays(); + + for (QUuid& currentAvatarID : thisList.getAvatarIDs()) { + auto avatar = std::static_pointer_cast(DependencyManager::get()->getAvatarBySessionID(currentAvatarID)); + if (avatar) { + currentID = avatar->getRenderItemID(); + if (currentID != render::Item::INVALID_ITEM_ID) { + finalList.push_back(currentID); + } + } + } + + for (EntityItemID& currentEntityID : thisList.getEntityIDs()) { + currentID = entityTreeRenderer->renderableIdForEntityId(currentEntityID); + if (currentID != render::Item::INVALID_ITEM_ID) { + finalList.push_back(currentID); + } + } + + for (OverlayID& currentOverlayID : thisList.getOverlayIDs()) { + auto overlay = overlays.getOverlay(currentOverlayID); + if (overlay != NULL) { + currentID = overlay->getRenderItemID(); + if (currentID != render::Item::INVALID_ITEM_ID) { + finalList.push_back(currentID); + } + } + } + + render::Selection selection(_listName.toStdString(), finalList); + transaction.resetSelection(selection); + + mainScene->enqueueTransaction(transaction); + } else { + qWarning() << "SelectionToSceneHandler::updateRendererSelectedList(), Unexpected null scene, possibly during application shutdown"; + } +} diff --git a/interface/src/scripting/SelectionScriptingInterface.h b/interface/src/scripting/SelectionScriptingInterface.h new file mode 100644 index 0000000000..d1a372c5c4 --- /dev/null +++ b/interface/src/scripting/SelectionScriptingInterface.h @@ -0,0 +1,91 @@ + +// SelectionScriptingInterface.h +// interface/src/scripting +// +// Created by Zach Fox on 2017-08-22. +// 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_SelectionScriptingInterface_h +#define hifi_SelectionScriptingInterface_h + +#include +#include +#include + +#include + +#include "RenderableEntityItem.h" +#include "ui/overlays/Overlay.h" +#include + +class GameplayObjects { +public: + GameplayObjects(); + + bool getContainsData() { return containsData; } + + std::vector getAvatarIDs() { return _avatarIDs; } + bool addToGameplayObjects(const QUuid& avatarID); + bool removeFromGameplayObjects(const QUuid& avatarID); + + std::vector getEntityIDs() { return _entityIDs; } + bool addToGameplayObjects(const EntityItemID& entityID); + bool removeFromGameplayObjects(const EntityItemID& entityID); + + std::vector getOverlayIDs() { return _overlayIDs; } + bool addToGameplayObjects(const OverlayID& overlayID); + bool removeFromGameplayObjects(const OverlayID& overlayID); + +private: + bool containsData { false }; + std::vector _avatarIDs; + std::vector _entityIDs; + std::vector _overlayIDs; +}; + + +class SelectionScriptingInterface : public QObject, public Dependency { + Q_OBJECT + +public: + SelectionScriptingInterface(); + + GameplayObjects getList(const QString& listName); + + Q_INVOKABLE void printList(const QString& listName); + Q_INVOKABLE bool removeListFromMap(const QString& listName); + + Q_INVOKABLE bool addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id); + Q_INVOKABLE bool removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id); + +signals: + void selectedItemsListChanged(const QString& listName); + +private: + QMap _selectedItemsListMap; + + template bool addToGameplayObjects(const QString& listName, T idToAdd); + template bool removeFromGameplayObjects(const QString& listName, T idToRemove); +}; + + +class SelectionToSceneHandler : public QObject { + Q_OBJECT +public: + SelectionToSceneHandler(); + void initialize(const QString& listName); + + void updateSceneFromSelectedList(); + +public slots: + void selectedItemsListChanged(const QString& listName); + +private: + QString _listName { "" }; +}; + +#endif // hifi_SelectionScriptingInterface_h diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 46fb2df007..34aae37175 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -13,6 +13,7 @@ #include "Application.h" #include +#include static const float CONTEXT_OVERLAY_TABLET_OFFSET = 30.0f; // Degrees static const float CONTEXT_OVERLAY_TABLET_ORIENTATION = 210.0f; // Degrees @@ -27,6 +28,9 @@ ContextOverlayInterface::ContextOverlayInterface() { _entityScriptingInterface = DependencyManager::get(); _hmdScriptingInterface = DependencyManager::get(); _tabletScriptingInterface = DependencyManager::get(); + _selectionScriptingInterface = DependencyManager::get(); + + _selectionToSceneHandler.initialize("contextOverlayHighlightList"); _entityPropertyFlags += PROP_POSITION; _entityPropertyFlags += PROP_ROTATION; @@ -57,6 +61,8 @@ ContextOverlayInterface::ContextOverlayInterface() { }); auto entityScriptingInterface = DependencyManager::get().data(); connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity); + + connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandler, &SelectionToSceneHandler::selectedItemsListChanged); } static const uint32_t LEFT_HAND_HW_ID = 1; @@ -242,7 +248,7 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI } } -static const QString MARKETPLACE_BASE_URL = "https://metaverse.highfidelity.com/marketplace/items/"; +static const QString MARKETPLACE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace/items/"; void ContextOverlayInterface::openMarketplace() { // lets open the tablet and go to the current item in @@ -260,25 +266,11 @@ void ContextOverlayInterface::openMarketplace() { } void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityItemID) { - auto entityTree = qApp->getEntities()->getTree(); - entityTree->withReadLock([&] { - auto entityItem = entityTree->findEntityByEntityItemID(entityItemID); - if ((entityItem != NULL) && !entityItem->getShouldHighlight()) { - qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'true' for Entity ID:" << entityItemID; - entityItem->setShouldHighlight(true); - } - }); + _selectionScriptingInterface->addToSelectedItemsList("contextOverlayHighlightList", "entity", entityItemID); } void ContextOverlayInterface::disableEntityHighlight(const EntityItemID& entityItemID) { - auto entityTree = qApp->getEntities()->getTree(); - entityTree->withReadLock([&] { - auto entityItem = entityTree->findEntityByEntityItemID(entityItemID); - if ((entityItem != NULL) && entityItem->getShouldHighlight()) { - qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'false' for Entity ID:" << entityItemID; - entityItem->setShouldHighlight(false); - } - }); + _selectionScriptingInterface->removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityItemID); } void ContextOverlayInterface::deletingEntity(const EntityItemID& entityID) { diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index b386de08cc..c14262029e 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -25,6 +25,7 @@ #include "ui/overlays/Image3DOverlay.h" #include "ui/overlays/Overlays.h" #include "scripting/HMDScriptingInterface.h" +#include "scripting/SelectionScriptingInterface.h" #include "EntityTree.h" #include "ContextOverlayLogging.h" @@ -42,6 +43,7 @@ class ContextOverlayInterface : public QObject, public Dependency { EntityPropertyFlags _entityPropertyFlags; QSharedPointer _hmdScriptingInterface; QSharedPointer _tabletScriptingInterface; + QSharedPointer _selectionScriptingInterface; OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID }; std::shared_ptr _contextOverlay { nullptr }; public: @@ -81,6 +83,8 @@ private: void disableEntityHighlight(const EntityItemID& entityItemID); void deletingEntity(const EntityItemID& entityItemID); + + SelectionToSceneHandler _selectionToSceneHandler; }; #endif // hifi_ContextOverlayInterface_h diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 75d9afeb90..e4eb02b817 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -242,6 +242,7 @@ public: void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene); void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene); bool isInScene() const { return render::Item::isValidID(_renderItemID); } + render::ItemID getRenderItemID() { return _renderItemID; } bool isMoving() const { return _moving; } void setPhysicsCallback(AvatarPhysicsCallback cb); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 429bb629c6..0950974347 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -147,6 +147,7 @@ public slots: void setDisplayModelBounds(bool value) { _displayModelBounds = value; } void setPrecisionPicking(bool value) { _setPrecisionPickingOperator(_mouseRayPickID, value); } EntityRendererPointer renderableForEntityId(const EntityItemID& id) const; + render::ItemID renderableIdForEntityId(const EntityItemID& id) const; protected: virtual OctreePointer createTree() override { @@ -156,7 +157,6 @@ protected: } private: - render::ItemID renderableIdForEntityId(const EntityItemID& id) const; EntityRendererPointer renderableForEntity(const EntityItemPointer& entity) const { return renderableForEntityId(entity->getID()); } render::ItemID renderableIdForEntity(const EntityItemPointer& entity) const { return renderableIdForEntityId(entity->getID()); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 5ec0a1408a..277f6898d1 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1080,7 +1080,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce } _marketplaceEntity = entity->getMarketplaceID().length() != 0; - _shouldHighlight = entity->getShouldHighlight(); _animating = entity->isAnimatingSomething(); withWriteLock([&] { @@ -1207,17 +1206,6 @@ void ModelEntityRenderer::doRender(RenderArgs* args) { model = _model; }); - // this simple logic should say we set showingEntityHighlight to true whenever we are in marketplace mode and we have a marketplace id, or - // whenever we are not set to none and shouldHighlight is true. - bool showingEntityHighlight = ((bool)(args->_outlineFlags & (int)RenderArgs::RENDER_OUTLINE_MARKETPLACE_MODE) && _marketplaceEntity != 0) || - (args->_outlineFlags != RenderArgs::RENDER_OUTLINE_NONE && _shouldHighlight); - if (showingEntityHighlight) { - static glm::vec4 yellowColor(1.0f, 1.0f, 0.0f, 1.0f); - gpu::Batch& batch = *args->_batch; - batch.setModelTransform(_modelTransform); // we want to include the scale as well - DependencyManager::get()->renderWireCubeInstance(args, batch, yellowColor); - } - if (_model && _model->didVisualGeometryRequestFail()) { static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); gpu::Batch& batch = *args->_batch; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 6b57c79713..107af837fe 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -95,7 +95,6 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_LOCKED; requestedProperties += PROP_USER_DATA; requestedProperties += PROP_MARKETPLACE_ID; - requestedProperties += PROP_SHOULD_HIGHLIGHT; requestedProperties += PROP_NAME; requestedProperties += PROP_HREF; requestedProperties += PROP_DESCRIPTION; @@ -241,7 +240,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData()); APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID()); - APPEND_ENTITY_PROPERTY(PROP_SHOULD_HIGHLIGHT, getShouldHighlight()); APPEND_ENTITY_PROPERTY(PROP_NAME, getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_HREF, getHref()); @@ -793,10 +791,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); } - if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT) { - READ_ENTITY_PROPERTY(PROP_SHOULD_HIGHLIGHT, bool, setShouldHighlight); - } - READ_ENTITY_PROPERTY(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref); @@ -2777,20 +2771,6 @@ void EntityItem::setMarketplaceID(const QString& value) { }); } -bool EntityItem::getShouldHighlight() const { - bool result; - withReadLock([&] { - result = _shouldHighlight; - }); - return result; -} - -void EntityItem::setShouldHighlight(const bool value) { - withWriteLock([&] { - _shouldHighlight = value; - }); -} - uint32_t EntityItem::getDirtyFlags() const { uint32_t result; withReadLock([&] { diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 1bd75f78d4..20b541f563 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -289,7 +289,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart); CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID); - CHECK_PROPERTY_CHANGE(PROP_SHOULD_HIGHLIGHT, shouldHighlight); CHECK_PROPERTY_CHANGE(PROP_NAME, name); CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode); CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); @@ -407,7 +406,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHOULD_HIGHLIGHT, shouldHighlight); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL); @@ -984,7 +982,6 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float); ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float); ADD_PROPERTY_TO_MAP(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString); - ADD_PROPERTY_TO_MAP(PROP_SHOULD_HIGHLIGHT, ShouldHighlight, shouldHighlight, bool); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float); @@ -1337,7 +1334,6 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape()); } APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID()); - APPEND_ENTITY_PROPERTY(PROP_SHOULD_HIGHLIGHT, properties.getShouldHighlight()); APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData()); @@ -1636,7 +1632,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int } READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHOULD_HIGHLIGHT, bool, setShouldHighlight); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData); @@ -1751,7 +1746,6 @@ void EntityItemProperties::markAllChanged() { //_alphaFinishChanged = true; _marketplaceIDChanged = true; - _shouldHighlightChanged = true; _keyLight.markAllChanged(); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index b04c3e7dc7..dd8ce952d3 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -171,7 +171,6 @@ public: DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, particle::DEFAULT_RADIUS_FINISH); DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, particle::DEFAULT_EMITTER_SHOULD_TRAIL); DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID); - DEFINE_PROPERTY_REF(PROP_SHOULD_HIGHLIGHT, ShouldHighlight, shouldHighlight, bool, ENTITY_ITEM_DEFAULT_SHOULD_HIGHLIGHT); DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup); DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE); DEFINE_PROPERTY_REF(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray, PolyVoxEntityItem::DEFAULT_VOXEL_DATA); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 43d0e33ba6..d52c5d9aab 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -27,7 +27,6 @@ const glm::vec3 ENTITY_ITEM_HALF_VEC3 = glm::vec3(0.5f); const bool ENTITY_ITEM_DEFAULT_LOCKED = false; const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString(""); -const bool ENTITY_ITEM_DEFAULT_SHOULD_HIGHLIGHT = false; const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid(); const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 9600d0d4fe..b3cfc143c2 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -78,7 +78,6 @@ enum EntityPropertyList { PROP_COMPOUND_SHAPE_URL, // used by Model + zones entities PROP_MARKETPLACE_ID, // all entities - PROP_SHOULD_HIGHLIGHT, // all entities PROP_ACCELERATION, // all entities PROP_SIMULATION_OWNER, // formerly known as PROP_SIMULATOR_ID PROP_NAME, // all entities diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index f44beb6d74..c9961cc53a 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT; + return VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE; case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::JSONFilterWithFamilyTree); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index e8b74a74d5..3ba2b96dfc 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -259,6 +259,7 @@ const PacketVersion VERSION_ENTITIES_ZONE_FILTERS = 68; const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69; const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70; const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71; +const PacketVersion VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE = 72; enum class EntityQueryPacketVersion: PacketVersion { JSONFilter = 18, diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 68c0250bec..27abc8c282 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -210,6 +210,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren } task.addJob("DrawZoneStack", deferredFrameTransform); + + // Render.getConfig("RenderMainView.DrawSelectionBounds").enabled = true + const auto selectedMetas = task.addJob("PassTestSelection", metas, "contextOverlayHighlightList"); + task.addJob("DrawSelectionBounds", selectedMetas); } // AA job to be revisited diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index 12f9506286..7070a4def5 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -63,12 +63,6 @@ namespace render { public: enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE }; enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD }; - enum OutlineFlags { - RENDER_OUTLINE_NONE = 0, - RENDER_OUTLINE_WIREFRAMES = 1, - RENDER_OUTLINE_MARKETPLACE_MODE = 2, - RENDER_OUTLINE_SHADER = 4 - }; enum DebugFlags { RENDER_DEBUG_NONE = 0, RENDER_DEBUG_HULLS = 1 @@ -115,7 +109,6 @@ namespace render { int _boundaryLevelAdjust { 0 }; RenderMode _renderMode { DEFAULT_RENDER_MODE }; DisplayMode _displayMode { MONO }; - OutlineFlags _outlineFlags{ RENDER_OUTLINE_NONE }; DebugFlags _debugFlags { RENDER_DEBUG_NONE }; gpu::Batch* _batch = nullptr; diff --git a/interface/src/ui/ImageProvider.cpp b/libraries/ui/src/ui/ImageProvider.cpp similarity index 56% rename from interface/src/ui/ImageProvider.cpp rename to libraries/ui/src/ui/ImageProvider.cpp index 4925cdf1e9..c74ed0cb44 100644 --- a/interface/src/ui/ImageProvider.cpp +++ b/libraries/ui/src/ui/ImageProvider.cpp @@ -10,13 +10,39 @@ // #include "ImageProvider.h" -#include + +#include +#include const QString ImageProvider::PROVIDER_NAME = "security"; +QReadWriteLock ImageProvider::_rwLock; +QPixmap* ImageProvider::_securityImage = nullptr; + +ImageProvider::~ImageProvider() { + QWriteLocker lock(&_rwLock); + if (_securityImage) { + delete _securityImage; + _securityImage = nullptr; + } +} + +void ImageProvider::setSecurityImage(const QPixmap* pixmap) { + // no need to delete old one, that is managed by the wallet + QWriteLocker lock(&_rwLock); + if (_securityImage) { + delete _securityImage; + } + if (pixmap) { + _securityImage = new QPixmap(*pixmap); + } else { + _securityImage = nullptr; + } +} QPixmap ImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) { // adjust the internal pixmap to have the requested size + QReadLocker lock(&_rwLock); if (id == "securityImage" && _securityImage) { *size = _securityImage->size(); if (requestedSize.width() > 0 && requestedSize.height() > 0) { diff --git a/interface/src/ui/ImageProvider.h b/libraries/ui/src/ui/ImageProvider.h similarity index 79% rename from interface/src/ui/ImageProvider.h rename to libraries/ui/src/ui/ImageProvider.h index c0b620585a..0093b60655 100644 --- a/interface/src/ui/ImageProvider.h +++ b/libraries/ui/src/ui/ImageProvider.h @@ -13,19 +13,20 @@ #define hifi_ImageProvider_h #include +#include class ImageProvider: public QQuickImageProvider { public: static const QString PROVIDER_NAME; ImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {} - + virtual ~ImageProvider(); QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override; - void setSecurityImage(QPixmap* pixmap) { _securityImage = pixmap; } - + void setSecurityImage(const QPixmap* pixmap); protected: - QPixmap* _securityImage { nullptr }; + static QReadWriteLock _rwLock; + static QPixmap* _securityImage; }; diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index be9a15b416..84466f41b0 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -6,6 +6,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OffscreenQmlSurface.h" +#include "ImageProvider.h" // Has to come before Qt GL includes #include @@ -184,7 +185,7 @@ private: GLuint texture = textureAndFence.first; uvec2 size = _textureSizes[texture]; auto sizeKey = uvec2ToUint64(size); - // Textures can be returned after all surfaces of the given size have been destroyed, + // Textures can be returned after all surfaces of the given size have been destroyed, // in which case we just destroy the texture if (!_textures.count(sizeKey)) { destroy(textureAndFence); @@ -305,6 +306,9 @@ static size_t globalEngineRefCount{ 0 }; #endif void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) { + // register the pixmap image provider (used only for security image, for now) + engine->addImageProvider(ImageProvider::PROVIDER_NAME, new ImageProvider()); + engine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory); auto importList = engine->importPathList(); importList.insert(importList.begin(), PathUtils::resourcesPath()); @@ -464,8 +468,8 @@ std::function OffscreenQmlSurface::getDiscardLambda() { } bool OffscreenQmlSurface::allowNewFrame(uint8_t fps) { - // If we already have a pending texture, don't render another one - // i.e. don't render faster than the consumer context, since it wastes + // If we already have a pending texture, don't render another one + // i.e. don't render faster than the consumer context, since it wastes // GPU cycles on producing output that will never be seen if (0 != _latestTextureAndFence.first) { return false; @@ -526,6 +530,7 @@ void OffscreenQmlSurface::create() { // Create a QML engine. auto qmlEngine = acquireEngine(_quickWindow); + _qmlContext = new QQmlContext(qmlEngine->rootContext()); _qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow())); diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 7f24e7f634..a7b7b50379 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -53,14 +53,27 @@ // 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 isHmdPreviewDisabled = true; function fromQml(message) { switch (message.method) { case 'walletSetup_cancelClicked': + case 'needsLogIn_cancelClicked': tablet.gotoHomeScreen(); break; - case 'walletSetup_loginClicked': + case 'needsLogIn_loginClicked': openLoginWindow(); break; + case 'disableHmdPreview': + isHmdPreviewDisabled = Menu.isOptionChecked("Disable Preview"); + Menu.setIsOptionChecked("Disable Preview", true); + break; + case 'maybeEnableHmdPreview': + Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled); + break; + case 'walletReset': + onButtonClicked(); + onButtonClicked(); + break; default: print('Unrecognized message from QML:', JSON.stringify(message)); } diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 7ee6c64858..8b61226235 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -405,9 +405,11 @@ var toolBar = (function () { } }); - var createButtonIconRsrc = ((Entities.canRez() || Entities.canRezTmp()) ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON); + var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp()); + var createButtonIconRsrc = (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON); tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); activeButton = tablet.addButton({ + captionColorOverride: hasRezPermissions ? "" : "#888888", icon: createButtonIconRsrc, activeIcon: "icons/tablet-icons/edit-a.svg", text: "CREATE", @@ -789,6 +791,7 @@ function handleDomainChange() { var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp()); createButton.editProperties({ icon: (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON), + captionColorOverride: (hasRezPermissions ? "" : "#888888"), }); } diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 62a4dcf369..28d116d3ec 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -127,9 +127,15 @@ $(this).attr('data-href', $(this).attr('href')); $(this).attr('href', '#'); cost = $(this).closest('.col-xs-3').find('.item-cost').text(); + + $(this).closest('.col-xs-3').prev().attr("class", 'col-xs-6'); + $(this).closest('.col-xs-3').attr("class", 'col-xs-6'); if (parseInt(cost) > 0) { - $(this).find('.price').text("BUY"); + var priceElement = $(this).find('.price') + priceElement.css({ "width": "auto", "padding": "3px 5px", "height": "26px" }); + priceElement.text(parseFloat(cost / 100).toFixed(2) + ' HFC'); + priceElement.css({ "min-width": priceElement.width() + 10 }); } }); @@ -160,23 +166,23 @@ // 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; + injectBuyButtonOnMainPage(); addPurchasesButton(); } } function injectHiFiItemPageCode() { if (confirmAllPurchases) { - var href = $('#side-info').find('.btn').attr('href'); - $('#side-info').find('.btn').attr('href', '#'); + var href = $('#side-info').find('.btn').first().attr('href'); + $('#side-info').find('.btn').first().attr('href', '#'); var cost = $('.item-cost').text(); - if (parseInt(cost) > 0) { - $('#side-info').find('.btn').html('Buy Item '); + if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) { + $('#side-info').find('.btn').first().html('Own Item: ' + (parseFloat(cost / 100).toFixed(2)) + ' HFC'); } - $('#side-info').find('.btn').on('click', function () { + $('#side-info').find('.btn').first().on('click', function () { buyButtonClicked(window.location.pathname.split("/")[3], $('#top-center').find('h1').text(), $('#creator').find('.value').text(), diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 7b479cdcad..7d1aaee157 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -228,6 +228,15 @@ case 'purchases_backClicked': tablet.gotoWebScreen(message.referrerURL, MARKETPLACES_INJECT_SCRIPT_URL); break; + case 'purchases_goToMarketplaceClicked': + tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL); + break; + case 'needsLogIn_cancelClicked': + tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL); + break; + case 'needsLogIn_loginClicked': + openLoginWindow(); + break; default: print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message)); }