diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml
index ca7226a6ab..579b4e7fd6 100644
--- a/interface/resources/qml/desktop/Desktop.qml
+++ b/interface/resources/qml/desktop/Desktop.qml
@@ -50,7 +50,22 @@ FocusScope {
property bool desktopRoot: true
// The VR version of the primary menu
- property var rootMenu: Menu { objectName: "rootMenu" }
+ property var rootMenu: Menu {
+ objectName: "rootMenu"
+
+ // for some reasons it is not possible to use just '({})' here as it gets empty when passed to TableRoot/DesktopRoot
+ property var exclusionGroupsByMenuItem : ListModel {}
+
+ function addExclusionGroup(menuItem, exclusionGroup)
+ {
+ exclusionGroupsByMenuItem.append(
+ {
+ 'menuItem' : menuItem.toString(),
+ 'exclusionGroup' : exclusionGroup.toString()
+ }
+ );
+ }
+ }
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX/AMD
// because shaders are 4.2, and do not include #version declarations.
diff --git a/interface/resources/qml/hifi/commerce/Checkout.qml b/interface/resources/qml/hifi/commerce/Checkout.qml
deleted file mode 100644
index d9b0072917..0000000000
--- a/interface/resources/qml/hifi/commerce/Checkout.qml
+++ /dev/null
@@ -1,463 +0,0 @@
-//
-// Checkout.qml
-// qml/hifi/commerce
-//
-// Checkout
-//
-// Created by Zach Fox on 2017-08-07
-// 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
-import "./wallet" as HifiWallet
-
-// references XXX from root context
-
-Rectangle {
- HifiConstants { id: hifi; }
-
- id: checkoutRoot;
- property bool inventoryReceived: false;
- property bool balanceReceived: false;
- property string itemId: "";
- property string itemHref: "";
- property int balanceAfterPurchase: 0;
- property bool alreadyOwned: false;
- property int itemPriceFull: 0;
- // Style
- color: hifi.colors.baseGray;
- Hifi.QmlCommerce {
- id: commerce;
- onBuyResult: {
- if (result.status !== 'success') {
- buyButton.text = result.message;
- buyButton.enabled = false;
- } else {
- if (urlHandler.canHandleUrl(itemHref)) {
- urlHandler.handleUrl(itemHref);
- }
- sendToScript({method: 'checkout_buySuccess', itemId: itemId});
- }
- }
- onBalanceResult: {
- if (result.status !== 'success') {
- console.log("Failed to get balance", result.message);
- } else {
- balanceReceived = true;
- hfcBalanceText.text = parseFloat(result.data.balance/100).toFixed(2);
- balanceAfterPurchase = parseFloat(result.data.balance/100) - parseFloat(checkoutRoot.itemPriceFull/100).toFixed(2);
- }
- }
- onInventoryResult: {
- if (result.status !== 'success') {
- console.log("Failed to get inventory", result.message);
- } else {
- inventoryReceived = true;
- console.log('inventory fixme', JSON.stringify(result));
- if (inventoryContains(result.data.assets, itemId)) {
- alreadyOwned = true;
- } else {
- alreadyOwned = false;
- }
- }
- }
- }
-
- //
- // TITLE BAR START
- //
- Item {
- id: titleBarContainer;
- // Size
- width: checkoutRoot.width;
- height: 50;
- // Anchors
- anchors.left: parent.left;
- anchors.top: parent.top;
-
- // Title Bar text
- RalewaySemiBold {
- id: titleBarText;
- text: "Checkout";
- // 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.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
-
- // Separator
- HifiControlsUit.Separator {
- anchors.left: parent.left;
- anchors.right: parent.right;
- anchors.bottom: parent.bottom;
- }
- }
- //
- // TITLE BAR END
- //
-
- //
- // ITEM DESCRIPTION START
- //
- Item {
- id: itemDescriptionContainer;
- // Size
- width: checkoutRoot.width;
- height: childrenRect.height + 20;
- // Anchors
- anchors.left: parent.left;
- anchors.top: titleBarContainer.bottom;
-
- // Item Name text
- Item {
- id: itemNameContainer;
- // Anchors
- anchors.top: parent.top;
- anchors.topMargin: 4;
- anchors.left: parent.left;
- anchors.leftMargin: 16;
- anchors.right: parent.right;
- anchors.rightMargin: 16;
- height: childrenRect.height;
-
- RalewaySemiBold {
- id: itemNameTextLabel;
- text: "Item Name:";
- // Anchors
- anchors.top: parent.top;
- anchors.left: parent.left;
- width: paintedWidth;
- // Text size
- size: 16;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- RalewayRegular {
- id: itemNameText;
- // Text size
- size: itemNameTextLabel.size;
- // Anchors
- anchors.top: parent.top;
- anchors.left: itemNameTextLabel.right;
- anchors.leftMargin: 16;
- width: paintedWidth;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- }
-
-
- // Item Author text
- Item {
- id: itemAuthorContainer;
- // Anchors
- anchors.top: itemNameContainer.bottom;
- anchors.topMargin: 4;
- anchors.left: parent.left;
- anchors.leftMargin: 16;
- anchors.right: parent.right;
- anchors.rightMargin: 16;
- height: childrenRect.height;
-
- RalewaySemiBold {
- id: itemAuthorTextLabel;
- text: "Item Author:";
- // Anchors
- anchors.top: parent.top;
- anchors.left: parent.left;
- width: paintedWidth;
- // Text size
- size: 16;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- RalewayRegular {
- id: itemAuthorText;
- // Text size
- size: itemAuthorTextLabel.size;
- // Anchors
- anchors.top: parent.top;
- anchors.left: itemAuthorTextLabel.right;
- anchors.leftMargin: 16;
- width: paintedWidth;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- }
-
- // HFC Balance text
- Item {
- id: hfcBalanceContainer;
- // Anchors
- anchors.top: itemAuthorContainer.bottom;
- anchors.topMargin: 16;
- anchors.left: parent.left;
- anchors.leftMargin: 16;
- anchors.right: parent.right;
- anchors.rightMargin: 16;
- height: childrenRect.height;
-
- RalewaySemiBold {
- id: hfcBalanceTextLabel;
- text: "HFC Balance:";
- // Anchors
- anchors.top: parent.top;
- anchors.left: parent.left;
- width: paintedWidth;
- // Text size
- size: 20;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- RalewayRegular {
- id: hfcBalanceText;
- text: "--";
- // Text size
- size: hfcBalanceTextLabel.size;
- // Anchors
- anchors.top: parent.top;
- anchors.left: hfcBalanceTextLabel.right;
- anchors.leftMargin: 16;
- width: paintedWidth;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- }
-
- // Item Price text
- Item {
- id: itemPriceContainer;
- // Anchors
- anchors.top: hfcBalanceContainer.bottom;
- anchors.topMargin: 4;
- anchors.left: parent.left;
- anchors.leftMargin: 16;
- anchors.right: parent.right;
- anchors.rightMargin: 16;
- height: childrenRect.height;
-
- RalewaySemiBold {
- id: itemPriceTextLabel;
- text: "Item Price:";
- // Anchors
- anchors.top: parent.top;
- anchors.left: parent.left;
- width: paintedWidth;
- // Text size
- size: 20;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- RalewayRegular {
- id: itemPriceText;
- // Text size
- size: itemPriceTextLabel.size;
- // Anchors
- anchors.top: parent.top;
- anchors.left: itemPriceTextLabel.right;
- anchors.leftMargin: 16;
- width: paintedWidth;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- }
-
- // HFC "Balance After Purchase" text
- Item {
- id: hfcBalanceAfterPurchaseContainer;
- // Anchors
- anchors.top: itemPriceContainer.bottom;
- anchors.topMargin: 4;
- anchors.left: parent.left;
- anchors.leftMargin: 16;
- anchors.right: parent.right;
- anchors.rightMargin: 16;
- height: childrenRect.height;
-
- RalewaySemiBold {
- id: hfcBalanceAfterPurchaseTextLabel;
- text: "HFC Balance After Purchase:";
- // Anchors
- anchors.top: parent.top;
- anchors.left: parent.left;
- width: paintedWidth;
- // Text size
- size: 20;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- RalewayRegular {
- id: hfcBalanceAfterPurchaseText;
- text: balanceAfterPurchase;
- // Text size
- size: hfcBalanceAfterPurchaseTextLabel.size;
- // Anchors
- anchors.top: parent.top;
- anchors.left: hfcBalanceAfterPurchaseTextLabel.right;
- anchors.leftMargin: 16;
- width: paintedWidth;
- // Style
- color: (balanceAfterPurchase >= 0) ? hifi.colors.lightGrayText : hifi.colors.redHighlight;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- }
- }
- //
- // ITEM DESCRIPTION END
- //
-
-
- //
- // ACTION BUTTONS START
- //
- Item {
- id: actionButtonsContainer;
- // Size
- width: checkoutRoot.width;
- height: 40;
- // Anchors
- anchors.left: parent.left;
- anchors.bottom: parent.bottom;
- anchors.bottomMargin: 8;
-
- // "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: 'checkout_cancelClicked', params: itemId});
- }
- }
-
- // "Buy" button
- HifiControlsUit.Button {
- id: buyButton;
- enabled: balanceAfterPurchase >= 0 && inventoryReceived && balanceReceived;
- color: hifi.buttons.black;
- 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: (inventoryReceived && balanceReceived) ? (alreadyOwned ? "Already Owned: Get Item" : "Buy") : "--";
- onClicked: {
- if (!alreadyOwned) {
- commerce.buy(itemId, parseFloat(itemPriceText.text*100));
- } else {
- if (urlHandler.canHandleUrl(itemHref)) {
- urlHandler.handleUrl(itemHref);
- }
- sendToScript({method: 'checkout_buySuccess', itemId: itemId});
- }
- }
- }
- }
- //
- // ACTION BUTTONS END
- //
-
- //
- // FUNCTION DEFINITIONS START
- //
- //
- // Function Name: fromScript()
- //
- // Relevant Variables:
- // None
- //
- // Arguments:
- // message: The message sent from the JavaScript, in this case the Marketplaces JavaScript.
- // Messages are in format "{method, params}", like json-rpc.
- //
- // Description:
- // Called when a message is received from a script.
- //
- function fromScript(message) {
- switch (message.method) {
- case 'updateCheckoutQML':
- itemId = message.params.itemId;
- itemNameText.text = message.params.itemName;
- itemAuthorText.text = message.params.itemAuthor;
- checkoutRoot.itemPriceFull = message.params.itemPrice;
- itemPriceText.text = parseFloat(checkoutRoot.itemPriceFull/100).toFixed(2);
- itemHref = message.params.itemHref;
- commerce.balance();
- commerce.inventory();
- break;
- default:
- console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
- }
- }
- signal sendToScript(var message);
-
- function inventoryContains(inventoryJson, id) {
- for (var idx = 0; idx < inventoryJson.length; idx++) {
- if(inventoryJson[idx].id === id) {
- return true;
- }
- }
- return false;
- }
-
- //
- // FUNCTION DEFINITIONS END
- //
-}
diff --git a/interface/resources/qml/hifi/commerce/Inventory.qml b/interface/resources/qml/hifi/commerce/Inventory.qml
deleted file mode 100644
index 20458f9f16..0000000000
--- a/interface/resources/qml/hifi/commerce/Inventory.qml
+++ /dev/null
@@ -1,280 +0,0 @@
-//
-// Inventory.qml
-// qml/hifi/commerce
-//
-// Inventory
-//
-// Created by Zach Fox on 2017-08-10
-// 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
-import "./wallet" as HifiWallet
-
-// references XXX from root context
-
-Rectangle {
- HifiConstants { id: hifi; }
-
- id: inventoryRoot;
- property string referrerURL: "";
- // Style
- color: hifi.colors.baseGray;
- Hifi.QmlCommerce {
- id: commerce;
- onBalanceResult: {
- if (result.status !== 'success') {
- console.log("Failed to get balance", result.message);
- } else {
- hfcBalanceText.text = parseFloat(result.data.balance/100).toFixed(2);
- }
- }
- onInventoryResult: {
- if (result.status !== 'success') {
- console.log("Failed to get inventory", result.message);
- } else {
- inventoryContentsList.model = result.data.assets;
- }
- }
- }
-
- //
- // TITLE BAR START
- //
- Item {
- id: titleBarContainer;
- // Size
- width: parent.width;
- height: 50;
- // Anchors
- anchors.left: parent.left;
- anchors.top: parent.top;
-
- // Title Bar text
- RalewaySemiBold {
- id: titleBarText;
- text: "Inventory";
- // 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.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
-
- // Separator
- HifiControlsUit.Separator {
- anchors.left: parent.left;
- anchors.right: parent.right;
- anchors.bottom: parent.bottom;
- }
- }
- //
- // TITLE BAR END
- //
-
- //
- // HFC BALANCE START
- //
- Item {
- id: hfcBalanceContainer;
- // Size
- width: inventoryRoot.width;
- height: childrenRect.height + 20;
- // Anchors
- anchors.left: parent.left;
- anchors.leftMargin: 16;
- anchors.top: titleBarContainer.bottom;
- anchors.topMargin: 4;
-
- RalewaySemiBold {
- id: hfcBalanceTextLabel;
- text: "HFC Balance:";
- // Anchors
- anchors.top: parent.top;
- anchors.left: parent.left;
- width: paintedWidth;
- // Text size
- size: 20;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- RalewayRegular {
- id: hfcBalanceText;
- text: "--";
- // Text size
- size: hfcBalanceTextLabel.size;
- // Anchors
- anchors.top: parent.top;
- anchors.left: hfcBalanceTextLabel.right;
- anchors.leftMargin: 16;
- width: paintedWidth;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- }
- //
- // HFC BALANCE END
- //
-
- //
- // INVENTORY CONTENTS START
- //
- Item {
- id: inventoryContentsContainer;
- // Anchors
- anchors.left: parent.left;
- anchors.leftMargin: 16;
- anchors.right: parent.right;
- anchors.rightMargin: 16;
- anchors.top: hfcBalanceContainer.bottom;
- anchors.topMargin: 8;
- anchors.bottom: actionButtonsContainer.top;
- anchors.bottomMargin: 8;
-
- RalewaySemiBold {
- id: inventoryContentsLabel;
- text: "Inventory:";
- // Anchors
- anchors.top: parent.top;
- anchors.left: parent.left;
- width: paintedWidth;
- // Text size
- size: 24;
- // Style
- color: hifi.colors.lightGrayText;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- verticalAlignment: Text.AlignVCenter;
- }
- ListView {
- id: inventoryContentsList;
- clip: true;
- // Anchors
- anchors.top: inventoryContentsLabel.bottom;
- anchors.topMargin: 8;
- anchors.left: parent.left;
- anchors.bottom: parent.bottom;
- width: parent.width;
- delegate: Item {
- width: parent.width;
- height: 30;
- RalewayRegular {
- id: thisItemId;
- // Text size
- size: 20;
- // Style
- color: hifi.colors.blueAccent;
- text: modelData.title;
- // Alignment
- horizontalAlignment: Text.AlignHLeft;
- }
- MouseArea {
- anchors.fill: parent;
- hoverEnabled: enabled;
- onClicked: {
- sendToScript({method: 'inventory_itemClicked', itemId: modelData.id});
- }
- onEntered: {
- thisItemId.color = hifi.colors.blueHighlight;
- }
- onExited: {
- thisItemId.color = hifi.colors.blueAccent;
- }
- }
- }
- }
- }
- //
- // INVENTORY CONTENTS END
- //
-
- //
- // ACTION BUTTONS START
- //
- Item {
- id: actionButtonsContainer;
- // Size
- width: inventoryRoot.width;
- height: 40;
- // Anchors
- anchors.left: parent.left;
- anchors.bottom: parent.bottom;
- anchors.bottomMargin: 8;
-
- // "Back" button
- HifiControlsUit.Button {
- id: backButton;
- 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: "Back"
- onClicked: {
- sendToScript({method: 'inventory_backClicked', referrerURL: referrerURL});
- }
- }
- }
- //
- // ACTION BUTTONS END
- //
-
- //
- // FUNCTION DEFINITIONS START
- //
- //
- // Function Name: fromScript()
- //
- // Relevant Variables:
- // None
- //
- // Arguments:
- // message: The message sent from the JavaScript, in this case the Marketplaces JavaScript.
- // Messages are in format "{method, params}", like json-rpc.
- //
- // Description:
- // Called when a message is received from a script.
- //
- function fromScript(message) {
- switch (message.method) {
- case 'updateInventory':
- referrerURL = message.referrerURL;
- commerce.balance();
- commerce.inventory();
- break;
- default:
- console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
- }
- }
- signal sendToScript(var message);
-
- //
- // FUNCTION DEFINITIONS END
- //
-}
diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
new file mode 100644
index 0000000000..109e357206
--- /dev/null
+++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
@@ -0,0 +1,944 @@
+//
+// Checkout.qml
+// qml/hifi/commerce/checkout
+//
+// Checkout
+//
+// Created by Zach Fox on 2017-08-25
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import Hifi 1.0 as Hifi
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import "../../../styles-uit"
+import "../../../controls-uit" as HifiControlsUit
+import "../../../controls" as HifiControls
+import "../wallet" as HifiWallet
+
+// references XXX from root context
+
+Rectangle {
+ HifiConstants { id: hifi; }
+
+ id: root;
+ 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;
+ // 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"
+ root.activeView = "notSetUp";
+ } else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
+ root.activeView = "checkoutMain";
+ } else if (exists) {
+ // just set the source again (to be sure the change was noticed)
+ securityImage.source = "";
+ securityImage.source = "image://security/securityImage";
+ }
+ }
+
+ onKeyFilePathIfExistsResult: {
+ keyFilePathIfExistsResultReceived = true;
+ if (path === "" && root.activeView !== "notSetUp") {
+ root.activeView = "notSetUp";
+ } else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
+ root.activeView = "checkoutMain";
+ }
+ }
+
+ onBuyResult: {
+ if (result.status !== 'success') {
+ failureErrorText.text = "Here's some more info about the error:
" + (result.message);
+ root.activeView = "checkoutFailure";
+ } else {
+ root.activeView = "checkoutSuccess";
+ }
+ }
+
+ onBalanceResult: {
+ if (result.status !== 'success') {
+ console.log("Failed to get balance", result.data.message);
+ } else {
+ root.balanceReceived = true;
+ hfcBalanceText.text = (parseFloat(result.data.balance/100).toFixed(2)) + " HFC";
+ balanceAfterPurchase = parseFloat(result.data.balance/100) - root.itemPriceFull/100;
+ root.setBuyText();
+ }
+ }
+
+ onInventoryResult: {
+ if (result.status !== 'success') {
+ console.log("Failed to get purchases", result.data.message);
+ } else {
+ root.purchasesReceived = true;
+ if (purchasesContains(result.data.assets, itemId)) {
+ root.alreadyOwned = true;
+ } else {
+ root.alreadyOwned = false;
+ }
+ root.setBuyText();
+ }
+ }
+ }
+
+ HifiWallet.SecurityImageModel {
+ id: securityImageModel;
+ }
+
+ //
+ // TITLE BAR START
+ //
+ Item {
+ id: titleBarContainer;
+ visible: !needsLogIn.visible;
+ // Size
+ width: parent.width;
+ height: 50;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.top: parent.top;
+
+ // Title Bar text
+ RalewaySemiBold {
+ id: titleBarText;
+ text: "MARKETPLACE";
+ // 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;
+ }
+
+ // Security Image (TEMPORARY!)
+ Image {
+ id: securityImage;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.right: parent.right;
+ anchors.verticalCenter: parent.verticalCenter;
+ height: parent.height - 10;
+ width: height;
+ fillMode: Image.PreserveAspectFit;
+ mipmap: true;
+ 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 {
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ anchors.bottom: parent.bottom;
+ }
+ }
+ //
+ // TITLE BAR END
+ //
+
+ Rectangle {
+ id: initialize;
+ visible: root.activeView === "initialize";
+ anchors.top: titleBarContainer.bottom;
+ anchors.bottom: parent.top;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ color: hifi.colors.baseGray;
+
+ Component.onCompleted: {
+ 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
+ //
+ Item {
+ id: notSetUp;
+ visible: root.activeView === "notSetUp";
+ anchors.top: titleBarContainer.bottom;
+ anchors.bottom: parent.bottom;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+
+ RalewayRegular {
+ id: notSetUpText;
+ text: "Your wallet isn't set up.
Set up your Wallet (no credit card necessary) to claim your free HFC " +
+ "and get items from the Marketplace.";
+ // Text size
+ size: 24;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.bottom: notSetUpActionButtonsContainer.top;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ // Style
+ color: hifi.colors.faintGray;
+ wrapMode: Text.WordWrap;
+ // Alignment
+ horizontalAlignment: Text.AlignHCenter;
+ verticalAlignment: Text.AlignVCenter;
+ }
+
+ Item {
+ id: notSetUpActionButtonsContainer;
+ // Size
+ width: root.width;
+ height: 70;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 24;
+
+ // "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: 'checkout_cancelClicked', params: itemId});
+ }
+ }
+
+ // "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: "Set Up Wallet"
+ onClicked: {
+ sendToScript({method: 'checkout_setUpClicked'});
+ }
+ }
+ }
+ }
+ //
+ // "WALLET NOT SET UP" END
+ //
+
+ //
+ // CHECKOUT CONTENTS START
+ //
+ Item {
+ id: checkoutContents;
+ visible: root.activeView === "checkoutMain";
+ anchors.top: titleBarContainer.bottom;
+ anchors.bottom: parent.bottom;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+
+ //
+ // ITEM DESCRIPTION START
+ //
+ Item {
+ id: itemDescriptionContainer;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.leftMargin: 32;
+ anchors.right: parent.right;
+ anchors.rightMargin: 32;
+ anchors.top: parent.top;
+ anchors.bottom: checkoutActionButtonsContainer.top;
+
+ // HFC Balance text
+ Item {
+ id: hfcBalanceContainer;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.topMargin: 30;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: childrenRect.height;
+
+ RalewaySemiBold {
+ id: hfcBalanceTextLabel;
+ text: "Balance:";
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: parent.left;
+ width: paintedWidth;
+ height: paintedHeight;
+ // Text size
+ size: 30;
+ // Style
+ color: hifi.colors.lightGrayText;
+ // Alignment
+ horizontalAlignment: Text.AlignLeft;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ RalewayRegular {
+ id: hfcBalanceText;
+ text: "-- HFC";
+ // Text size
+ size: hfcBalanceTextLabel.size;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: hfcBalanceTextLabel.right;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: paintedHeight;
+ // Style
+ color: hifi.colors.lightGrayText;
+ // Alignment
+ horizontalAlignment: Text.AlignRight;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ }
+
+ // Item Name text
+ Item {
+ id: itemNameContainer;
+ // Anchors
+ anchors.top: hfcBalanceContainer.bottom;
+ anchors.topMargin: 32;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: childrenRect.height;
+
+ RalewaySemiBold {
+ id: itemNameTextLabel;
+ text: "Item:";
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: parent.left;
+ width: paintedWidth;
+ height: paintedHeight;
+ // Text size
+ size: 20;
+ // Style
+ color: hifi.colors.lightGrayText;
+ // Alignment
+ horizontalAlignment: Text.AlignLeft;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ RalewayRegular {
+ id: itemNameText;
+ // Text size
+ size: itemNameTextLabel.size;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: itemNameTextLabel.right;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: paintedHeight;
+ // Style
+ color: hifi.colors.lightGrayText;
+ elide: Text.ElideRight;
+ // Alignment
+ horizontalAlignment: Text.AlignRight;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ }
+
+
+ // Item Author text
+ Item {
+ id: itemAuthorContainer;
+ // Anchors
+ anchors.top: itemNameContainer.bottom;
+ anchors.topMargin: 4;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: childrenRect.height;
+
+ RalewaySemiBold {
+ id: itemAuthorTextLabel;
+ text: "Author:";
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: parent.left;
+ width: paintedWidth;
+ height: paintedHeight;
+ // Text size
+ size: 20;
+ // Style
+ color: hifi.colors.lightGrayText;
+ // Alignment
+ horizontalAlignment: Text.AlignLeft;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ RalewayRegular {
+ id: itemAuthorText;
+ // Text size
+ size: itemAuthorTextLabel.size;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: itemAuthorTextLabel.right;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: paintedHeight;
+ // Style
+ color: hifi.colors.lightGrayText;
+ elide: Text.ElideRight;
+ // Alignment
+ horizontalAlignment: Text.AlignRight;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ }
+
+ // "Item Price" container
+ Item {
+ id: itemPriceContainer;
+ // Anchors
+ anchors.top: itemAuthorContainer.bottom;
+ anchors.topMargin: 32;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: childrenRect.height;
+
+ RalewaySemiBold {
+ id: itemPriceTextLabel;
+ text: "Item Price:";
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: parent.left;
+ width: paintedWidth;
+ height: paintedHeight;
+ // Text size
+ size: 30;
+ // Style
+ color: hifi.colors.lightGrayText;
+ // Alignment
+ horizontalAlignment: Text.AlignLeft;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ RalewayRegular {
+ id: itemPriceText;
+ text: "-- HFC";
+ // Text size
+ size: itemPriceTextLabel.size;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: itemPriceTextLabel.right;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: paintedHeight;
+ // Style
+ color: (balanceAfterPurchase >= 0) ? hifi.colors.lightGrayText : hifi.colors.redHighlight;
+ // Alignment
+ horizontalAlignment: Text.AlignRight;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ }
+
+ // "Balance After Purchase" container
+ Item {
+ id: balanceAfterPurchaseContainer;
+ // Anchors
+ anchors.top: itemPriceContainer.bottom;
+ anchors.topMargin: 16;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: childrenRect.height;
+
+ RalewaySemiBold {
+ id: balanceAfterPurchaseTextLabel;
+ text: "Balance After Purchase:";
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: parent.left;
+ width: paintedWidth;
+ height: paintedHeight;
+ // Text size
+ size: 20;
+ // Style
+ color: hifi.colors.lightGrayText;
+ // Alignment
+ horizontalAlignment: Text.AlignLeft;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ RalewayRegular {
+ id: balanceAfterPurchaseText;
+ text: balanceAfterPurchase.toFixed(2) + " HFC";
+ // Text size
+ size: balanceAfterPurchaseTextLabel.size;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.left: balanceAfterPurchaseTextLabel.right;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ height: paintedHeight;
+ // Style
+ color: (balanceAfterPurchase >= 0) ? hifi.colors.lightGrayText : hifi.colors.redHighlight;
+ // Alignment
+ horizontalAlignment: Text.AlignRight;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ }
+ }
+ //
+ // ITEM DESCRIPTION END
+ //
+
+
+ //
+ // ACTION BUTTONS AND TEXT START
+ //
+ Item {
+ id: checkoutActionButtonsContainer;
+ // Size
+ width: root.width;
+ height: 200;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 8;
+
+ // "Cancel" button
+ HifiControlsUit.Button {
+ id: cancelPurchaseButton;
+ color: hifi.buttons.black;
+ colorScheme: hifi.colorSchemes.dark;
+ anchors.top: parent.top;
+ anchors.topMargin: 3;
+ height: 40;
+ anchors.left: parent.left;
+ anchors.leftMargin: 20;
+ width: parent.width/2 - anchors.leftMargin*2;
+ text: "Cancel"
+ onClicked: {
+ sendToScript({method: 'checkout_cancelClicked', params: itemId});
+ }
+ }
+
+ // "Buy" button
+ HifiControlsUit.Button {
+ id: buyButton;
+ enabled: (balanceAfterPurchase >= 0 && purchasesReceived && balanceReceived) || !itemIsJson;
+ color: hifi.buttons.blue;
+ colorScheme: hifi.colorSchemes.dark;
+ anchors.top: parent.top;
+ anchors.topMargin: 3;
+ height: 40;
+ anchors.right: parent.right;
+ anchors.rightMargin: 20;
+ width: parent.width/2 - anchors.rightMargin*2;
+ text: (itemIsJson ? ((purchasesReceived && balanceReceived) ? (root.alreadyOwned ? "Buy Another" : "Buy"): "--") : "Get Item");
+ onClicked: {
+ if (itemIsJson) {
+ buyButton.enabled = false;
+ commerce.buy(itemId, itemPriceFull);
+ } else {
+ if (urlHandler.canHandleUrl(itemHref)) {
+ urlHandler.handleUrl(itemHref);
+ }
+ }
+ }
+ }
+
+ // "Purchases" button
+ HifiControlsUit.Button {
+ id: goToPurchasesButton;
+ color: hifi.buttons.black;
+ colorScheme: hifi.colorSchemes.dark;
+ anchors.top: buyButton.bottom;
+ anchors.topMargin: 20;
+ anchors.bottomMargin: 7;
+ height: 40;
+ anchors.left: parent.left;
+ anchors.leftMargin: 20;
+ width: parent.width - anchors.leftMargin*2;
+ text: "View Purchases"
+ onClicked: {
+ sendToScript({method: 'checkout_goToPurchases'});
+ }
+ }
+
+ RalewayRegular {
+ id: buyText;
+ // Text size
+ size: 20;
+ // Anchors
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 10;
+ height: paintedHeight;
+ anchors.left: parent.left;
+ anchors.leftMargin: 10;
+ anchors.right: parent.right;
+ anchors.rightMargin: 10;
+ // Style
+ color: hifi.colors.faintGray;
+ wrapMode: Text.WordWrap;
+ // Alignment
+ horizontalAlignment: Text.AlignHCenter;
+ verticalAlignment: Text.AlignVCenter;
+ }
+ }
+ //
+ // ACTION BUTTONS END
+ //
+ }
+ //
+ // CHECKOUT CONTENTS END
+ //
+
+ //
+ // CHECKOUT SUCCESS START
+ //
+ Item {
+ id: checkoutSuccess;
+ visible: root.activeView === "checkoutSuccess";
+ anchors.top: titleBarContainer.bottom;
+ anchors.bottom: root.bottom;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+
+ RalewayRegular {
+ id: completeText;
+ text: "Purchase Complete!
You bought " + (itemNameText.text) + " by " + (itemAuthorText.text) + "";
+ // Text size
+ size: 24;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.topMargin: 40;
+ height: paintedHeight;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ // Style
+ color: hifi.colors.faintGray;
+ wrapMode: Text.WordWrap;
+ // Alignment
+ horizontalAlignment: Text.AlignHCenter;
+ verticalAlignment: Text.AlignVCenter;
+ }
+
+ Item {
+ id: checkoutSuccessActionButtonsContainer;
+ // Size
+ width: root.width;
+ height: 70;
+ // Anchors
+ anchors.top: completeText.bottom;
+ anchors.topMargin: 30;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+
+ // "Purchases" button
+ HifiControlsUit.Button {
+ id: purchasesButton;
+ 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: "View Purchases";
+ onClicked: {
+ sendToScript({method: 'checkout_goToPurchases'});
+ }
+ }
+
+ // "Rez Now!" button
+ HifiControlsUit.Button {
+ id: rezNowButton;
+ 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: "Rez Now!"
+ onClicked: {
+ if (urlHandler.canHandleUrl(itemHref)) {
+ urlHandler.handleUrl(itemHref);
+ }
+ }
+ }
+ }
+
+ Item {
+ id: continueShoppingButtonContainer;
+ // Size
+ width: root.width;
+ height: 70;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 8;
+ // "Continue Shopping" button
+ HifiControlsUit.Button {
+ id: continueShoppingButton;
+ 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.rightMargin*2;
+ text: "Continue Shopping";
+ onClicked: {
+ sendToScript({method: 'checkout_continueShopping', itemId: itemId});
+ }
+ }
+ }
+ }
+ //
+ // CHECKOUT SUCCESS END
+ //
+
+ //
+ // CHECKOUT FAILURE START
+ //
+ Item {
+ id: checkoutFailure;
+ visible: root.activeView === "checkoutFailure";
+ anchors.top: titleBarContainer.bottom;
+ anchors.bottom: root.bottom;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+
+ RalewayRegular {
+ id: failureHeaderText;
+ text: "Purchase Failed.
Your Purchases and HFC balance haven't changed.";
+ // Text size
+ size: 24;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.topMargin: 80;
+ height: paintedHeight;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ // Style
+ color: hifi.colors.faintGray;
+ wrapMode: Text.WordWrap;
+ // Alignment
+ horizontalAlignment: Text.AlignHCenter;
+ verticalAlignment: Text.AlignVCenter;
+ }
+
+ RalewayRegular {
+ id: failureErrorText;
+ // Text size
+ size: 16;
+ // Anchors
+ anchors.top: failureHeaderText.bottom;
+ anchors.topMargin: 35;
+ height: paintedHeight;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ // Style
+ color: hifi.colors.faintGray;
+ wrapMode: Text.WordWrap;
+ // Alignment
+ horizontalAlignment: Text.AlignHCenter;
+ verticalAlignment: Text.AlignVCenter;
+ }
+
+ Item {
+ id: backToMarketplaceButtonContainer;
+ // Size
+ width: root.width;
+ height: 130;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 8;
+ // "Back to Marketplace" button
+ HifiControlsUit.Button {
+ id: backToMarketplaceButton;
+ color: hifi.buttons.black;
+ 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: "Back to Marketplace";
+ onClicked: {
+ sendToScript({method: 'checkout_continueShopping', itemId: itemId});
+ }
+ }
+ }
+ }
+ //
+ // CHECKOUT FAILURE END
+ //
+
+ //
+ // FUNCTION DEFINITIONS START
+ //
+ //
+ // Function Name: fromScript()
+ //
+ // Relevant Variables:
+ // None
+ //
+ // Arguments:
+ // message: The message sent from the JavaScript, in this case the Marketplaces JavaScript.
+ // Messages are in format "{method, params}", like json-rpc.
+ //
+ // Description:
+ // Called when a message is received from a script.
+ //
+ function fromScript(message) {
+ switch (message.method) {
+ case 'updateCheckoutQML':
+ itemId = message.params.itemId;
+ itemNameText.text = message.params.itemName;
+ itemAuthorText.text = message.params.itemAuthor;
+ root.itemPriceFull = message.params.itemPrice;
+ itemPriceText.text = root.itemPriceFull === 0 ? "Free" : "" + (parseFloat(root.itemPriceFull/100).toFixed(2)) + " HFC";
+ itemHref = message.params.itemHref;
+ if (itemHref.indexOf('.json') === -1) {
+ root.itemIsJson = false;
+ }
+ setBuyText();
+ break;
+ default:
+ console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
+ }
+ }
+ signal sendToScript(var message);
+
+ function purchasesContains(purchasesJson, id) {
+ for (var idx = 0; idx < purchasesJson.length; idx++) {
+ if(purchasesJson[idx].id === id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function setBuyText() {
+ if (root.itemIsJson) {
+ 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.";
+ } else {
+ buyText.text = "You do not have enough HFC to purchase this item.";
+ }
+ } else {
+ if (root.alreadyOwned) {
+ buyText.text = "You already own this item. If you buy it again, you'll be able to use multiple copies of it at once.";
+ } else {
+ buyText.text = "This item will be added to your Purchases, which can be accessed from Marketplace.";
+ }
+ }
+ } else {
+ buyText.text = "";
+ }
+ } else {
+ buyText.text = "This Marketplace item isn't an entity. It will not be added to your Purchases.";
+ }
+ }
+
+ //
+ // FUNCTION DEFINITIONS END
+ //
+}
diff --git a/interface/resources/qml/hifi/commerce/images/02car.jpg b/interface/resources/qml/hifi/commerce/images/02car.jpg
deleted file mode 100644
index 5dd8091e57..0000000000
Binary files a/interface/resources/qml/hifi/commerce/images/02car.jpg and /dev/null differ
diff --git a/interface/resources/qml/hifi/commerce/images/04stars.jpg b/interface/resources/qml/hifi/commerce/images/04stars.jpg
deleted file mode 100644
index 8f2bf62f83..0000000000
Binary files a/interface/resources/qml/hifi/commerce/images/04stars.jpg and /dev/null differ
diff --git a/interface/resources/qml/hifi/commerce/images/05plane.jpg b/interface/resources/qml/hifi/commerce/images/05plane.jpg
deleted file mode 100644
index 6504459d8b..0000000000
Binary files a/interface/resources/qml/hifi/commerce/images/05plane.jpg and /dev/null differ
diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
new file mode 100644
index 0000000000..af32f5cfb7
--- /dev/null
+++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml
@@ -0,0 +1,143 @@
+//
+// PurchasedItem.qml
+// qml/hifi/commerce/purchases
+//
+// PurchasedItem
+//
+// Created by Zach Fox on 2017-08-25
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import Hifi 1.0 as Hifi
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import "../../../styles-uit"
+import "../../../controls-uit" as HifiControlsUit
+import "../../../controls" as HifiControls
+import "../wallet" as HifiWallet
+
+// references XXX from root context
+
+Rectangle {
+ HifiConstants { id: hifi; }
+
+ id: root;
+ property string itemName: "";
+ property string itemId: "";
+ property string itemPreviewImageUrl: "";
+ property string itemHref: "";
+ // Style
+ color: hifi.colors.white;
+ // Size
+ width: parent.width;
+ height: 120;
+
+ Image {
+ id: itemPreviewImage;
+ source: root.itemPreviewImageUrl;
+ anchors.left: parent.left;
+ anchors.leftMargin: 8;
+ anchors.top: parent.top;
+ anchors.topMargin: 8;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 8;
+ width: 180;
+ fillMode: Image.PreserveAspectFit;
+
+ MouseArea {
+ anchors.fill: parent;
+ onClicked: {
+ sendToPurchases({method: 'purchases_itemInfoClicked', itemId: root.itemId});
+ }
+ }
+ }
+
+
+ RalewayRegular {
+ id: itemName;
+ anchors.top: itemPreviewImage.top;
+ anchors.left: itemPreviewImage.right;
+ anchors.leftMargin: 8;
+ anchors.right: parent.right;
+ anchors.rightMargin: 8;
+ height: 30;
+ // Text size
+ size: 20;
+ // Style
+ color: hifi.colors.blueAccent;
+ text: root.itemName;
+ elide: Text.ElideRight;
+ // Alignment
+ horizontalAlignment: Text.AlignLeft;
+ verticalAlignment: Text.AlignVCenter;
+
+ MouseArea {
+ anchors.fill: parent;
+ hoverEnabled: enabled;
+ onClicked: {
+ sendToPurchases({method: 'purchases_itemInfoClicked', itemId: root.itemId});
+ }
+ onEntered: {
+ itemName.color = hifi.colors.blueHighlight;
+ }
+ onExited: {
+ itemName.color = hifi.colors.blueAccent;
+ }
+ }
+ }
+
+ Item {
+ id: buttonContainer;
+ anchors.top: itemName.bottom;
+ anchors.topMargin: 8;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 8;
+ anchors.left: itemPreviewImage.right;
+ anchors.leftMargin: 8;
+ anchors.right: parent.right;
+ anchors.rightMargin: 8;
+
+ // "Rez" button
+ HifiControlsUit.Button {
+ id: rezButton;
+ color: hifi.buttons.blue;
+ colorScheme: hifi.colorSchemes.dark;
+ anchors.top: parent.top;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ height: parent.height/2 - 4;
+ text: "Rez Item"
+ onClicked: {
+ if (urlHandler.canHandleUrl(root.itemHref)) {
+ urlHandler.handleUrl(root.itemHref);
+ }
+ }
+ }
+
+ // "More Info" button
+ HifiControlsUit.Button {
+ id: moreInfoButton;
+ color: hifi.buttons.black;
+ colorScheme: hifi.colorSchemes.dark;
+ anchors.bottom: parent.bottom;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ height: parent.height/2 - 4;
+ text: "More Info"
+ onClicked: {
+ sendToPurchases({method: 'purchases_itemInfoClicked', itemId: root.itemId});
+ }
+ }
+ }
+
+ //
+ // FUNCTION DEFINITIONS START
+ //
+ signal sendToPurchases(var msg);
+ //
+ // FUNCTION DEFINITIONS END
+ //
+}
diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
new file mode 100644
index 0000000000..bc843a140d
--- /dev/null
+++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml
@@ -0,0 +1,505 @@
+//
+// Purchases.qml
+// qml/hifi/commerce/purchases
+//
+// Purchases
+//
+// Created by Zach Fox on 2017-08-25
+// Copyright 2017 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+import Hifi 1.0 as Hifi
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import "../../../styles-uit"
+import "../../../controls-uit" as HifiControlsUit
+import "../../../controls" as HifiControls
+import "../wallet" as HifiWallet
+
+// references XXX from root context
+
+Rectangle {
+ HifiConstants { id: hifi; }
+
+ id: root;
+ property string activeView: "initialize";
+ 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"
+ root.activeView = "notSetUp";
+ } else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") {
+ root.activeView = "purchasesMain";
+ } else if (exists) {
+ // just set the source again (to be sure the change was noticed)
+ securityImage.source = "";
+ securityImage.source = "image://security/securityImage";
+ }
+ }
+
+ onKeyFilePathIfExistsResult: {
+ keyFilePathIfExistsResultReceived = true;
+ if (path === "" && root.activeView !== "notSetUp") {
+ root.activeView = "notSetUp";
+ } else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
+ root.activeView = "purchasesMain";
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+
+ HifiWallet.SecurityImageModel {
+ id: securityImageModel;
+ }
+
+ //
+ // TITLE BAR START
+ //
+ Item {
+ id: titleBarContainer;
+ visible: !needsLogIn.visible;
+ // Size
+ height: 50;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ anchors.top: parent.top;
+
+ // Title Bar text
+ RalewaySemiBold {
+ id: titleBarText;
+ text: "PURCHASES";
+ // 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;
+ }
+
+ // Security Image (TEMPORARY!)
+ Image {
+ id: securityImage;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.right: parent.right;
+ anchors.verticalCenter: parent.verticalCenter;
+ height: parent.height - 10;
+ width: height;
+ fillMode: Image.PreserveAspectFit;
+ mipmap: true;
+ 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 {
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ anchors.bottom: parent.bottom;
+ }
+ }
+ //
+ // TITLE BAR END
+ //
+
+ Rectangle {
+ id: initialize;
+ visible: root.activeView === "initialize";
+ anchors.top: titleBarContainer.bottom;
+ anchors.bottom: parent.bottom;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+ color: hifi.colors.baseGray;
+
+ Component.onCompleted: {
+ 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();
+ }
+ }
+
+ //
+ // "WALLET NOT SET UP" START
+ //
+ Item {
+ id: notSetUp;
+ visible: root.activeView === "notSetUp";
+ anchors.top: titleBarContainer.bottom;
+ anchors.bottom: parent.bottom;
+ anchors.left: parent.left;
+ anchors.right: parent.right;
+
+ RalewayRegular {
+ id: notSetUpText;
+ text: "Your wallet isn't set up.
Set up your Wallet (no credit card necessary) to claim your free HFC " +
+ "and get items from the Marketplace.";
+ // Text size
+ size: 24;
+ // Anchors
+ anchors.top: parent.top;
+ anchors.bottom: notSetUpActionButtonsContainer.top;
+ anchors.left: parent.left;
+ anchors.leftMargin: 16;
+ anchors.right: parent.right;
+ anchors.rightMargin: 16;
+ // Style
+ color: hifi.colors.faintGray;
+ wrapMode: Text.WordWrap;
+ // Alignment
+ horizontalAlignment: Text.AlignHCenter;
+ verticalAlignment: Text.AlignVCenter;
+ }
+
+ Item {
+ id: notSetUpActionButtonsContainer;
+ // Size
+ width: root.width;
+ height: 70;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.bottom: parent.bottom;
+ anchors.bottomMargin: 24;
+
+ // "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: 'purchases_backClicked', referrerURL: referrerURL});
+ }
+ }
+
+ // "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: "Set Up Wallet"
+ onClicked: {
+ sendToScript({method: 'checkout_setUpClicked'});
+ }
+ }
+ }
+ }
+ //
+ // "WALLET NOT SET UP" END
+ //
+
+ //
+ // PURCHASES CONTENTS START
+ //
+ Item {
+ id: purchasesContentsContainer;
+ visible: root.activeView === "purchasesMain";
+ // Anchors
+ anchors.left: parent.left;
+ anchors.leftMargin: 4;
+ anchors.right: parent.right;
+ anchors.rightMargin: 4;
+ anchors.top: titleBarContainer.bottom;
+ anchors.topMargin: 8;
+ anchors.bottom: actionButtonsContainer.top;
+ anchors.bottomMargin: 8;
+
+ //
+ // FILTER BAR START
+ //
+ Item {
+ id: filterBarContainer;
+ // Size
+ height: 40;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.leftMargin: 8;
+ anchors.right: parent.right;
+ anchors.rightMargin: 8;
+ anchors.top: parent.top;
+ anchors.topMargin: 4;
+
+ HifiControlsUit.TextField {
+ id: filterBar;
+ property int previousLength: 0;
+ anchors.fill: parent;
+ placeholderText: "Filter";
+
+ onTextChanged: {
+ if (filterBar.text.length < previousLength) {
+ filteredPurchasesModel.clear();
+
+ for (var i = 0; i < purchasesModel.count; i++) {
+ filteredPurchasesModel.append(purchasesModel.get(i));
+ }
+ }
+
+ for (var i = 0; i < filteredPurchasesModel.count; i++) {
+ if (filteredPurchasesModel.get(i).title.toLowerCase().indexOf(filterBar.text.toLowerCase()) === -1) {
+ filteredPurchasesModel.remove(i);
+ i--;
+ }
+ }
+ previousLength = filterBar.text.length;
+ }
+
+ onAccepted: {
+ focus = false;
+ }
+ }
+ }
+ //
+ // FILTER BAR END
+ //
+
+ ListModel {
+ id: purchasesModel;
+ }
+ ListModel {
+ id: filteredPurchasesModel;
+ }
+
+ ListView {
+ id: purchasesContentsList;
+ visible: purchasesModel.count !== 0;
+ clip: true;
+ model: filteredPurchasesModel;
+ // Anchors
+ anchors.top: filterBarContainer.bottom;
+ anchors.topMargin: 12;
+ anchors.left: parent.left;
+ anchors.bottom: parent.bottom;
+ width: parent.width;
+ delegate: PurchasedItem {
+ itemName: title;
+ itemId: id;
+ itemPreviewImageUrl: preview;
+ itemHref: root_file_url;
+ anchors.topMargin: 12;
+ anchors.bottomMargin: 12;
+
+ Connections {
+ onSendToPurchases: {
+ if (msg.method === 'purchases_itemInfoClicked') {
+ sendToScript({method: 'purchases_itemInfoClicked', itemId: itemId});
+ }
+ }
+ }
+ }
+ }
+
+ 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
+ //
+
+ //
+ // ACTION BUTTONS START
+ //
+ Item {
+ id: actionButtonsContainer;
+ visible: purchasesContentsContainer.visible;
+ // Size
+ width: parent.width;
+ height: 40;
+ // Anchors
+ anchors.left: parent.left;
+ anchors.bottom: keyboard.top;
+ anchors.bottomMargin: 8;
+
+ // "Back" button
+ HifiControlsUit.Button {
+ id: backButton;
+ 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: "Back"
+ onClicked: {
+ sendToScript({method: 'purchases_backClicked', referrerURL: referrerURL});
+ }
+ }
+ }
+ //
+ // ACTION BUTTONS END
+ //
+
+ HifiControlsUit.Keyboard {
+ id: keyboard;
+ raised: HMD.mounted && filterBar.focus;
+ numeric: parent.punctuationMode;
+ anchors {
+ bottom: parent.bottom;
+ left: parent.left;
+ right: parent.right;
+ }
+ }
+
+ //
+ // FUNCTION DEFINITIONS START
+ //
+ //
+ // Function Name: fromScript()
+ //
+ // Relevant Variables:
+ // None
+ //
+ // Arguments:
+ // message: The message sent from the JavaScript, in this case the Marketplaces JavaScript.
+ // Messages are in format "{method, params}", like json-rpc.
+ //
+ // Description:
+ // Called when a message is received from a script.
+ //
+ function fromScript(message) {
+ switch (message.method) {
+ case 'updatePurchases':
+ referrerURL = message.referrerURL;
+ break;
+ default:
+ console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
+ }
+ }
+ signal sendToScript(var message);
+
+ //
+ // FUNCTION DEFINITIONS END
+ //
+}
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..0d46077f2a 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;
+ }
}
}
}
@@ -254,6 +308,7 @@ Rectangle {
//
Item {
id: tabButtonsContainer;
+ visible: !needsLogIn.visible;
property int numTabs: 5;
// Size
width: root.width;
@@ -455,7 +510,47 @@ 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 88f939d393..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;
@@ -39,6 +40,14 @@ Item {
onBalanceResult : {
balanceText.text = parseFloat(result.data.balance/100).toFixed(2);
}
+
+ onHistoryResult : {
+ historyReceived = true;
+ if (result.status === 'success') {
+ transactionHistoryModel.clear();
+ transactionHistoryModel.append(result.data.history);
+ }
+ }
}
SecurityImageModel {
@@ -104,7 +113,9 @@ Item {
onVisibleChanged: {
if (visible) {
+ historyReceived = false;
commerce.balance();
+ commerce.history();
}
}
}
@@ -174,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
@@ -200,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;
@@ -216,116 +236,68 @@ 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.bottom: parent.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
+ color: "white";
- // some placeholder stuff
+ 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
+ }
+ }
+ }
+
+ // This should never be visible (since you immediately get 100 HFC)
RalewayRegular {
- text: homeMessage.visible ? "you CANNOT scroll through this." : "you CAN scroll through this";
- // Text size
- size: 16;
- // Anchors
+ id: emptyTransationHistory;
+ size: 24;
+ visible: !transactionHistory.visible && root.historyReceived;
+ text: "Recent Activity Unavailable";
anchors.fill: parent;
- // Style
- color: hifi.colors.darkGray;
- // Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
}
}
-
- 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;
- }
-
- 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;
- }
- }
- 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;
- }
- }
- }
}
//
@@ -351,6 +323,7 @@ Item {
}
}
signal sendSignalToWallet(var msg);
+
//
// FUNCTION DEFINITIONS END
//
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/images/01cat.jpg b/interface/resources/qml/hifi/commerce/wallet/images/01.jpg
similarity index 100%
rename from interface/resources/qml/hifi/commerce/images/01cat.jpg
rename to interface/resources/qml/hifi/commerce/wallet/images/01.jpg
diff --git a/interface/resources/qml/hifi/commerce/wallet/images/01cat.jpg b/interface/resources/qml/hifi/commerce/wallet/images/01cat.jpg
deleted file mode 100644
index 6e7897cb82..0000000000
Binary files a/interface/resources/qml/hifi/commerce/wallet/images/01cat.jpg and /dev/null differ
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/images/03dog.jpg b/interface/resources/qml/hifi/commerce/wallet/images/03.jpg
similarity index 100%
rename from interface/resources/qml/hifi/commerce/images/03dog.jpg
rename to interface/resources/qml/hifi/commerce/wallet/images/03.jpg
diff --git a/interface/resources/qml/hifi/commerce/wallet/images/03dog.jpg b/interface/resources/qml/hifi/commerce/wallet/images/03dog.jpg
deleted file mode 100644
index 4a85b80c0c..0000000000
Binary files a/interface/resources/qml/hifi/commerce/wallet/images/03dog.jpg and /dev/null differ
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/images/06gingerbread.jpg b/interface/resources/qml/hifi/commerce/wallet/images/06.jpg
similarity index 100%
rename from interface/resources/qml/hifi/commerce/images/06gingerbread.jpg
rename to interface/resources/qml/hifi/commerce/wallet/images/06.jpg
diff --git a/interface/resources/qml/hifi/commerce/wallet/images/06gingerbread.jpg b/interface/resources/qml/hifi/commerce/wallet/images/06gingerbread.jpg
deleted file mode 100644
index 54c37faa2f..0000000000
Binary files a/interface/resources/qml/hifi/commerce/wallet/images/06gingerbread.jpg and /dev/null differ
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/tablet/TabletMenuItem.qml b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml
index 25f672e7a9..71e59e0d01 100644
--- a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml
+++ b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml
@@ -26,24 +26,48 @@ Item {
visible: source.visible
width: parent.width
- CheckBox {
+ Item {
id: check
- // FIXME: Should use radio buttons if source.exclusiveGroup.
+
anchors {
left: parent.left
leftMargin: hifi.dimensions.menuPadding.x + 15
verticalCenter: label.verticalCenter
}
- width: 20
- visible: source.visible && source.type === 1 && source.checkable
- checked: setChecked()
- function setChecked() {
- if (!source || source.type !== 1 || !source.checkable) {
- return false;
+
+ width: checkbox.visible ? checkbox.width : radiobutton.width
+ height: checkbox.visible ? checkbox.height : radiobutton.height
+
+ CheckBox {
+ id: checkbox
+ // FIXME: Should use radio buttons if source.exclusiveGroup.
+ width: 20
+ visible: source.visible && source.type === 1 && source.checkable && !source.exclusiveGroup
+ checked: setChecked()
+ function setChecked() {
+ if (!source || source.type !== 1 || !source.checkable) {
+ return false;
+ }
+ // FIXME this works for native QML menus but I don't think it will
+ // for proxied QML menus
+ return source.checked;
+ }
+ }
+
+ RadioButton {
+ id: radiobutton
+ // FIXME: Should use radio buttons if source.exclusiveGroup.
+ width: 20
+ visible: source.visible && source.type === 1 && source.checkable && source.exclusiveGroup
+ checked: setChecked()
+ function setChecked() {
+ if (!source || source.type !== 1 || !source.checkable) {
+ return false;
+ }
+ // FIXME this works for native QML menus but I don't think it will
+ // for proxied QML menus
+ return source.checked;
}
- // FIXME this works for native QML menus but I don't think it will
- // for proxied QML menus
- return source.checked;
}
}
diff --git a/interface/resources/qml/hifi/tablet/TabletMenuStack.qml b/interface/resources/qml/hifi/tablet/TabletMenuStack.qml
index 9076cd6c48..e7eefbc5e7 100644
--- a/interface/resources/qml/hifi/tablet/TabletMenuStack.qml
+++ b/interface/resources/qml/hifi/tablet/TabletMenuStack.qml
@@ -64,8 +64,10 @@ Item {
d.pop();
}
- function toModel(items) {
+ function toModel(items, newMenu) {
var result = modelMaker.createObject(tabletMenu);
+ var exclusionGroups = {};
+
for (var i = 0; i < items.length; ++i) {
var item = items[i];
if (!item.visible) continue;
@@ -77,6 +79,28 @@ Item {
if (item.text !== "Users Online") {
result.append({"name": item.text, "item": item})
}
+
+ for(var j = 0; j < tabletMenu.rootMenu.exclusionGroupsByMenuItem.count; ++j)
+ {
+ var entry = tabletMenu.rootMenu.exclusionGroupsByMenuItem.get(j);
+ if(entry.menuItem == item.toString())
+ {
+ var exclusionGroupId = entry.exclusionGroup;
+ console.debug('item exclusionGroupId: ', exclusionGroupId)
+
+ if(!exclusionGroups[exclusionGroupId])
+ {
+ exclusionGroups[exclusionGroupId] = exclusiveGroupMaker.createObject(newMenu);
+ console.debug('new exclusion group created: ', exclusionGroups[exclusionGroupId])
+ }
+
+ var exclusionGroup = exclusionGroups[exclusionGroupId];
+
+ item.exclusiveGroup = exclusionGroup
+ console.debug('item.exclusiveGroup: ', item.exclusiveGroup)
+ }
+ }
+
break;
case MenuItemType.Separator:
result.append({"name": "", "item": item})
@@ -133,10 +157,21 @@ Item {
}
}
+ property Component exclusiveGroupMaker: Component {
+ ExclusiveGroup {
+ }
+ }
+
function buildMenu(items) {
- var model = toModel(items);
// Menus must be childed to desktop for Z-ordering
- var newMenu = menuViewMaker.createObject(tabletMenu, { model: model, isSubMenu: topMenu !== null });
+ var newMenu = menuViewMaker.createObject(tabletMenu);
+ console.debug('newMenu created: ', newMenu)
+
+ var model = toModel(items, newMenu);
+
+ newMenu.model = model;
+ newMenu.isSubMenu = topMenu !== null;
+
pushMenu(newMenu);
return newMenu;
}
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index ba68e68123..88003bb10f 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -184,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"
@@ -265,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;
@@ -1028,6 +1027,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_glWidget->setFocusPolicy(Qt::StrongFocus);
_glWidget->setFocus();
+ if (cmdOptionExists(argc, constArgv, "--system-cursor")) {
+ _preferredCursor.set(Cursor::Manager::getIconName(Cursor::Icon::SYSTEM));
+ }
showCursor(Cursor::Manager::lookupIcon(_preferredCursor.get()));
// enable mouse tracking; otherwise, we only get drag events
@@ -2245,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();
@@ -4550,10 +4550,13 @@ void Application::updateMyAvatarLookAtPosition() {
}
} else {
AvatarSharedPointer lookingAt = myAvatar->getLookAtTargetAvatar().lock();
- if (lookingAt && myAvatar.get() != lookingAt.get()) {
+ bool haveLookAtCandidate = lookingAt && myAvatar.get() != lookingAt.get();
+ auto avatar = static_pointer_cast(lookingAt);
+ bool mutualLookAtSnappingEnabled = avatar && avatar->getLookAtSnappingEnabled() && myAvatar->getLookAtSnappingEnabled();
+ if (haveLookAtCandidate && mutualLookAtSnappingEnabled) {
// If I am looking at someone else, look directly at one of their eyes
isLookingAtSomeone = true;
- auto lookingAtHead = static_pointer_cast(lookingAt)->getHead();
+ auto lookingAtHead = avatar->getHead();
const float MAXIMUM_FACE_ANGLE = 65.0f * RADIANS_PER_DEGREE;
glm::vec3 lookingAtFaceOrientation = lookingAtHead->getFinalOrientationInWorldFrame() * IDENTITY_FORWARD;
@@ -5167,7 +5170,7 @@ void Application::update(float deltaTime) {
}
} else {
// update the rendering without any simulation
- getEntities()->update(false);
+ getEntities()->update(false);
}
// AvatarManager update
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index 2c4a515736..005d478411 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -56,6 +56,8 @@ Menu* Menu::getInstance() {
return dynamic_cast