mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
commit
0e4f3460b3
15 changed files with 518 additions and 63 deletions
|
@ -59,17 +59,17 @@ Rectangle {
|
|||
if (root.activeView !== "needsLogIn") {
|
||||
root.activeView = "needsLogIn";
|
||||
}
|
||||
} else if (walletStatus === 1) {
|
||||
} else if ((walletStatus === 1) || (walletStatus === 2) || (walletStatus === 3)) {
|
||||
if (root.activeView !== "notSetUp") {
|
||||
root.activeView = "notSetUp";
|
||||
notSetUpTimer.start();
|
||||
}
|
||||
} else if (walletStatus === 2) {
|
||||
} else if (walletStatus === 4) {
|
||||
if (root.activeView !== "passphraseModal") {
|
||||
root.activeView = "passphraseModal";
|
||||
UserActivityLogger.commercePassphraseEntry("marketplace checkout");
|
||||
}
|
||||
} else if (walletStatus === 3) {
|
||||
} else if (walletStatus === 5) {
|
||||
authSuccessStep();
|
||||
} else {
|
||||
console.log("ERROR in Checkout.qml: Unknown wallet status: " + walletStatus);
|
||||
|
|
|
@ -25,10 +25,13 @@ Rectangle {
|
|||
property string titleText;
|
||||
property string bodyImageSource;
|
||||
property string bodyText;
|
||||
property string button1color: hifi.buttons.noneBorderlessGray;
|
||||
property string button1text;
|
||||
property string button1method;
|
||||
property string button2color: hifi.buttons.noneBorderless;
|
||||
property string button2text;
|
||||
property string button2method;
|
||||
property string buttonLayout: "leftright";
|
||||
|
||||
readonly property string securityPicBodyText: "When you see your Security Pic, your actions and data are securely making use of your " +
|
||||
"Wallet's private keys.<br><br>You can change your Security Pic in your Wallet.";
|
||||
|
@ -39,6 +42,12 @@ Rectangle {
|
|||
color: Qt.rgba(0, 0, 0, 0.5);
|
||||
z: 999;
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
resetLightbox();
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -112,18 +121,21 @@ Rectangle {
|
|||
anchors.topMargin: 30;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 70;
|
||||
height: root.buttonLayout === "leftright" ? 70 : 150;
|
||||
|
||||
// Button 1
|
||||
HifiControlsUit.Button {
|
||||
color: hifi.buttons.noneBorderlessGray;
|
||||
id: button1;
|
||||
color: root.button1color;
|
||||
colorScheme: hifi.colorSchemes.light;
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.bottomMargin: 20;
|
||||
anchors.top: root.buttonLayout === "leftright" ? parent.top : parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 10;
|
||||
width: root.button2text ? parent.width/2 - anchors.leftMargin*2 : parent.width - anchors.leftMargin * 2;
|
||||
anchors.right: root.buttonLayout === "leftright" ? undefined : parent.right;
|
||||
anchors.rightMargin: root.buttonLayout === "leftright" ? undefined : 10;
|
||||
width: root.buttonLayout === "leftright" ? (root.button2text ? parent.width/2 - anchors.leftMargin*2 : parent.width - anchors.leftMargin * 2) :
|
||||
(undefined);
|
||||
height: 50;
|
||||
text: root.button1text;
|
||||
onClicked: {
|
||||
eval(button1method);
|
||||
|
@ -132,15 +144,18 @@ Rectangle {
|
|||
|
||||
// Button 2
|
||||
HifiControlsUit.Button {
|
||||
id: button2;
|
||||
visible: root.button2text;
|
||||
color: hifi.buttons.noneBorderless;
|
||||
color: root.button2color;
|
||||
colorScheme: hifi.colorSchemes.light;
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.bottomMargin: 20;
|
||||
anchors.top: root.buttonLayout === "leftright" ? parent.top : button1.bottom;
|
||||
anchors.topMargin: root.buttonLayout === "leftright" ? undefined : 20;
|
||||
anchors.left: root.buttonLayout === "leftright" ? undefined : parent.left;
|
||||
anchors.leftMargin: root.buttonLayout === "leftright" ? undefined : 10;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 10;
|
||||
width: parent.width/2 - anchors.rightMargin*2;
|
||||
width: root.buttonLayout === "leftright" ? parent.width/2 - anchors.rightMargin*2 : undefined;
|
||||
height: 50;
|
||||
text: root.button2text;
|
||||
onClicked: {
|
||||
eval(button2method);
|
||||
|
@ -153,6 +168,19 @@ Rectangle {
|
|||
// FUNCTION DEFINITIONS START
|
||||
//
|
||||
signal sendToParent(var msg);
|
||||
|
||||
function resetLightbox() {
|
||||
root.titleText = "";
|
||||
root.bodyImageSource = "";
|
||||
root.bodyText = "";
|
||||
root.button1color = hifi.buttons.noneBorderlessGray;
|
||||
root.button1text = "";
|
||||
root.button1method = "";
|
||||
root.button2color = hifi.buttons.noneBorderless;
|
||||
root.button2text = "";
|
||||
root.button2method = "";
|
||||
root.buttonLayout = "leftright";
|
||||
}
|
||||
//
|
||||
// FUNCTION DEFINITIONS END
|
||||
//
|
||||
|
|
|
@ -37,9 +37,9 @@ Item {
|
|||
onWalletStatusResult: {
|
||||
if (walletStatus === 0) {
|
||||
sendToParent({method: "needsLogIn"});
|
||||
} else if (walletStatus === 3) {
|
||||
} else if (walletStatus === 5) {
|
||||
Commerce.getSecurityImage();
|
||||
} else if (walletStatus > 3) {
|
||||
} else if (walletStatus > 5) {
|
||||
console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,17 +47,17 @@ Rectangle {
|
|||
if (root.activeView !== "needsLogIn") {
|
||||
root.activeView = "needsLogIn";
|
||||
}
|
||||
} else if (walletStatus === 1) {
|
||||
} else if ((walletStatus === 1) || (walletStatus === 2) || (walletStatus === 3)) {
|
||||
if (root.activeView !== "notSetUp") {
|
||||
root.activeView = "notSetUp";
|
||||
notSetUpTimer.start();
|
||||
}
|
||||
} else if (walletStatus === 2) {
|
||||
} else if (walletStatus === 4) {
|
||||
if (root.activeView !== "passphraseModal") {
|
||||
root.activeView = "passphraseModal";
|
||||
UserActivityLogger.commercePassphraseEntry("marketplace purchases");
|
||||
}
|
||||
} else if (walletStatus === 3) {
|
||||
} else if (walletStatus === 5) {
|
||||
if ((Settings.getValue("isFirstUseOfPurchases", true) || root.isDebuggingFirstUseTutorial) && root.activeView !== "firstUseTutorial") {
|
||||
root.activeView = "firstUseTutorial";
|
||||
} else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") {
|
||||
|
|
|
@ -47,20 +47,22 @@ Rectangle {
|
|||
}
|
||||
} else if (walletStatus === 1) {
|
||||
if (root.activeView !== "walletSetup") {
|
||||
root.activeView = "walletSetup";
|
||||
Commerce.resetLocalWalletOnly();
|
||||
var timestamp = new Date();
|
||||
walletSetup.startingTimestamp = timestamp;
|
||||
walletSetup.setupAttemptID = generateUUID();
|
||||
UserActivityLogger.commerceWalletSetupStarted(timestamp, setupAttemptID, walletSetup.setupFlowVersion, walletSetup.referrer ? walletSetup.referrer : "wallet app",
|
||||
(AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''));
|
||||
walletResetSetup();
|
||||
}
|
||||
} else if (walletStatus === 2) {
|
||||
if (root.activeView != "preexisting") {
|
||||
root.activeView = "preexisting";
|
||||
}
|
||||
} else if (walletStatus === 3) {
|
||||
if (root.activeView != "conflicting") {
|
||||
root.activeView = "conflicting";
|
||||
}
|
||||
} else if (walletStatus === 4) {
|
||||
if (root.activeView !== "passphraseModal") {
|
||||
root.activeView = "passphraseModal";
|
||||
UserActivityLogger.commercePassphraseEntry("wallet app");
|
||||
}
|
||||
} else if (walletStatus === 3) {
|
||||
} else if (walletStatus === 5) {
|
||||
if (root.activeView !== "walletSetup") {
|
||||
root.activeView = "walletHome";
|
||||
Commerce.getSecurityImage();
|
||||
|
@ -169,6 +171,25 @@ Rectangle {
|
|||
// TITLE BAR END
|
||||
//
|
||||
|
||||
WalletChoice {
|
||||
id: walletChoice;
|
||||
proceedFunction: function (isReset) {
|
||||
console.log(isReset ? "Reset wallet." : "Trying again with new wallet.");
|
||||
Commerce.setSoftReset();
|
||||
if (isReset) {
|
||||
walletResetSetup();
|
||||
} else {
|
||||
var msg = { referrer: walletChoice.referrer }
|
||||
followReferrer(msg);
|
||||
}
|
||||
}
|
||||
copyFunction: Commerce.copyKeyFileFrom;
|
||||
z: 997;
|
||||
visible: (root.activeView === "preexisting") || (root.activeView === "conflicting");
|
||||
activeView: root.activeView;
|
||||
anchors.fill: parent;
|
||||
}
|
||||
|
||||
WalletSetup {
|
||||
id: walletSetup;
|
||||
visible: root.activeView === "walletSetup";
|
||||
|
@ -178,14 +199,7 @@ Rectangle {
|
|||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
if (msg.method === 'walletSetup_finished') {
|
||||
if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
|
||||
root.activeView = "initialize";
|
||||
Commerce.getWalletStatus();
|
||||
} else if (msg.referrer === 'purchases') {
|
||||
sendToScript({method: 'goToPurchases'});
|
||||
} else {
|
||||
sendToScript({method: 'goToMarketplaceItemPage', itemId: msg.referrer});
|
||||
}
|
||||
followReferrer(msg);
|
||||
} else if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||
root.keyboardRaised = true;
|
||||
root.isPassword = msg.isPasswordField;
|
||||
|
@ -738,6 +752,7 @@ Rectangle {
|
|||
switch (message.method) {
|
||||
case 'updateWalletReferrer':
|
||||
walletSetup.referrer = message.referrer;
|
||||
walletChoice.referrer = message.referrer;
|
||||
break;
|
||||
case 'inspectionCertificate_resetCert':
|
||||
// NOP
|
||||
|
@ -768,6 +783,28 @@ Rectangle {
|
|||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
function walletResetSetup() {
|
||||
root.activeView = "walletSetup";
|
||||
var timestamp = new Date();
|
||||
walletSetup.startingTimestamp = timestamp;
|
||||
walletSetup.setupAttemptID = generateUUID();
|
||||
UserActivityLogger.commerceWalletSetupStarted(timestamp, walletSetup.setupAttemptID, walletSetup.setupFlowVersion, walletSetup.referrer ? walletSetup.referrer : "wallet app",
|
||||
(AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''));
|
||||
}
|
||||
|
||||
function followReferrer(msg) {
|
||||
if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
|
||||
root.activeView = "initialize";
|
||||
Commerce.getWalletStatus();
|
||||
} else if (msg.referrer === 'purchases') {
|
||||
sendToScript({method: 'goToPurchases'});
|
||||
} else if (msg.referrer === 'marketplace cta' || msg.referrer === 'mainPage') {
|
||||
sendToScript({method: 'goToMarketplaceMainPage', itemId: msg.referrer});
|
||||
} else {
|
||||
sendToScript({method: 'goToMarketplaceItemPage', itemId: msg.referrer});
|
||||
}
|
||||
}
|
||||
//
|
||||
// FUNCTION DEFINITIONS END
|
||||
//
|
||||
|
|
297
interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml
Normal file
297
interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml
Normal file
|
@ -0,0 +1,297 @@
|
|||
//
|
||||
// WalletChoice.qml
|
||||
// qml/hifi/commerce/wallet
|
||||
//
|
||||
// WalletChoice
|
||||
//
|
||||
// Created by Howard Stearns
|
||||
// Copyright 2018 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 "../common" as HifiCommerceCommon
|
||||
import "../../../styles-uit"
|
||||
import "../../../controls-uit" as HifiControlsUit
|
||||
|
||||
|
||||
Item {
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property string activeView: "conflict";
|
||||
property var proceedFunction: nil;
|
||||
property var copyFunction: nil;
|
||||
property string referrer: "";
|
||||
|
||||
Image {
|
||||
anchors.fill: parent;
|
||||
source: "images/wallet-bg.jpg";
|
||||
}
|
||||
|
||||
HifiCommerceCommon.CommerceLightbox {
|
||||
id: lightboxPopup;
|
||||
visible: false;
|
||||
anchors.fill: parent;
|
||||
}
|
||||
|
||||
// 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;
|
||||
hoverEnabled: true;
|
||||
}
|
||||
|
||||
//
|
||||
// TITLE BAR START
|
||||
//
|
||||
Item {
|
||||
id: titleBarContainer;
|
||||
// Size
|
||||
height: 50;
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.top: parent.top;
|
||||
anchors.right: parent.right;
|
||||
|
||||
// Wallet icon
|
||||
HiFiGlyphs {
|
||||
id: walletIcon;
|
||||
text: hifi.glyphs.wallet;
|
||||
// Size
|
||||
size: parent.height * 0.8;
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 8;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
// Style
|
||||
color: hifi.colors.blueHighlight;
|
||||
}
|
||||
|
||||
// Title Bar text
|
||||
RalewayRegular {
|
||||
id: titleBarText;
|
||||
text: "Wallet Setup";
|
||||
// Text size
|
||||
size: hifi.fontSizes.overlayTitle;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: walletIcon.right;
|
||||
anchors.leftMargin: 8;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: paintedWidth;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
}
|
||||
//
|
||||
// TITLE BAR END
|
||||
//
|
||||
|
||||
//
|
||||
// MAIN PAGE START
|
||||
//
|
||||
Item {
|
||||
id: preexistingContainer;
|
||||
// Anchors
|
||||
anchors.top: titleBarContainer.bottom;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
||||
HiFiGlyphs {
|
||||
id: bigKeyIcon;
|
||||
text: hifi.glyphs.walletKey;
|
||||
// Size
|
||||
size: 180;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 40;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: text01;
|
||||
text: root.activeView === "preexisting" ?
|
||||
"Where are your private keys?" :
|
||||
"Hmm, your keys are different"
|
||||
// Text size
|
||||
size: 26;
|
||||
// Anchors
|
||||
anchors.top: bigKeyIcon.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 16;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 16;
|
||||
height: paintedHeight;
|
||||
width: paintedWidth;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: text02;
|
||||
text: root.activeView === "preexisting" ?
|
||||
"Our records indicate that you created a wallet, but the private keys are not in the folder where we checked." :
|
||||
"Our records indicate that you created a wallet with different keys than the keys you're providing."
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: text01.bottom;
|
||||
anchors.topMargin: 40;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 65;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 65;
|
||||
height: paintedHeight;
|
||||
width: paintedWidth;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
// "Locate" button
|
||||
HifiControlsUit.Button {
|
||||
id: locateButton;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: text02.bottom;
|
||||
anchors.topMargin: 40;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
width: parent.width/2;
|
||||
height: 50;
|
||||
text: root.activeView === "preexisting" ?
|
||||
"LOCATE MY KEYS" :
|
||||
"LOCATE OTHER KEYS"
|
||||
onClicked: {
|
||||
walletChooser();
|
||||
}
|
||||
}
|
||||
|
||||
// "Create New" OR "Continue" button
|
||||
HifiControlsUit.Button {
|
||||
id: button02;
|
||||
color: hifi.buttons.none;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: locateButton.bottom;
|
||||
anchors.topMargin: 20;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
width: parent.width/2;
|
||||
height: 50;
|
||||
text: root.activeView === "preexisting" ?
|
||||
"CREATE NEW WALLET" :
|
||||
"CONTINUE WITH THESE KEYS"
|
||||
onClicked: {
|
||||
lightboxPopup.titleText = "Are you sure?";
|
||||
lightboxPopup.bodyText = "Taking this step will abandon your old wallet and you will no " +
|
||||
"longer be able to access your money and your past purchases.<br><br>" +
|
||||
"This step should only be used if you cannot find your keys.<br><br>" +
|
||||
"This step cannot be undone.";
|
||||
lightboxPopup.button1color = hifi.buttons.red;
|
||||
lightboxPopup.button1text = "YES, CREATE NEW WALLET";
|
||||
lightboxPopup.button1method = "root.visible = false;proceed(true);";
|
||||
lightboxPopup.button2text = "CANCEL";
|
||||
lightboxPopup.button2method = "root.visible = false;"
|
||||
lightboxPopup.buttonLayout = "topbottom";
|
||||
lightboxPopup.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
// "What's This?" link
|
||||
RalewayRegular {
|
||||
id: whatsThisLink;
|
||||
text: '<font color="#FFFFFF"><a href="#whatsthis">What\'s this?</a></font>';
|
||||
// Anchors
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.bottomMargin: 48;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
width: paintedWidth;
|
||||
height: paintedHeight;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
|
||||
onClicked: {
|
||||
if (root.activeView === "preexisting") {
|
||||
lightboxPopup.titleText = "Your wallet's private keys are not in the folder we expected";
|
||||
lightboxPopup.bodyText = "We see that you have created a wallet but the private keys " +
|
||||
"for it seem to have been moved to a different folder.<br><br>" +
|
||||
"To tell us where the keys are, click 'Locate My Keys'. <br><br>" +
|
||||
"If you'd prefer to create a new wallet (not recommended - you will lose your money and past " +
|
||||
"purchases), click 'Create New Wallet'.";
|
||||
lightboxPopup.button1text = "CLOSE";
|
||||
lightboxPopup.button1method = "root.visible = false;"
|
||||
lightboxPopup.visible = true;
|
||||
} else {
|
||||
lightboxPopup.titleText = "You may have set up more than one wallet";
|
||||
lightboxPopup.bodyText = "We see that the private keys stored on your computer are different " +
|
||||
"from the ones you used last time. This may mean that you set up more than one wallet. " +
|
||||
"If you would like to use these keys, click 'Continue With These Keys'.<br><br>" +
|
||||
"If you would prefer to use another wallet, click 'Locate Other Keys' to show us where " +
|
||||
"you've stored the private keys for that wallet.";
|
||||
lightboxPopup.button1text = "CLOSE";
|
||||
lightboxPopup.button1method = "root.visible = false;"
|
||||
lightboxPopup.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// MAIN PAGE END
|
||||
//
|
||||
|
||||
//
|
||||
// FUNCTION DEFINITIONS START
|
||||
//
|
||||
function onFileOpenChanged(filename) {
|
||||
// disconnect the event, otherwise the requests will stack up
|
||||
try { // Not all calls to onFileOpenChanged() connect an event.
|
||||
Window.browseChanged.disconnect(onFileOpenChanged);
|
||||
} catch (e) {
|
||||
console.log('WalletChoice.qml ignoring', e);
|
||||
}
|
||||
if (filename) {
|
||||
if (copyFunction && copyFunction(filename)) {
|
||||
proceed(false);
|
||||
} else {
|
||||
console.log("WalletChoice.qml copyFunction", copyFunction, "failed.");
|
||||
}
|
||||
} // Else we're still at WalletChoice
|
||||
}
|
||||
function walletChooser() {
|
||||
Window.browseChanged.connect(onFileOpenChanged);
|
||||
Window.browseAsync("Locate your .hifikey file", "", "*.hifikey");
|
||||
}
|
||||
function proceed(isReset) {
|
||||
if (!proceedFunction) {
|
||||
console.log("Provide a function of no arguments to WalletChoice.qml.");
|
||||
} else {
|
||||
proceedFunction(isReset);
|
||||
}
|
||||
}
|
||||
//
|
||||
// FUNCTION DEFINITIONS END
|
||||
//
|
||||
}
|
|
@ -310,7 +310,7 @@ Item {
|
|||
height: parent.height;
|
||||
|
||||
HifiControlsUit.Separator {
|
||||
colorScheme: 1;
|
||||
colorScheme: 1;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: parent.top;
|
||||
|
@ -318,20 +318,42 @@ Item {
|
|||
|
||||
RalewayRegular {
|
||||
id: noActivityText;
|
||||
text: "<b>The Wallet app is in closed Beta.</b><br><br>To request entry and <b>receive free HFC</b>, please contact " +
|
||||
"<b>info@highfidelity.com</b> with your High Fidelity account username and the email address registered to that account.";
|
||||
// Text size
|
||||
size: 24;
|
||||
// Style
|
||||
color: hifi.colors.blueAccent;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 12;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 12;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
height: paintedHeight;
|
||||
wrapMode: Text.WordWrap;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
text: "Congrats! Your wallet is all set!<br><br>" +
|
||||
"<b>Where's my HFC?</b><br>" +
|
||||
"High Fidelity commerce is in open beta right now. Want more HFC? Get it by meeting with a banker at " +
|
||||
"<a href='#goToBank'>BankOfHighFidelity</a>!"
|
||||
// Text size
|
||||
size: 22;
|
||||
// Style
|
||||
color: hifi.colors.blueAccent;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 36;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 12;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 12;
|
||||
height: paintedHeight;
|
||||
wrapMode: Text.WordWrap;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
|
||||
onLinkActivated: {
|
||||
sendSignalToWallet({ method: "transactionHistory_goToBank" });
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: bankButton;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: noActivityText.bottom;
|
||||
anchors.topMargin: 30;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
width: parent.width/2;
|
||||
height: 50;
|
||||
text: "VISIT BANK OF HIGH FIDELITY";
|
||||
onClicked: {
|
||||
sendSignalToWallet({ method: "transactionHistory_goToBank" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
// inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}}
|
||||
// balance answers {status: 'success', data: {balance: integer}}
|
||||
// buy and receive_at answer {status: 'success'}
|
||||
// account synthesizes a result {status: 'success', data: {keyStatus: "preexisting"|"conflicting"|"ok"}}
|
||||
|
||||
|
||||
QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply& reply) {
|
||||
QByteArray response = reply.readAll();
|
||||
|
@ -99,7 +101,7 @@ void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, cons
|
|||
signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure", controlled_failure);
|
||||
}
|
||||
|
||||
bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key) {
|
||||
bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
if (!accountManager->isLoggedIn()) {
|
||||
qCWarning(commerce) << "Cannot set receiveAt when not logged in.";
|
||||
|
@ -108,7 +110,7 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key) {
|
|||
return false; // We know right away that we will fail, so tell the caller.
|
||||
}
|
||||
|
||||
signedSend("public_key", hfc_key.toUtf8(), old_key, "receive_at", "receiveAtSuccess", "receiveAtFailure");
|
||||
signedSend("public_key", hfc_key.toUtf8(), signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure");
|
||||
return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in.
|
||||
}
|
||||
|
||||
|
@ -179,7 +181,7 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
} else {
|
||||
result += valueObject["message"].toString();
|
||||
}
|
||||
|
||||
|
||||
// no matter what we append a smaller date to the bottom of this...
|
||||
result += QString("<br><font size='-2' color='#1080B8'>%1").arg(createdAt.toLocalTime().toString(Qt::DefaultLocaleShortDate));
|
||||
return result;
|
||||
|
@ -246,18 +248,33 @@ void Ledger::accountSuccess(QNetworkReply& reply) {
|
|||
auto iv = QByteArray::fromBase64(data["iv"].toString().toUtf8());
|
||||
auto ckey = QByteArray::fromBase64(data["ckey"].toString().toUtf8());
|
||||
QString remotePublicKey = data["public_key"].toString();
|
||||
bool isOverride = wallet->wasSoftReset();
|
||||
|
||||
wallet->setSalt(salt);
|
||||
wallet->setIv(iv);
|
||||
wallet->setCKey(ckey);
|
||||
|
||||
QString keyStatus = "ok";
|
||||
QStringList localPublicKeys = wallet->listPublicKeys();
|
||||
if (remotePublicKey.isEmpty() && !localPublicKeys.isEmpty()) {
|
||||
receiveAt(localPublicKeys.first(), "");
|
||||
if (remotePublicKey.isEmpty() || isOverride) {
|
||||
if (!localPublicKeys.isEmpty()) {
|
||||
QString key = localPublicKeys.first();
|
||||
receiveAt(key, key);
|
||||
}
|
||||
} else {
|
||||
if (localPublicKeys.isEmpty()) {
|
||||
keyStatus = "preexisting";
|
||||
} else if (localPublicKeys.first() != remotePublicKey) {
|
||||
keyStatus = "conflicting";
|
||||
}
|
||||
}
|
||||
|
||||
// none of the hfc account info should be emitted
|
||||
emit accountResult(QJsonObject{ {"status", "success"} });
|
||||
QJsonObject json;
|
||||
QJsonObject responseData{ { "status", "success"} };
|
||||
json["keyStatus"] = keyStatus;
|
||||
responseData["data"] = json;
|
||||
emit accountResult(responseData);
|
||||
}
|
||||
|
||||
void Ledger::accountFailure(QNetworkReply& reply) {
|
||||
|
|
|
@ -26,7 +26,7 @@ class Ledger : public QObject, public Dependency {
|
|||
|
||||
public:
|
||||
void buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure = false);
|
||||
bool receiveAt(const QString& hfc_key, const QString& old_key);
|
||||
bool receiveAt(const QString& hfc_key, const QString& signing_key);
|
||||
void balance(const QStringList& keys);
|
||||
void inventory(const QStringList& keys);
|
||||
void history(const QStringList& keys, const int& pageNumber);
|
||||
|
|
|
@ -62,6 +62,11 @@ void QmlCommerce::getKeyFilePathIfExists() {
|
|||
emit keyFilePathIfExistsResult(wallet->getKeyFilePath());
|
||||
}
|
||||
|
||||
bool QmlCommerce::copyKeyFileFrom(const QString& pathname) {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
return wallet->copyKeyFileFrom(pathname);
|
||||
}
|
||||
|
||||
void QmlCommerce::getWalletAuthenticatedStatus() {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
emit walletAuthenticatedStatusResult(wallet->walletIsAuthenticatedWithPassphrase());
|
||||
|
@ -128,6 +133,11 @@ void QmlCommerce::changePassphrase(const QString& oldPassphrase, const QString&
|
|||
}
|
||||
}
|
||||
|
||||
void QmlCommerce::setSoftReset() {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
wallet->setSoftReset();
|
||||
}
|
||||
|
||||
void QmlCommerce::setPassphrase(const QString& passphrase) {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
wallet->setPassphrase(passphrase);
|
||||
|
|
|
@ -61,10 +61,12 @@ protected:
|
|||
Q_INVOKABLE void getKeyFilePathIfExists();
|
||||
Q_INVOKABLE void getSecurityImage();
|
||||
Q_INVOKABLE void getWalletAuthenticatedStatus();
|
||||
Q_INVOKABLE bool copyKeyFileFrom(const QString& pathname);
|
||||
|
||||
Q_INVOKABLE void chooseSecurityImage(const QString& imageFile);
|
||||
Q_INVOKABLE void setPassphrase(const QString& passphrase);
|
||||
Q_INVOKABLE void changePassphrase(const QString& oldPassphrase, const QString& newPassphrase);
|
||||
Q_INVOKABLE void setSoftReset();
|
||||
|
||||
Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false);
|
||||
Q_INVOKABLE void balance();
|
||||
|
|
|
@ -59,6 +59,23 @@ QString keyFilePath() {
|
|||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
return PathUtils::getAppDataFilePath(QString("%1.%2").arg(accountManager->getAccountInfo().getUsername(), KEY_FILE));
|
||||
}
|
||||
bool Wallet::copyKeyFileFrom(const QString& pathname) {
|
||||
QString existing = getKeyFilePath();
|
||||
qCDebug(commerce) << "Old keyfile" << existing;
|
||||
if (!existing.isEmpty()) {
|
||||
QString backup = QString(existing).insert(existing.indexOf(KEY_FILE) - 1,
|
||||
QDateTime::currentDateTime().toString(Qt::ISODate).replace(":", ""));
|
||||
qCDebug(commerce) << "Renaming old keyfile to" << backup;
|
||||
if (!QFile::rename(existing, backup)) {
|
||||
qCCritical(commerce) << "Unable to backup" << existing << "to" << backup;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
QString destination = keyFilePath();
|
||||
bool result = QFile::copy(pathname, destination);
|
||||
qCDebug(commerce) << "copy" << pathname << "to" << destination << "=>" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// use the cached _passphrase if it exists, otherwise we need to prompt
|
||||
int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
|
||||
|
@ -300,17 +317,24 @@ Wallet::Wallet() {
|
|||
packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket");
|
||||
packetReceiver.registerListener(PacketType::ChallengeOwnershipRequest, this, "handleChallengeOwnershipPacket");
|
||||
|
||||
connect(ledger.data(), &Ledger::accountResult, this, [&]() {
|
||||
connect(ledger.data(), &Ledger::accountResult, this, [&](QJsonObject result) {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
|
||||
uint status;
|
||||
QString keyStatus = result.contains("data") ? result["data"].toObject()["keyStatus"].toString() : "";
|
||||
|
||||
if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_NOT_SET_UP;
|
||||
if (keyStatus == "preexisting") {
|
||||
status = (uint) WalletStatus::WALLET_STATUS_PREEXISTING;
|
||||
} else{
|
||||
status = (uint) WalletStatus::WALLET_STATUS_NOT_SET_UP;
|
||||
}
|
||||
} else if (!wallet->walletIsAuthenticatedWithPassphrase()) {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED;
|
||||
status = (uint) WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED;
|
||||
} else if (keyStatus == "conflicting") {
|
||||
status = (uint) WalletStatus::WALLET_STATUS_CONFLICTING;
|
||||
} else {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_READY;
|
||||
status = (uint) WalletStatus::WALLET_STATUS_READY;
|
||||
}
|
||||
|
||||
walletScriptingInterface->setWalletStatus(status);
|
||||
|
@ -524,17 +548,17 @@ bool Wallet::generateKeyPair() {
|
|||
|
||||
// TODO: redo this soon -- need error checking and so on
|
||||
writeSecurityImage(_securityImage, keyFilePath());
|
||||
QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last();
|
||||
QString key = keyPair.first->toBase64();
|
||||
_publicKeys.push_back(key);
|
||||
qCDebug(commerce) << "public key:" << key;
|
||||
_isOverridingServer = false;
|
||||
|
||||
// It's arguable whether we want to change the receiveAt every time, but:
|
||||
// 1. It's certainly needed the first time, when createIfNeeded answers true.
|
||||
// 2. It is maximally private, and we can step back from that later if desired.
|
||||
// 3. It maximally exercises all the machinery, so we are most likely to surface issues now.
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
return ledger->receiveAt(key, oldKey);
|
||||
return ledger->receiveAt(key, key);
|
||||
}
|
||||
|
||||
QStringList Wallet::listPublicKeys() {
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
void chooseSecurityImage(const QString& imageFile);
|
||||
bool getSecurityImage();
|
||||
QString getKeyFilePath();
|
||||
bool copyKeyFileFrom(const QString& pathname);
|
||||
|
||||
void setSalt(const QByteArray& salt) { _salt = salt; }
|
||||
QByteArray getSalt() { return _salt; }
|
||||
|
@ -48,11 +49,15 @@ public:
|
|||
bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); }
|
||||
bool walletIsAuthenticatedWithPassphrase();
|
||||
bool changePassphrase(const QString& newPassphrase);
|
||||
void setSoftReset() { _isOverridingServer = true; }
|
||||
bool wasSoftReset() { bool was = _isOverridingServer; _isOverridingServer = false; return was; }
|
||||
|
||||
void getWalletStatus();
|
||||
enum WalletStatus {
|
||||
WALLET_STATUS_NOT_LOGGED_IN = 0,
|
||||
WALLET_STATUS_NOT_SET_UP,
|
||||
WALLET_STATUS_PREEXISTING,
|
||||
WALLET_STATUS_CONFLICTING,
|
||||
WALLET_STATUS_NOT_AUTHENTICATED,
|
||||
WALLET_STATUS_READY
|
||||
};
|
||||
|
@ -73,6 +78,7 @@ private:
|
|||
QByteArray _iv;
|
||||
QByteArray _ckey;
|
||||
QString* _passphrase { new QString("") };
|
||||
bool _isOverridingServer { false };
|
||||
|
||||
bool writeWallet(const QString& newPassphrase = QString(""));
|
||||
void updateImageProvider();
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <GeometryUtil.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <scripting/HMDScriptingInterface.h>
|
||||
#include <scripting/WindowScriptingInterface.h>
|
||||
#include <ui/OffscreenQmlSurface.h>
|
||||
#include <ui/OffscreenQmlSurfaceCache.h>
|
||||
#include <ui/TabletScriptingInterface.h>
|
||||
|
@ -233,6 +234,7 @@ void Web3DOverlay::setupQmlSurface() {
|
|||
_webSurface->getSurfaceContext()->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Pointers", DependencyManager::get<PointerScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this);
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
||||
|
||||
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
|
||||
|
||||
|
|
|
@ -655,6 +655,9 @@
|
|||
case 'goToPurchases':
|
||||
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
|
||||
break;
|
||||
case 'goToMarketplaceMainPage':
|
||||
tablet.gotoWebScreen(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
break;
|
||||
case 'goToMarketplaceItemPage':
|
||||
tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + message.itemId, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
break;
|
||||
|
@ -688,6 +691,13 @@
|
|||
updateSendMoneyParticleEffect();
|
||||
sendMoneyParticleEffectUpdateTimer = Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE);
|
||||
break;
|
||||
case 'transactionHistory_goToBank':
|
||||
if (Account.metaverseServerURL.indexOf("staging") >= 0) {
|
||||
Window.location = "hifi://hifiqa-master-metaverse-staging"; // So that we can test in staging.
|
||||
} else {
|
||||
Window.location = "hifi://BankOfHighFidelity";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
print('Unrecognized message from QML:', JSON.stringify(message));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue