diff --git a/interface/resources/icons/tablet-icons/wallet-a.svg b/interface/resources/icons/tablet-icons/wallet-a.svg new file mode 100644 index 0000000000..4a0bab4b33 --- /dev/null +++ b/interface/resources/icons/tablet-icons/wallet-a.svg @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + HFC + diff --git a/interface/resources/icons/tablet-icons/wallet-i.svg b/interface/resources/icons/tablet-icons/wallet-i.svg new file mode 100644 index 0000000000..2a16ecf973 --- /dev/null +++ b/interface/resources/icons/tablet-icons/wallet-i.svg @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + HFC + diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml new file mode 100644 index 0000000000..2252cbfb59 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/Help.qml @@ -0,0 +1,73 @@ +// +// SendMoney.qml +// qml/hifi/commerce/wallet +// +// SendMoney +// +// 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; + } + + // "Unavailable" + RalewayRegular { + text: "Help me!"; + // Anchors + anchors.fill: parent; + // Text size + size: 24; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + + // + // 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 new file mode 100644 index 0000000000..3efb592ba1 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/NotSetUp.qml @@ -0,0 +1,127 @@ +// +// NotSetUp.qml +// qml/hifi/commerce/wallet +// +// NotSetUp +// +// 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; + } + + // + // TAB CONTENTS START + // + + // Text below title bar + RalewaySemiBold { + id: notSetUpText; + text: "Your Wallet Account Has Not Been Set Up"; + // Text size + size: 22; + // Anchors + anchors.top: parent.top; + anchors.topMargin: 100; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: 50; + width: paintedWidth; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + + // Explanitory text + RalewayRegular { + text: "To buy and sell items in High Fidelity Coin (HFC), you first need " + + "to set up your wallet.
You do not need to submit a credit card or personal information to set up your wallet."; + // Text size + size: 18; + // Anchors + anchors.top: notSetUpText.bottom; + anchors.topMargin: 16; + anchors.left: parent.left; + anchors.leftMargin: 30; + anchors.right: parent.right; + anchors.rightMargin: 30; + height: 100; + width: paintedWidth; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + + // "Set Up" button + HifiControlsUit.Button { + color: hifi.buttons.black; + colorScheme: hifi.colorSchemes.dark; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 150; + anchors.horizontalCenter: parent.horizontalCenter; + width: parent.width/2; + height: 50; + text: "Set Up My Wallet"; + onClicked: { + sendSignalToWallet({method: 'setUpClicked'}); + } + } + + + // + // TAB CONTENTS 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/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml new file mode 100644 index 0000000000..ff01aa65da --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -0,0 +1,230 @@ +// +// PassphraseSelection.qml +// qml/hifi/commerce/wallet +// +// PassphraseSelection +// +// 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; + + // This object is always used in a popup. + // This MouseArea is used to prevent a user from being + // able to click on a button/mouseArea underneath the popup. + MouseArea { + anchors.fill: parent; + propagateComposedEvents: false; + } + + Hifi.QmlCommerce { + id: commerce; + onSecurityImageResult: { + passphrasePageSecurityImage.source = gridModel.getImagePathFromImageID(imageID); + } + + onPassphraseSetupStatusResult: { + sendMessageToLightbox({method: 'statusResult', status: passphraseIsSetup}); + } + } + + onVisibleChanged: { + if (visible) { + passphraseField.focus = true; + } + } + + SecurityImageModel { + id: gridModel; + } + + HifiControlsUit.TextField { + id: passphraseField; + anchors.top: parent.top; + anchors.topMargin: 30; + anchors.left: parent.left; + anchors.leftMargin: 16; + width: 280; + height: 50; + echoMode: TextInput.Password; + placeholderText: "passphrase"; + + onVisibleChanged: { + if (visible) { + text = ""; + } + } + } + HifiControlsUit.TextField { + id: passphraseFieldAgain; + anchors.top: passphraseField.bottom; + anchors.topMargin: 10; + anchors.left: passphraseField.left; + anchors.right: passphraseField.right; + height: 50; + echoMode: TextInput.Password; + placeholderText: "re-enter passphrase"; + + onVisibleChanged: { + if (visible) { + text = ""; + } + } + } + + // Security Image + Item { + id: securityImageContainer; + // Anchors + anchors.top: passphraseField.top; + anchors.left: passphraseField.right; + anchors.leftMargin: 12; + anchors.right: parent.right; + Image { + id: passphrasePageSecurityImage; + anchors.top: parent.top; + anchors.horizontalCenter: parent.horizontalCenter; + height: 75; + width: height; + fillMode: Image.PreserveAspectFit; + mipmap: true; + + onVisibleChanged: { + commerce.getSecurityImage(); + } + } + // "Security picture" text below pic + RalewayRegular { + text: "security picture"; + // Text size + size: 12; + // Anchors + anchors.top: passphrasePageSecurityImage.bottom; + anchors.topMargin: 4; + anchors.left: securityImageContainer.left; + anchors.right: securityImageContainer.right; + height: paintedHeight; + // Style + color: hifi.colors.faintGray; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + } + + // Error text below TextFields + RalewaySemiBold { + id: errorText; + text: ""; + // Text size + size: 16; + // Anchors + anchors.top: passphraseFieldAgain.bottom; + anchors.topMargin: 0; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: 30; + // Style + color: hifi.colors.redHighlight; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // Text below TextFields + RalewaySemiBold { + id: passwordReqs; + text: "Passphrase must be at least 4 characters"; + // Text size + size: 16; + // Anchors + anchors.top: passphraseFieldAgain.bottom; + anchors.topMargin: 16; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: 30; + // Style + color: hifi.colors.faintGray; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // Show passphrase text + HifiControlsUit.CheckBox { + id: showPassphrase; + colorScheme: hifi.colorSchemes.dark; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.top: passwordReqs.bottom; + anchors.topMargin: 16; + height: 30; + text: "Show passphrase as plain text"; + boxSize: 24; + onClicked: { + passphraseField.echoMode = checked ? TextInput.Normal : TextInput.Password; + passphraseFieldAgain.echoMode = checked ? TextInput.Normal : TextInput.Password; + } + } + + // Text below checkbox + RalewayRegular { + text: "Your passphrase is used to encrypt your private keys. Please write it down. If it is lost, you will not be able to recover it."; + // Text size + size: 16; + // Anchors + anchors.top: showPassphrase.bottom; + anchors.topMargin: 16; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: paintedHeight; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignVCenter; + } + + function validateAndSubmitPassphrase() { + if (passphraseField.text.length < 4) { + setErrorText("Passphrase too short."); + return false; + } else if (passphraseField.text !== passphraseFieldAgain.text) { + setErrorText("Passphrases don't match."); + return false; + } else { + setErrorText(""); + commerce.setPassphrase(passphraseField.text); + return true; + } + } + + function setErrorText(text) { + errorText.text = text; + } + + signal sendMessageToLightbox(var msg); +} diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelectionLightbox.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelectionLightbox.qml new file mode 100644 index 0000000000..862d1894db --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelectionLightbox.qml @@ -0,0 +1,175 @@ +// +// PassphraseSelectionLightbox.qml +// qml/hifi/commerce/wallet +// +// PassphraseSelectionLightbox +// +// 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 + +Rectangle { + HifiConstants { id: hifi; } + + id: root; + // 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 + // + Item { + id: choosePassphraseContainer; + // Anchors + anchors.fill: parent; + + Item { + id: passphraseTitle; + // Size + width: parent.width; + height: 50; + // Anchors + anchors.left: parent.left; + anchors.top: parent.top; + + // Title Bar text + RalewaySemiBold { + text: "CHANGE PASSPHRASE"; + // 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: passphraseTitleHelper; + text: "Choose a Secure Passphrase"; + // Text size + size: 24; + // Anchors + anchors.top: passphraseTitle.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; + } + + PassphraseSelection { + id: passphraseSelection; + anchors.top: passphraseTitleHelper.bottom; + anchors.topMargin: 30; + anchors.left: parent.left; + anchors.right: parent.right; + anchors.bottom: passphraseNavBar.top; + } + + // Navigation Bar + Item { + id: passphraseNavBar; + // 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: { + root.visible = false; + } + } + + // "Submit" button + HifiControlsUit.Button { + id: passphraseSubmitButton; + 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: 100; + text: "Submit"; + onClicked: { + if (passphraseSelection.validateAndSubmitPassphrase()) { + passphraseSubmitButton.text = "Submitting..."; + passphraseSubmitButton.enabled = false; + } + } + } + } + } + // + // SECURE PASSPHRASE SELECTION END + // + + function resetSubmitButton() { + passphraseSubmitButton.enabled = true; + passphraseSubmitButton.text = "Submit"; + } +} diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml new file mode 100644 index 0000000000..7fc3d9324f --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -0,0 +1,312 @@ +// +// Security.qml +// qml/hifi/commerce/wallet +// +// Security +// +// 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; + + onSecurityImageResult: { + if (imageID !== 0) { // "If security image is set up" + var path = securityImageModel.getImagePathFromImageID(imageID); + topSecurityImage.source = path; + changeSecurityImageImage.source = path; + } + } + + onKeyFilePathResult: { + if (path !== "") { + keyFilePath.text = path; + } + } + } + + SecurityImageModel { + id: securityImageModel; + } + + // Username Text + RalewayRegular { + id: usernameText; + text: Account.username; + // Text size + size: 24; + // Style + color: hifi.colors.faintGray; + elide: Text.ElideRight; + // Anchors + anchors.top: securityImageContainer.top; + anchors.bottom: securityImageContainer.bottom; + anchors.left: parent.left; + anchors.right: securityImageContainer.left; + } + + // Security Image + Item { + id: securityImageContainer; + // Anchors + anchors.top: parent.top; + anchors.right: parent.right; + width: 75; + height: childrenRect.height; + + onVisibleChanged: { + if (visible) { + commerce.getSecurityImage(); + } + } + + Image { + id: topSecurityImage; + // Anchors + anchors.top: parent.top; + anchors.horizontalCenter: parent.horizontalCenter; + height: parent.width - 10; + width: height; + fillMode: Image.PreserveAspectFit; + mipmap: true; + } + // "Security picture" text below pic + RalewayRegular { + text: "security picture"; + // Text size + size: 12; + // Anchors + anchors.top: topSecurityImage.bottom; + anchors.topMargin: 4; + anchors.left: securityImageContainer.left; + anchors.right: securityImageContainer.right; + height: paintedHeight; + // Style + color: hifi.colors.faintGray; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + } + + Item { + id: securityContainer; + anchors.top: securityImageContainer.bottom; + anchors.topMargin: 20; + anchors.left: parent.left; + anchors.right: parent.right; + height: childrenRect.height; + + RalewayRegular { + id: securityText; + text: "Security"; + // Anchors + anchors.top: parent.top; + anchors.left: parent.left; + anchors.right: parent.right; + height: 30; + // Text size + size: 22; + // Style + color: hifi.colors.faintGray; + } + + Item { + id: changePassphraseContainer; + anchors.top: securityText.bottom; + anchors.topMargin: 16; + anchors.left: parent.left; + anchors.right: parent.right; + height: 75; + + Image { + id: changePassphraseImage; + // Anchors + anchors.top: parent.top; + anchors.left: parent.left; + height: parent.height; + width: height; + fillMode: Image.PreserveAspectFit; + mipmap: true; + } + // "Change Passphrase" button + HifiControlsUit.Button { + id: changePassphraseButton; + color: hifi.buttons.black; + colorScheme: hifi.colorSchemes.dark; + anchors.verticalCenter: parent.verticalCenter; + anchors.left: changePassphraseImage.right; + anchors.leftMargin: 16; + width: 250; + height: 50; + text: "Change My Passphrase"; + onClicked: { + sendSignalToWallet({method: 'walletSecurity_changePassphrase'}); + } + } + } + + Item { + id: changeSecurityImageContainer; + anchors.top: changePassphraseContainer.bottom; + anchors.topMargin: 8; + anchors.left: parent.left; + anchors.right: parent.right; + height: 75; + + Image { + id: changeSecurityImageImage; + // Anchors + anchors.top: parent.top; + anchors.left: parent.left; + height: parent.height; + width: height; + fillMode: Image.PreserveAspectFit; + mipmap: true; + } + // "Change Security Image" button + HifiControlsUit.Button { + id: changeSecurityImageButton; + color: hifi.buttons.black; + colorScheme: hifi.colorSchemes.dark; + anchors.verticalCenter: parent.verticalCenter; + anchors.left: changeSecurityImageImage.right; + anchors.leftMargin: 16; + width: 250; + height: 50; + text: "Change My Security Image"; + onClicked: { + sendSignalToWallet({method: 'walletSecurity_changeSecurityImage'}); + } + } + } + } + + Item { + id: yourPrivateKeysContainer; + anchors.top: securityContainer.bottom; + anchors.topMargin: 20; + anchors.left: parent.left; + anchors.right: parent.right; + height: childrenRect.height; + + RalewaySemiBold { + id: yourPrivateKeysText; + text: "Your Private Keys"; + // Anchors + anchors.top: parent.top; + anchors.left: parent.left; + anchors.right: parent.right; + height: 30; + // Text size + size: 22; + // Style + color: hifi.colors.faintGray; + } + + // Text below "your private keys" + RalewayRegular { + id: explanitoryText; + text: "Your money and purchases are secured with private keys that only you " + + "have access to. If they are lost, you will not be able to access your money or purchases. " + + "To safeguard your private keys, back up this file regularly:"; + // Text size + size: 18; + // Anchors + anchors.top: yourPrivateKeysText.bottom; + anchors.topMargin: 10; + anchors.left: parent.left; + anchors.right: parent.right; + height: paintedHeight; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignVCenter; + } + HifiControlsUit.TextField { + id: keyFilePath; + anchors.top: explanitoryText.bottom; + anchors.topMargin: 10; + anchors.left: parent.left; + anchors.right: clipboardButton.left; + height: 40; + readOnly: true; + + onVisibleChanged: { + if (visible) { + commerce.getKeyFilePath(); + } + } + } + HifiControlsUit.Button { + id: clipboardButton; + color: hifi.buttons.black; + colorScheme: hifi.colorSchemes.dark; + anchors.right: parent.right; + anchors.top: keyFilePath.top; + anchors.bottom: keyFilePath.bottom; + width: height; + HiFiGlyphs { + text: hifi.glyphs.question; + // Size + size: parent.height*1.3; + // Anchors + anchors.fill: parent; + // Style + horizontalAlignment: Text.AlignHCenter; + color: enabled ? hifi.colors.white : hifi.colors.faintGray; + } + + onClicked: { + Window.copyToClipboard(keyFilePath.text); + } + } + } + + // + // 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/SecurityImageModel.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageModel.qml new file mode 100644 index 0000000000..b49f16857b --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageModel.qml @@ -0,0 +1,46 @@ +// +// SecurityImageModel.qml +// qml/hifi/commerce +// +// SecurityImageModel +// +// Created by Zach Fox on 2017-08-17 +// 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 QtQuick 2.5 + +ListModel { + id: root; + ListElement{ + sourcePath: "images/01cat.jpg" + securityImageEnumValue: 1; + } + ListElement{ + sourcePath: "images/02car.jpg" + securityImageEnumValue: 2; + } + ListElement{ + sourcePath: "images/03dog.jpg" + securityImageEnumValue: 3; + } + ListElement{ + sourcePath: "images/04stars.jpg" + securityImageEnumValue: 4; + } + ListElement{ + sourcePath: "images/05plane.jpg" + securityImageEnumValue: 5; + } + ListElement{ + sourcePath: "images/06gingerbread.jpg" + securityImageEnumValue: 6; + } + + function getImagePathFromImageID(imageID) { + return (imageID ? root.get(imageID - 1).sourcePath : ""); + } +} diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml new file mode 100644 index 0000000000..0d64217717 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml @@ -0,0 +1,107 @@ +// +// SecurityImageSelection.qml +// qml/hifi/commerce/wallet +// +// SecurityImageSelection +// +// Created by Zach Fox on 2017-08-17 +// 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; + onSecurityImageResult: { + if (imageID > 0) { + for (var itr = 0; itr < gridModel.count; itr++) { + var thisValue = gridModel.get(itr).securityImageEnumValue; + if (thisValue === imageID) { + securityImageGrid.currentIndex = itr; + break; + } + } + } + } + } + + onVisibleChanged: { + if (visible) { + commerce.getSecurityImage(); + } + } + + SecurityImageModel { + id: gridModel; + } + + GridView { + id: securityImageGrid; + clip: true; + // Anchors + anchors.fill: parent; + currentIndex: -1; + cellWidth: width / 3; + cellHeight: height / 2; + model: gridModel; + delegate: Item { + width: securityImageGrid.cellWidth; + height: securityImageGrid.cellHeight; + Item { + anchors.fill: parent; + Image { + width: parent.width - 8; + height: parent.height - 8; + source: sourcePath; + anchors.horizontalCenter: parent.horizontalCenter; + anchors.verticalCenter: parent.verticalCenter; + fillMode: Image.PreserveAspectFit; + mipmap: true; + } + } + MouseArea { + anchors.fill: parent; + propagateComposedEvents: false; + onClicked: { + securityImageGrid.currentIndex = index; + } + } + } + highlight: Rectangle { + width: securityImageGrid.cellWidth; + height: securityImageGrid.cellHeight; + color: hifi.colors.blueHighlight; + } + } + + // + // FUNCTION DEFINITIONS START + // + signal sendToScript(var message); + + function getImagePathFromImageID(imageID) { + return (imageID ? gridModel.getImagePathFromImageID(imageID) : ""); + } + + function getSelectedImageIndex() { + return gridModel.get(securityImageGrid.currentIndex).securityImageEnumValue; + } + // + // FUNCTION DEFINITIONS END + // +} diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml new file mode 100644 index 0000000000..12511d6e6c --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelectionLightbox.qml @@ -0,0 +1,199 @@ +// +// SecurityImageSelectionLightbox.qml +// qml/hifi/commerce/wallet +// +// SecurityImageSelectionLightbox +// +// 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 + +Rectangle { + HifiConstants { id: hifi; } + + id: root; + property bool justSubmitted: false; + // Style + color: hifi.colors.baseGray; + + onVisibleChanged: { + if (visible) { + root.resetSubmitButton(); + } + } + + Hifi.QmlCommerce { + id: commerce; + + onSecurityImageResult: { + if (imageID !== 0) { // Success submitting new security image + if (root.justSubmitted) { + root.resetSubmitButton(); + root.visible = false; + root.justSubmitted = false; + } + } else if (root.justSubmitted) { + // Error submitting new security image. + root.resetSubmitButton(); + root.justSubmitted = false; + } + } + } + + // + // SECURITY IMAGE SELECTION START + // + Item { + id: securityImageContainer; + // Anchors + anchors.fill: parent; + + Item { + id: securityImageTitle; + // Size + width: parent.width; + height: 50; + // Anchors + anchors.left: parent.left; + anchors.top: parent.top; + + // Title Bar text + RalewaySemiBold { + text: "CHANGE SECURITY IMAGE"; + // 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: securityImageTitleHelper; + text: "Choose a Security Picture:"; + // Text size + size: 24; + // Anchors + anchors.top: securityImageTitle.bottom; + anchors.left: parent.left; + anchors.leftMargin: 16; + height: 50; + width: paintedWidth; + // Style + color: hifi.colors.faintGray; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + SecurityImageSelection { + id: securityImageSelection; + // Anchors + anchors.top: securityImageTitleHelper.bottom; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: 280; + } + + // Text below security images + RalewayRegular { + text: "Your security picture shows you that the service asking for your passphrase is authorized. You can change your secure picture at any time."; + // Text size + size: 18; + // Anchors + anchors.top: securityImageSelection.bottom; + anchors.topMargin: 40; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: paintedHeight; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // Navigation Bar + Item { + id: securityImageNavBar; + // 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: { + root.visible = false; + } + } + + // "Submit" button + HifiControlsUit.Button { + id: securityImageSubmitButton; + 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: 100; + text: "Submit"; + onClicked: { + root.justSubmitted = true; + securityImageSubmitButton.text = "Submitting..."; + securityImageSubmitButton.enabled = false; + commerce.chooseSecurityImage(securityImageSelection.getSelectedImageIndex()); + } + } + } + } + // + // SECURITY IMAGE SELECTION END + // + + function resetSubmitButton() { + securityImageSubmitButton.enabled = true; + securityImageSubmitButton.text = "Submit"; + } +} diff --git a/interface/resources/qml/hifi/commerce/wallet/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/SendMoney.qml new file mode 100644 index 0000000000..75334b1686 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/SendMoney.qml @@ -0,0 +1,73 @@ +// +// SendMoney.qml +// qml/hifi/commerce/wallet +// +// SendMoney +// +// 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; + } + + // "Unavailable" + RalewayRegular { + text: "You currently cannot send money to other High Fidelity users."; + // Anchors + anchors.fill: parent; + // Text size + size: 24; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + + // + // 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/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml new file mode 100644 index 0000000000..23989f0db5 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -0,0 +1,479 @@ +// +// Wallet.qml +// qml/hifi/commerce/wallet +// +// Wallet +// +// Created by Zach Fox on 2017-08-17 +// 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 + +Rectangle { + HifiConstants { id: hifi; } + + id: root; + + property string activeView: "walletHome"; + + // Style + color: hifi.colors.baseGray; + Hifi.QmlCommerce { + id: commerce; + + onSecurityImageResult: { + if (imageID === 0) { // "If security image is not set up" + if (root.activeView !== "notSetUp") { + root.activeView = "notSetUp"; + } + } + } + + onKeyFilePathResult: { + if (path === "" && root.activeView !== "notSetUp") { + root.activeView = "notSetUp"; + } + } + } + + SecurityImageModel { + 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; + z: 998; + anchors.fill: parent; + color: "black"; + opacity: 0.5; + } + WalletSetupLightbox { + id: walletSetupLightbox; + visible: false; + z: 999; + anchors.centerIn: walletSetupLightboxContainer; + width: walletSetupLightboxContainer.width - 50; + height: walletSetupLightboxContainer.height - 50; + } + PassphraseSelectionLightbox { + id: passphraseSelectionLightbox; + visible: false; + z: 999; + anchors.centerIn: walletSetupLightboxContainer; + width: walletSetupLightboxContainer.width - 50; + height: walletSetupLightboxContainer.height - 50; + } + SecurityImageSelectionLightbox { + id: securityImageSelectionLightbox; + visible: false; + z: 999; + anchors.centerIn: walletSetupLightboxContainer; + width: walletSetupLightboxContainer.width - 50; + height: walletSetupLightboxContainer.height - 50; + } + + + // + // 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: "WALLET"; + // 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; + } + + // Separator + HifiControlsUit.Separator { + anchors.left: parent.left; + anchors.right: parent.right; + anchors.bottom: parent.bottom; + } + } + // + // TITLE BAR END + // + + // + // TAB CONTENTS START + // + NotSetUp { + id: notSetUp; + visible: root.activeView === "notSetUp"; + anchors.top: titleBarContainer.bottom; + anchors.bottom: tabButtonsContainer.top; + anchors.left: parent.left; + anchors.right: parent.right; + } + + WalletHome { + id: walletHome; + visible: root.activeView === "walletHome"; + anchors.top: titleBarContainer.bottom; + anchors.topMargin: 16; + anchors.bottom: tabButtonsContainer.top; + anchors.bottomMargin: 16; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + } + + SendMoney { + id: sendMoney; + visible: root.activeView === "sendMoney"; + anchors.top: titleBarContainer.bottom; + anchors.topMargin: 16; + anchors.bottom: tabButtonsContainer.top; + anchors.bottomMargin: 16; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + } + + Security { + id: security; + visible: root.activeView === "security"; + anchors.top: titleBarContainer.bottom; + anchors.topMargin: 16; + anchors.bottom: tabButtonsContainer.top; + anchors.bottomMargin: 16; + anchors.left: parent.left; + 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; + } + } + } + + Help { + id: help; + visible: root.activeView === "help"; + anchors.top: titleBarContainer.bottom; + anchors.topMargin: 16; + anchors.bottom: tabButtonsContainer.top; + anchors.bottomMargin: 16; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + } + + + // + // TAB CONTENTS END + // + + // + // TAB BUTTONS START + // + Item { + id: tabButtonsContainer; + property int numTabs: 5; + // Size + width: root.width; + height: 80; + // Anchors + anchors.left: parent.left; + anchors.bottom: parent.bottom; + + // Separator + HifiControlsUit.Separator { + anchors.left: parent.left; + anchors.right: parent.right; + anchors.top: parent.top; + } + + // "WALLET HOME" tab button + Rectangle { + id: walletHomeButtonContainer; + visible: !notSetUp.visible; + color: root.activeView === "walletHome" ? hifi.colors.blueAccent : hifi.colors.black; + anchors.top: parent.top; + anchors.left: parent.left; + anchors.bottom: parent.bottom; + width: parent.width / tabButtonsContainer.numTabs; + + RalewaySemiBold { + text: "WALLET HOME"; + // Text size + size: hifi.fontSizes.overlayTitle; + // Anchors + anchors.fill: parent; + anchors.leftMargin: 4; + anchors.rightMargin: 4; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + MouseArea { + enabled: !walletSetupLightboxContainer.visible; + anchors.fill: parent; + hoverEnabled: enabled; + onClicked: { + root.activeView = "walletHome"; + tabButtonsContainer.resetTabButtonColors(); + } + onEntered: parent.color = hifi.colors.blueHighlight; + onExited: parent.color = root.activeView === "walletHome" ? hifi.colors.blueAccent : hifi.colors.black; + } + + onVisibleChanged: { + if (visible) { + commerce.getSecurityImage(); + commerce.balance(); + } + } + } + + // "SEND MONEY" tab button + Rectangle { + id: sendMoneyButtonContainer; + visible: !notSetUp.visible; + color: hifi.colors.black; + anchors.top: parent.top; + anchors.left: walletHomeButtonContainer.right; + anchors.bottom: parent.bottom; + width: parent.width / tabButtonsContainer.numTabs; + + RalewaySemiBold { + text: "SEND MONEY"; + // Text size + size: 14; + // Anchors + anchors.fill: parent; + anchors.leftMargin: 4; + anchors.rightMargin: 4; + // Style + color: hifi.colors.lightGray50; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + } + + // "EXCHANGE MONEY" tab button + Rectangle { + id: exchangeMoneyButtonContainer; + visible: !notSetUp.visible; + color: hifi.colors.black; + anchors.top: parent.top; + anchors.left: sendMoneyButtonContainer.right; + anchors.bottom: parent.bottom; + width: parent.width / tabButtonsContainer.numTabs; + + RalewaySemiBold { + text: "EXCHANGE MONEY"; + // Text size + size: 14; + // Anchors + anchors.fill: parent; + anchors.leftMargin: 4; + anchors.rightMargin: 4; + // Style + color: hifi.colors.lightGray50; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + } + + // "SECURITY" tab button + Rectangle { + id: securityButtonContainer; + visible: !notSetUp.visible; + color: root.activeView === "security" ? hifi.colors.blueAccent : hifi.colors.black; + anchors.top: parent.top; + anchors.left: exchangeMoneyButtonContainer.right; + anchors.bottom: parent.bottom; + width: parent.width / tabButtonsContainer.numTabs; + + RalewaySemiBold { + text: "SECURITY"; + // Text size + size: hifi.fontSizes.overlayTitle; + // Anchors + anchors.fill: parent; + anchors.leftMargin: 4; + anchors.rightMargin: 4; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + MouseArea { + enabled: !walletSetupLightboxContainer.visible; + anchors.fill: parent; + hoverEnabled: enabled; + onClicked: { + root.activeView = "security"; + tabButtonsContainer.resetTabButtonColors(); + } + onEntered: parent.color = hifi.colors.blueHighlight; + onExited: parent.color = root.activeView === "security" ? hifi.colors.blueAccent : hifi.colors.black; + } + + onVisibleChanged: { + if (visible) { + commerce.getSecurityImage(); + commerce.getKeyFilePath(); + } + } + } + + // "HELP" tab button + Rectangle { + id: helpButtonContainer; + visible: !notSetUp.visible; + color: root.activeView === "help" ? hifi.colors.blueAccent : hifi.colors.black; + anchors.top: parent.top; + anchors.left: securityButtonContainer.right; + anchors.bottom: parent.bottom; + width: parent.width / tabButtonsContainer.numTabs; + + RalewaySemiBold { + text: "HELP"; + // Text size + size: hifi.fontSizes.overlayTitle; + // Anchors + anchors.fill: parent; + anchors.leftMargin: 4; + anchors.rightMargin: 4; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + MouseArea { + enabled: !walletSetupLightboxContainer.visible; + anchors.fill: parent; + hoverEnabled: enabled; + onClicked: { + root.activeView = "help"; + tabButtonsContainer.resetTabButtonColors(); + } + onEntered: parent.color = hifi.colors.blueHighlight; + onExited: parent.color = root.activeView === "help" ? hifi.colors.blueAccent : hifi.colors.black; + } + } + + function resetTabButtonColors() { + walletHomeButtonContainer.color = hifi.colors.black; + sendMoneyButtonContainer.color = hifi.colors.black; + securityButtonContainer.color = hifi.colors.black; + helpButtonContainer.color = hifi.colors.black; + if (root.activeView === "walletHome") { + walletHomeButtonContainer.color = hifi.colors.blueAccent; + } else if (root.activeView === "sendMoney") { + sendMoneyButtonContainer.color = hifi.colors.blueAccent; + } else if (root.activeView === "security") { + securityButtonContainer.color = hifi.colors.blueAccent; + } else if (root.activeView === "help") { + helpButtonContainer.color = hifi.colors.blueAccent; + } + } + } + // + // TAB BUTTONS 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 sendToScript(var message); + + // + // FUNCTION DEFINITIONS END + // +} diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml new file mode 100644 index 0000000000..281d110f21 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -0,0 +1,354 @@ +// +// WalletHome.qml +// qml/hifi/commerce/wallet +// +// WalletHome +// +// 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; + + onSecurityImageResult: { + if (imageID !== 0) { // "If security image is set up" + var path = securityImageModel.getImagePathFromImageID(imageID); + securityImage.source = path; + } + } + + onBalanceResult : { + balanceText.text = parseFloat(result.data.balance/100).toFixed(2); + } + } + + SecurityImageModel { + id: securityImageModel; + } + + Connections { + target: GlobalServices + onMyUsernameChanged: { + usernameText.text = Account.username; + } + } + + // Username Text + RalewayRegular { + id: usernameText; + text: Account.username; + // Text size + size: 24; + // Style + color: hifi.colors.faintGray; + elide: Text.ElideRight; + // Anchors + anchors.top: securityImageContainer.top; + anchors.bottom: securityImageContainer.bottom; + anchors.left: parent.left; + anchors.right: hfcBalanceContainer.left; + } + + // HFC Balance Container + Item { + id: hfcBalanceContainer; + // Anchors + anchors.top: securityImageContainer.top; + anchors.right: securityImageContainer.left; + anchors.rightMargin: 16; + width: 175; + height: 60; + Rectangle { + id: hfcBalanceField; + anchors.right: parent.right; + anchors.left: parent.left; + anchors.bottom: parent.bottom; + height: parent.height - 15; + + // "HFC" balance label + RalewayRegular { + id: balanceLabel; + text: "HFC"; + // Text size + size: 20; + // Anchors + anchors.top: parent.top; + anchors.bottom: parent.bottom; + anchors.right: hfcBalanceField.right; + anchors.rightMargin: 4; + width: paintedWidth; + // Style + color: hifi.colors.darkGray; + // Alignment + horizontalAlignment: Text.AlignRight; + verticalAlignment: Text.AlignVCenter; + + onVisibleChanged: { + if (visible) { + commerce.balance(); + } + } + } + + // Balance Text + FiraSansRegular { + id: balanceText; + text: "--"; + // Text size + size: 28; + // Anchors + anchors.top: parent.top; + anchors.bottom: parent.bottom; + anchors.left: parent.left; + anchors.right: balanceLabel.left; + anchors.rightMargin: 4; + // Style + color: hifi.colors.darkGray; + // Alignment + horizontalAlignment: Text.AlignRight; + verticalAlignment: Text.AlignVCenter; + } + } + // "balance" text above field + RalewayRegular { + text: "balance"; + // Text size + size: 12; + // Anchors + anchors.top: parent.top; + anchors.bottom: hfcBalanceField.top; + anchors.bottomMargin: 4; + anchors.left: hfcBalanceField.left; + anchors.right: hfcBalanceField.right; + // Style + color: hifi.colors.faintGray; + // Alignment + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignVCenter; + } + } + + // Security Image + Item { + id: securityImageContainer; + // Anchors + anchors.top: parent.top; + anchors.right: parent.right; + width: 75; + height: childrenRect.height; + + onVisibleChanged: { + if (visible) { + commerce.getSecurityImage(); + } + } + + Image { + id: securityImage; + // Anchors + anchors.top: parent.top; + anchors.horizontalCenter: parent.horizontalCenter; + height: parent.width - 10; + width: height; + fillMode: Image.PreserveAspectFit; + mipmap: true; + } + // "Security picture" text below pic + RalewayRegular { + text: "security picture"; + // Text size + size: 12; + // Anchors + anchors.top: securityImage.bottom; + anchors.topMargin: 4; + anchors.left: securityImageContainer.left; + anchors.right: securityImageContainer.right; + height: paintedHeight; + // Style + color: hifi.colors.faintGray; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + } + + // Recent Activity + Item { + id: recentActivityContainer; + anchors.top: securityImageContainer.bottom; + anchors.topMargin: 8; + anchors.left: parent.left; + anchors.right: parent.right; + anchors.bottom: homeMessage.visible ? homeMessage.top : root.bottom; + anchors.bottomMargin: 10; + + RalewayRegular { + id: recentActivityText; + text: "Recent Activity"; + // Anchors + anchors.top: parent.top; + anchors.left: parent.left; + anchors.right: parent.right; + height: 30; + // Text size + size: 22; + // Style + color: hifi.colors.faintGray; + } + + Rectangle { + id: transactionHistory; + anchors.top: recentActivityText.bottom; + anchors.topMargin: 4; + anchors.bottom: toggleFullHistoryButton.top; + anchors.bottomMargin: 8; + anchors.left: parent.left; + anchors.right: parent.right; + + // some placeholder stuff + RalewayRegular { + text: homeMessage.visible ? "you CANNOT scroll through this." : "you CAN scroll through this"; + // Text size + size: 16; + // Anchors + 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; + } + } + } + } + + // + // 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/WalletSetupLightbox.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml new file mode 100644 index 0000000000..ecb277f800 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetupLightbox.qml @@ -0,0 +1,632 @@ +// +// WalletSetupLightbox.qml +// qml/hifi/commerce/wallet +// +// WalletSetupLightbox +// +// Created by Zach Fox on 2017-08-17 +// 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 + +Rectangle { + HifiConstants { id: hifi; } + + id: root; + property string lastPage: "login"; + // Style + color: hifi.colors.baseGray; + + Hifi.QmlCommerce { + id: commerce; + + onLoginStatusResult: { + if (isLoggedIn) { + securityImageContainer.visible = true; + } else { + loginPageContainer.visible = true; + } + } + + onSecurityImageResult: { + if (imageID === 0 && root.lastPage === "securityImage") { + // ERROR! Invalid security image. + securityImageContainer.visible = true; + choosePassphraseContainer.visible = false; + } + } + + onPassphraseSetupStatusResult: { + securityImageContainer.visible = false; + if (passphraseIsSetup) { + privateKeysReadyContainer.visible = true; + } else { + choosePassphraseContainer.visible = true; + } + } + + onKeyFilePathResult: { + if (path !== "") { + keyFilePath.text = path; + } + } + } + + // + // 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 + width: parent.width; + height: 50; + // Anchors + anchors.left: parent.left; + anchors.top: parent.top; + + // Title Bar text + RalewaySemiBold { + text: "WALLET SETUP - STEP 1 OF 3"; + // 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: securityImageTitleHelper; + text: "Choose a Security Picture:"; + // Text size + size: 24; + // Anchors + anchors.top: securityImageTitle.bottom; + anchors.left: parent.left; + anchors.leftMargin: 16; + height: 50; + width: paintedWidth; + // Style + color: hifi.colors.faintGray; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + SecurityImageSelection { + id: securityImageSelection; + // Anchors + anchors.top: securityImageTitleHelper.bottom; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: 280; + } + + // Text below security images + RalewayRegular { + text: "Your security picture shows you that the service asking for your passphrase is authorized. You can change your secure picture at any time."; + // Text size + size: 18; + // Anchors + anchors.top: securityImageSelection.bottom; + anchors.topMargin: 40; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: paintedHeight; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // 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'}); + } + } + + // "Next" 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.right: parent.right; + anchors.rightMargin: 20; + width: 100; + text: "Next"; + onClicked: { + root.lastPage = "securityImage"; + commerce.chooseSecurityImage(securityImageSelection.getSelectedImageIndex()); + securityImageContainer.visible = false; + choosePassphraseContainer.visible = true; + } + } + } + } + // + // SECURITY IMAGE SELECTION END + // + + // + // SECURE PASSPHRASE SELECTION START + // + Item { + id: choosePassphraseContainer; + visible: false; + // Anchors + anchors.fill: parent; + + onVisibleChanged: { + if (visible) { + commerce.getPassphraseSetupStatus(); + } + } + + Item { + id: passphraseTitle; + // Size + width: parent.width; + height: 50; + // Anchors + anchors.left: parent.left; + anchors.top: parent.top; + + // Title Bar text + RalewaySemiBold { + text: "WALLET SETUP - STEP 2 OF 3"; + // 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: passphraseTitleHelper; + text: "Choose a Secure Passphrase"; + // Text size + size: 24; + // Anchors + anchors.top: passphraseTitle.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; + } + + PassphraseSelection { + id: passphraseSelection; + anchors.top: passphraseTitleHelper.bottom; + anchors.topMargin: 30; + anchors.left: parent.left; + anchors.right: parent.right; + anchors.bottom: passphraseNavBar.top; + } + + // Navigation Bar + Item { + id: passphraseNavBar; + // Size + width: parent.width; + height: 100; + // Anchors: + anchors.left: parent.left; + anchors.bottom: parent.bottom; + + // "Back" 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: "Back" + onClicked: { + root.lastPage = "choosePassphrase"; + choosePassphraseContainer.visible = false; + securityImageContainer.visible = true; + } + } + + // "Next" button + HifiControlsUit.Button { + id: passphrasePageNextButton; + 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: 100; + text: "Next"; + onClicked: { + if (passphraseSelection.validateAndSubmitPassphrase()) { + root.lastPage = "passphrase"; + choosePassphraseContainer.visible = false; + privateKeysReadyContainer.visible = true; + commerce.balance(); // Do this here so that keys are generated. Order might change as backend changes? + } + } + } + } + } + // + // SECURE PASSPHRASE SELECTION END + // + + // + // PRIVATE KEYS READY START + // + Item { + id: privateKeysReadyContainer; + visible: false; + // Anchors + anchors.fill: parent; + + Item { + id: keysReadyTitle; + // Size + width: parent.width; + height: 50; + // Anchors + anchors.left: parent.left; + anchors.top: parent.top; + + // Title Bar text + RalewaySemiBold { + text: "WALLET SETUP - STEP 3 OF 3"; + // 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: keysReadyTitleHelper; + text: "Your Private Keys are Ready"; + // Text size + size: 24; + // Anchors + anchors.top: keysReadyTitle.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 checkbox + RalewayRegular { + id: explanationText; + text: "Your money and purchases are secured with private keys that only you have access to. " + + "If they are lost, you will not be able to access your money or purchases.

" + + "To protect your privacy, High Fidelity has no access to your private keys and cannot " + + "recover them for any reason.

To safeguard your private keys, backup this file on a regular basis:
"; + // Text size + size: 16; + // Anchors + anchors.top: keysReadyTitleHelper.bottom; + anchors.topMargin: 16; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: paintedHeight; + // Style + color: hifi.colors.faintGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + HifiControlsUit.TextField { + id: keyFilePath; + anchors.top: explanationText.bottom; + anchors.topMargin: 10; + anchors.left: parent.left; + anchors.leftMargin: 16; + anchors.right: clipboardButton.left; + height: 40; + readOnly: true; + + onVisibleChanged: { + if (visible) { + commerce.getKeyFilePath(); + } + } + } + HifiControlsUit.Button { + id: clipboardButton; + color: hifi.buttons.black; + colorScheme: hifi.colorSchemes.dark; + anchors.right: parent.right; + anchors.rightMargin: 16; + anchors.top: keyFilePath.top; + anchors.bottom: keyFilePath.bottom; + width: height; + HiFiGlyphs { + text: hifi.glyphs.question; + // Size + size: parent.height*1.3; + // Anchors + anchors.fill: parent; + // Style + horizontalAlignment: Text.AlignHCenter; + color: enabled ? hifi.colors.white : hifi.colors.faintGray; + } + + onClicked: { + Window.copyToClipboard(keyFilePath.text); + } + } + + // Navigation Bar + Item { + // Size + width: parent.width; + height: 100; + // Anchors: + anchors.left: parent.left; + anchors.bottom: parent.bottom; + // "Next" button + HifiControlsUit.Button { + id: keysReadyPageNextButton; + 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: 100; + text: "Finish"; + onClicked: { + root.visible = false; + sendSignalToWallet({method: 'walletSetup_finished'}); + } + } + } + } + // + // PRIVATE KEYS READY END + // + + // + // FUNCTION DEFINITIONS START + // + signal sendSignalToWallet(var msg); + // + // FUNCTION DEFINITIONS END + // +} diff --git a/interface/resources/qml/hifi/commerce/wallet/images/01cat.jpg b/interface/resources/qml/hifi/commerce/wallet/images/01cat.jpg new file mode 100644 index 0000000000..6e7897cb82 Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/01cat.jpg differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/02car.jpg b/interface/resources/qml/hifi/commerce/wallet/images/02car.jpg new file mode 100644 index 0000000000..5dd8091e57 Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/02car.jpg differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/03dog.jpg b/interface/resources/qml/hifi/commerce/wallet/images/03dog.jpg new file mode 100644 index 0000000000..4a85b80c0c Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/03dog.jpg differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/04stars.jpg b/interface/resources/qml/hifi/commerce/wallet/images/04stars.jpg new file mode 100644 index 0000000000..8f2bf62f83 Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/04stars.jpg differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/05plane.jpg b/interface/resources/qml/hifi/commerce/wallet/images/05plane.jpg new file mode 100644 index 0000000000..6504459d8b Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/05plane.jpg differ diff --git a/interface/resources/qml/hifi/commerce/wallet/images/06gingerbread.jpg b/interface/resources/qml/hifi/commerce/wallet/images/06gingerbread.jpg new file mode 100644 index 0000000000..54c37faa2f Binary files /dev/null and b/interface/resources/qml/hifi/commerce/wallet/images/06gingerbread.jpg differ diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index c50137fe9d..f1e9fa139e 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -14,6 +14,7 @@ #include "DependencyManager.h" #include "Ledger.h" #include "Wallet.h" +#include HIFI_QML_DEF(QmlCommerce) @@ -24,6 +25,7 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) { connect(ledger.data(), &Ledger::balanceResult, this, &QmlCommerce::balanceResult); connect(ledger.data(), &Ledger::inventoryResult, this, &QmlCommerce::inventoryResult); connect(wallet.data(), &Wallet::securityImageResult, this, &QmlCommerce::securityImageResult); + connect(wallet.data(), &Wallet::keyFilePathResult, this, &QmlCommerce::keyFilePathResult); } void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUsername) { @@ -58,3 +60,16 @@ void QmlCommerce::getSecurityImage() { auto wallet = DependencyManager::get(); wallet->getSecurityImage(); } +void QmlCommerce::getLoginStatus() { + emit loginStatusResult(DependencyManager::get()->isLoggedIn()); +} +void QmlCommerce::setPassphrase(const QString& passphrase) { + emit passphraseSetupStatusResult(true); +} +void QmlCommerce::getPassphraseSetupStatus() { + emit passphraseSetupStatusResult(false); +} +void QmlCommerce::getKeyFilePath() { + auto wallet = DependencyManager::get(); + wallet->getKeyFilePath(); +} diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index decc727928..ae606f80de 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -34,6 +34,9 @@ signals: void balanceResult(QJsonObject result); void inventoryResult(QJsonObject result); void securityImageResult(QPixmap* image); + void loginStatusResult(bool isLoggedIn); + void passphraseSetupStatusResult(bool passphraseIsSetup); + void keyFilePathResult(const QString& path); protected: Q_INVOKABLE void buy(const QString& assetId, int cost, const QString& buyerUsername = ""); @@ -41,6 +44,10 @@ protected: Q_INVOKABLE void inventory(); Q_INVOKABLE void chooseSecurityImage(const QString& imageFile); Q_INVOKABLE void getSecurityImage(); + Q_INVOKABLE void getLoginStatus(); + Q_INVOKABLE void setPassphrase(const QString& passphrase); + Q_INVOKABLE void getPassphraseSetupStatus(); + Q_INVOKABLE void getKeyFilePath(); }; #endif // hifi_QmlCommerce_h diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 9e7bc58024..68fdecca4a 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -430,3 +430,6 @@ void Wallet::getSecurityImage() { emit securityImageResult(nullptr); } } +void Wallet::getKeyFilePath() { + emit keyFilePathResult(keyFilePath()); +} diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index 2c558e358f..8f962a1bc9 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -30,12 +30,25 @@ public: QString signWithKey(const QByteArray& text, const QString& key); void chooseSecurityImage(const QString& imageFile); void getSecurityImage(); + void getKeyFilePath(); void setSalt(const QByteArray& salt) { _salt = salt; } QByteArray getSalt() { return _salt; } signals: void securityImageResult(QPixmap* image); + void keyFilePathResult(const QString& path); + +protected: + enum SecurityImage { + NONE = 0, + Cat, + Car, + Dog, + Stars, + Plane, + Gingerbread + }; private: QStringList _publicKeys{}; diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 2270118861..2285337f41 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -28,7 +28,8 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/notifications.js", "system/dialTone.js", "system/firstPersonHMD.js", - "system/tablet-ui/tabletUI.js" + "system/tablet-ui/tabletUI.js", + "system/commerce/wallet.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ "system/controllers/controllerScripts.js", diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js new file mode 100644 index 0000000000..6045bef8ef --- /dev/null +++ b/scripts/system/commerce/wallet.js @@ -0,0 +1,149 @@ +"use strict"; +/*jslint vars:true, plusplus:true, forin:true*/ +/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ +// +// wallet.js +// +// Created by Zach Fox on 2017-08-17 +// 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 +// + +/*global XXX */ + +(function () { // BEGIN LOCAL_SCOPE + + + // Function Name: onButtonClicked() + // + // Description: + // -Fired when the app button is pressed. + // + // Relevant Variables: + // -WALLET_QML_SOURCE: The path to the Wallet QML + // -onWalletScreen: true/false depending on whether we're looking at the app. + var WALLET_QML_SOURCE = Script.resourcesPath() + "qml/hifi/commerce/wallet/Wallet.qml"; + var onWalletScreen = false; + function onButtonClicked() { + if (!tablet) { + print("Warning in buttonClicked(): 'tablet' undefined!"); + return; + } + if (onWalletScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + tablet.loadQMLSource(WALLET_QML_SOURCE); + } + } + + // Function Name: sendToQml() + // + // Description: + // -Use this function to send a message to the QML (i.e. to change appearances). The "message" argument is what is sent to + // the QML in the format "{method, params}", like json-rpc. See also fromQml(). + function sendToQml(message) { + tablet.sendToQml(message); + } + + // Function Name: fromQml() + // + // Description: + // -Called when a message is received from SpectatorCamera.qml. The "message" argument is what is sent from the QML + // in the format "{method, params}", like json-rpc. See also sendToQml(). + function fromQml(message) { + switch (message.method) { + case 'walletSetup_cancelClicked': + tablet.gotoHomeScreen(); + break; + case 'walletSetup_loginClicked': + if ((HMD.active && Settings.getValue("hmdTabletBecomesToolbar", false)) + || (!HMD.active && Settings.getValue("desktopTabletBecomesToolbar", true))) { + Menu.triggerOption("Login / Sign Up"); + tablet.gotoHomeScreen(); + } else { + tablet.loadQMLOnTop("../../../dialogs/TabletLoginDialog.qml"); + } + break; + default: + print('Unrecognized message from QML:', JSON.stringify(message)); + } + } + + // Function Name: wireEventBridge() + // + // Description: + // -Used to connect/disconnect the script's response to the tablet's "fromQml" signal. Set the "on" argument to enable or + // disable to event bridge. + // + // Relevant Variables: + // -hasEventBridge: true/false depending on whether we've already connected the event bridge. + var hasEventBridge = false; + function wireEventBridge(on) { + if (!tablet) { + print("Warning in wireEventBridge(): 'tablet' undefined!"); + return; + } + if (on) { + if (!hasEventBridge) { + tablet.fromQml.connect(fromQml); + hasEventBridge = true; + } + } else { + if (hasEventBridge) { + tablet.fromQml.disconnect(fromQml); + hasEventBridge = false; + } + } + } + + // Function Name: onTabletScreenChanged() + // + // Description: + // -Called when the TabletScriptingInterface::screenChanged() signal is emitted. The "type" argument can be either the string + // value of "Home", "Web", "Menu", "QML", or "Closed". The "url" argument is only valid for Web and QML. + function onTabletScreenChanged(type, url) { + onWalletScreen = (type === "QML" && url === WALLET_QML_SOURCE); + wireEventBridge(onWalletScreen); + // Change button to active when window is first openend, false otherwise. + if (button) { + button.editProperties({ isActive: onWalletScreen }); + } + } + + // + // Manage the connection between the button and the window. + // + var button; + var buttonName = "WALLET"; + var tablet = null; + function startup() { + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + button = tablet.addButton({ + text: buttonName, + icon: "icons/tablet-icons/wallet-i.svg", + activeIcon: "icons/tablet-icons/wallet-a.svg" + }); + button.clicked.connect(onButtonClicked); + tablet.screenChanged.connect(onTabletScreenChanged); + } + function shutdown() { + button.clicked.disconnect(onButtonClicked); + tablet.removeButton(button); + if (tablet) { + tablet.screenChanged.disconnect(onTabletScreenChanged); + if (onWalletScreen) { + tablet.gotoHomeScreen(); + } + } + } + + // + // Run the functions. + // + startup(); + Script.scriptEnding.connect(shutdown); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 77be746bf4..2889a1514a 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -115,7 +115,7 @@ itemId: id, itemName: name, itemAuthor: author, - itemPrice: price ? parseInt(price, 10) : Math.round(Math.random() * 50), + itemPrice: price ? parseInt(price, 10) : 0, itemHref: href })); } diff --git a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js index f0b943ad92..fd08cd5655 100644 --- a/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js +++ b/unpublishedScripts/marketplace/spectator-camera/spectatorCamera.js @@ -153,7 +153,7 @@ // -showSpectatorInDesktop: Set to "true" to show the "SPECTATOR" app in desktop mode. var button = false; var buttonName = "SPECTATOR"; - var showSpectatorInDesktop = false; + var showSpectatorInDesktop = true; function addOrRemoveButton(isShuttingDown, isHMDMode) { if (!tablet) { print("Warning in addOrRemoveButton(): 'tablet' undefined!");