Merge pull request #11495 from zfox23/pop_interfaceChanges2

Commerce: One step closer!
This commit is contained in:
Zach Fox 2017-10-03 11:56:00 -07:00 committed by GitHub
commit ea3da6c9dd
32 changed files with 950 additions and 448 deletions

View file

@ -26,72 +26,57 @@ Rectangle {
HifiConstants { id: hifi; } HifiConstants { id: hifi; }
id: root; id: root;
objectName: "checkout"
property string activeView: "initialize"; property string activeView: "initialize";
property bool purchasesReceived: false; property bool purchasesReceived: false;
property bool balanceReceived: false; property bool balanceReceived: false;
property bool securityImageResultReceived: false; property string itemName;
property string itemId; property string itemId;
property string itemPreviewImageUrl;
property string itemHref; property string itemHref;
property double balanceAfterPurchase; property double balanceAfterPurchase;
property bool alreadyOwned: false; property bool alreadyOwned: false;
property int itemPrice: 0; property int itemPrice;
property bool itemIsJson: true; property bool itemIsJson: true;
property bool shouldBuyWithControlledFailure: false; property bool shouldBuyWithControlledFailure: false;
property bool debugCheckoutSuccess: false; property bool debugCheckoutSuccess: false;
property bool canRezCertifiedItems: false; property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified;
// Style // Style
color: hifi.colors.white; color: hifi.colors.white;
Hifi.QmlCommerce { Hifi.QmlCommerce {
id: commerce; id: commerce;
onWalletStatusResult: {
if (walletStatus === 0) {
if (root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn";
}
} else if (walletStatus === 1) {
if (root.activeView !== "notSetUp") {
root.activeView = "notSetUp";
notSetUpTimer.start();
}
} else if (walletStatus === 2) {
if (root.activeView !== "passphraseModal") {
root.activeView = "passphraseModal";
}
} else if (walletStatus === 3) {
authSuccessStep();
} else {
console.log("ERROR in Checkout.qml: Unknown wallet status: " + walletStatus);
}
}
onLoginStatusResult: { onLoginStatusResult: {
if (!isLoggedIn && root.activeView !== "needsLogIn") { if (!isLoggedIn && root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn"; root.activeView = "needsLogIn";
} else if (isLoggedIn) {
root.activeView = "initialize";
commerce.account();
}
}
onAccountResult: {
if (result.status === "success") {
commerce.getKeyFilePathIfExists();
} else { } else {
// unsure how to handle a failure here. We definitely cannot proceed. commerce.getWalletStatus();
}
}
onKeyFilePathIfExistsResult: {
if (path === "" && root.activeView !== "notSetUp") {
root.activeView = "notSetUp";
notSetUpTimer.start();
} else if (path !== "" && root.activeView === "initialize") {
commerce.getSecurityImage();
}
}
onSecurityImageResult: {
securityImageResultReceived = true;
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
root.activeView = "notSetUp";
notSetUpTimer.start();
} else if (exists && root.activeView === "initialize") {
commerce.getWalletAuthenticatedStatus();
}
}
onWalletAuthenticatedStatusResult: {
if (!isAuthenticated && root.activeView !== "passphraseModal") {
root.activeView = "passphraseModal";
} else if (isAuthenticated) {
authSuccessStep();
} }
} }
onBuyResult: { onBuyResult: {
if (result.status !== 'success') { if (result.status !== 'success') {
failureErrorText.text = "Here's some more info about the error:<br><br>" + (result.message); failureErrorText.text = result.message;
root.activeView = "checkoutFailure"; root.activeView = "checkoutFailure";
} else { } else {
root.activeView = "checkoutSuccess"; root.activeView = "checkoutSuccess";
@ -123,6 +108,19 @@ Rectangle {
} }
} }
onItemIdChanged: {
commerce.inventory();
itemPreviewImage.source = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/" + itemId + "/thumbnail/hifi-mp-" + itemId + ".jpg";
}
onItemHrefChanged: {
itemIsJson = root.itemHref.indexOf('.json') !== -1;
}
onItemPriceChanged: {
commerce.balance();
}
Timer { Timer {
id: notSetUpTimer; id: notSetUpTimer;
interval: 200; interval: 200;
@ -176,6 +174,13 @@ Rectangle {
} }
} }
} }
MouseArea {
enabled: titleBarContainer.usernameDropdownVisible;
anchors.fill: parent;
onClicked: {
titleBarContainer.usernameDropdownVisible = false;
}
}
// //
// TITLE BAR END // TITLE BAR END
// //
@ -190,10 +195,9 @@ Rectangle {
color: hifi.colors.white; color: hifi.colors.white;
Component.onCompleted: { Component.onCompleted: {
securityImageResultReceived = false;
purchasesReceived = false; purchasesReceived = false;
balanceReceived = false; balanceReceived = false;
commerce.getLoginStatus(); commerce.getWalletStatus();
} }
} }
@ -281,7 +285,6 @@ Rectangle {
Image { Image {
id: itemPreviewImage; id: itemPreviewImage;
source: root.itemPreviewImageUrl;
anchors.left: parent.left; anchors.left: parent.left;
anchors.top: parent.top; anchors.top: parent.top;
anchors.bottom: parent.bottom; anchors.bottom: parent.bottom;
@ -291,6 +294,7 @@ Rectangle {
RalewaySemiBold { RalewaySemiBold {
id: itemNameText; id: itemNameText;
text: root.itemName;
// Text size // Text size
size: 26; size: 26;
// Anchors // Anchors
@ -315,19 +319,19 @@ Rectangle {
anchors.top: parent.top; anchors.top: parent.top;
anchors.right: parent.right; anchors.right: parent.right;
height: 30; height: 30;
width: childrenRect.width; width: itemPriceTextLabel.width + itemPriceText.width + 20;
// "HFC" balance label // "HFC" balance label
HiFiGlyphs { HiFiGlyphs {
id: itemPriceTextLabel; id: itemPriceTextLabel;
text: hifi.glyphs.hfc; text: hifi.glyphs.hfc;
// Size // Size
size: 36; size: 30;
// Anchors // Anchors
anchors.right: itemPriceText.left; anchors.right: itemPriceText.left;
anchors.rightMargin: 4; anchors.rightMargin: 4;
anchors.top: parent.top; anchors.top: parent.top;
anchors.topMargin: -4; anchors.topMargin: 0;
width: paintedWidth; width: paintedWidth;
height: paintedHeight; height: paintedHeight;
// Style // Style
@ -335,7 +339,7 @@ Rectangle {
} }
FiraSansSemiBold { FiraSansSemiBold {
id: itemPriceText; id: itemPriceText;
text: "--"; text: root.itemPrice;
// Text size // Text size
size: 26; size: 26;
// Anchors // Anchors
@ -405,7 +409,7 @@ Rectangle {
verticalAlignment: Text.AlignTop; verticalAlignment: Text.AlignTop;
} }
RalewaySemiBold { RalewayRegular {
id: buyText; id: buyText;
// Text size // Text size
size: 18; size: 18;
@ -424,7 +428,7 @@ Rectangle {
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;
onLinkActivated: { onLinkActivated: {
sendToScript({method: 'checkout_goToPurchases', filterText: itemNameText.text}); sendToScript({method: 'checkout_goToPurchases', filterText: root.itemName});
} }
} }
} }
@ -508,7 +512,7 @@ Rectangle {
RalewaySemiBold { RalewaySemiBold {
id: completeText2; id: completeText2;
text: "The item " + '<font color="' + hifi.colors.blueAccent + '"><a href="#">' + itemNameText.text + '</a></font>' + text: "The item " + '<font color="' + hifi.colors.blueAccent + '"><a href="#">' + root.itemName + '</a></font>' +
" has been added to your Purchases and a receipt will appear in your Wallet's transaction history."; " has been added to your Purchases and a receipt will appear in your Wallet's transaction history.";
// Text size // Text size
size: 20; size: 20;
@ -709,7 +713,9 @@ Rectangle {
anchors.top: titleBarContainer.bottom; anchors.top: titleBarContainer.bottom;
anchors.bottom: root.bottom; anchors.bottom: root.bottom;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 16;
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 16;
RalewayRegular { RalewayRegular {
id: failureHeaderText; id: failureHeaderText;
@ -718,57 +724,65 @@ Rectangle {
size: 24; size: 24;
// Anchors // Anchors
anchors.top: parent.top; anchors.top: parent.top;
anchors.topMargin: 80; anchors.topMargin: 40;
height: paintedHeight; height: paintedHeight;
anchors.left: parent.left; anchors.left: parent.left;
anchors.right: parent.right; anchors.right: parent.right;
// Style // Style
color: hifi.colors.black; color: hifi.colors.black;
wrapMode: Text.WordWrap; wrapMode: Text.WordWrap;
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
} }
RalewayRegular { Rectangle {
id: failureErrorText; id: failureErrorTextContainer;
// Text size
size: 16;
// Anchors
anchors.top: failureHeaderText.bottom; anchors.top: failureHeaderText.bottom;
anchors.topMargin: 35; anchors.topMargin: 35;
height: paintedHeight;
anchors.left: parent.left; anchors.left: parent.left;
anchors.right: parent.right; anchors.right: parent.right;
// Style height: failureErrorText.height + 30;
color: hifi.colors.black; radius: 4;
wrapMode: Text.WordWrap; border.width: 2;
// Alignment border.color: "#F3808F";
horizontalAlignment: Text.AlignHCenter; color: "#FFC3CD";
verticalAlignment: Text.AlignVCenter;
AnonymousProRegular {
id: failureErrorText;
// Text size
size: 16;
// Anchors
anchors.top: parent.top;
anchors.topMargin: 15;
anchors.left: parent.left;
anchors.leftMargin: 8;
anchors.right: parent.right;
anchors.rightMargin: 8;
height: paintedHeight;
// Style
color: hifi.colors.black;
wrapMode: Text.Wrap;
verticalAlignment: Text.AlignVCenter;
}
} }
Item { Item {
id: backToMarketplaceButtonContainer; id: backToMarketplaceButtonContainer;
// Size // Size
width: root.width; width: root.width;
height: 130; height: 50;
// Anchors // Anchors
anchors.left: parent.left; anchors.left: parent.left;
anchors.bottom: parent.bottom; anchors.bottom: parent.bottom;
anchors.bottomMargin: 8; anchors.bottomMargin: 16;
// "Back to Marketplace" button // "Back to Marketplace" button
HifiControlsUit.Button { HifiControlsUit.Button {
id: backToMarketplaceButton; id: backToMarketplaceButton;
color: hifi.buttons.black; color: hifi.buttons.noneBorderlessGray;
colorScheme: hifi.colorSchemes.light; colorScheme: hifi.colorSchemes.light;
anchors.top: parent.top; anchors.top: parent.top;
anchors.topMargin: 3;
anchors.bottom: parent.bottom; anchors.bottom: parent.bottom;
anchors.bottomMargin: 3; anchors.left: parent.left;
anchors.right: parent.right; anchors.leftMargin: 16;
anchors.rightMargin: 20; width: parent.width/2 - anchors.leftMargin*2;
width: parent.width/2 - anchors.rightMargin*2;
text: "Back to Marketplace"; text: "Back to Marketplace";
onClicked: { onClicked: {
sendToScript({method: 'checkout_continueShopping', itemId: itemId}); sendToScript({method: 'checkout_continueShopping', itemId: itemId});
@ -814,15 +828,9 @@ Rectangle {
switch (message.method) { switch (message.method) {
case 'updateCheckoutQML': case 'updateCheckoutQML':
itemId = message.params.itemId; itemId = message.params.itemId;
itemNameText.text = message.params.itemName; itemName = message.params.itemName;
root.itemPrice = message.params.itemPrice; root.itemPrice = message.params.itemPrice;
itemPriceText.text = root.itemPrice === 0 ? "Free" : root.itemPrice;
itemHref = message.params.itemHref; itemHref = message.params.itemHref;
itemPreviewImageUrl = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/" + itemId + "/thumbnail/hifi-mp-" + itemId + ".jpg";
if (itemHref.indexOf('.json') === -1) {
root.itemIsJson = false;
}
root.canRezCertifiedItems = message.canRezCertifiedItems;
setBuyText(); setBuyText();
break; break;
default: default:
@ -845,10 +853,10 @@ Rectangle {
if (root.purchasesReceived && root.balanceReceived) { if (root.purchasesReceived && root.balanceReceived) {
if (root.balanceAfterPurchase < 0) { if (root.balanceAfterPurchase < 0) {
if (root.alreadyOwned) { if (root.alreadyOwned) {
buyText.text = "Your Wallet does not have sufficient funds to purchase this item again.<br>" + buyText.text = "<b>Your Wallet does not have sufficient funds to purchase this item again.<br>" +
'<font color="' + hifi.colors.blueAccent + '"><a href="#">View the copy you own in My Purchases</a></font>'; '<font color="' + hifi.colors.blueAccent + '"><a href="#">View the copy you own in My Purchases</a></font></b>';
} else { } else {
buyText.text = "Your Wallet does not have sufficient funds to purchase this item."; buyText.text = "<b>Your Wallet does not have sufficient funds to purchase this item.</b>";
} }
buyTextContainer.color = "#FFC3CD"; buyTextContainer.color = "#FFC3CD";
buyTextContainer.border.color = "#F3808F"; buyTextContainer.border.color = "#F3808F";
@ -856,8 +864,8 @@ Rectangle {
buyGlyph.size = 54; buyGlyph.size = 54;
} else { } else {
if (root.alreadyOwned) { if (root.alreadyOwned) {
buyText.text = 'You already own this item.<br>Purchasing it will buy another copy.<br><font color="' buyText.text = '<b>You already own this item.<br>Purchasing it will buy another copy.<br><font color="'
+ hifi.colors.blueAccent + '"><a href="#">View this item in My Purchases</a></font>'; + hifi.colors.blueAccent + '"><a href="#">View this item in My Purchases</a></font></b>';
buyTextContainer.color = "#FFD6AD"; buyTextContainer.color = "#FFD6AD";
buyTextContainer.border.color = "#FAC07D"; buyTextContainer.border.color = "#FAC07D";
buyGlyph.text = hifi.glyphs.alert; buyGlyph.text = hifi.glyphs.alert;
@ -870,7 +878,7 @@ Rectangle {
buyText.text = ""; buyText.text = "";
} }
} else { } else {
buyText.text = "This Marketplace item isn't an entity. It <b>will not</b> be added to your <b>Purchases</b>."; buyText.text = "This free item <b>will not</b> be added to your <b>Purchases</b>. Non-entities can't yet be purchased for HFC.";
buyTextContainer.color = "#FFD6AD"; buyTextContainer.color = "#FFD6AD";
buyTextContainer.border.color = "#FAC07D"; buyTextContainer.border.color = "#FAC07D";
buyGlyph.text = hifi.glyphs.alert; buyGlyph.text = hifi.glyphs.alert;
@ -884,12 +892,6 @@ Rectangle {
} else { } else {
root.activeView = "checkoutSuccess"; root.activeView = "checkoutSuccess";
} }
if (!balanceReceived) {
commerce.balance();
}
if (!purchasesReceived) {
commerce.inventory();
}
} }
// //

View file

@ -82,6 +82,7 @@ Rectangle {
height: 140; height: 140;
fillMode: Image.PreserveAspectFit; fillMode: Image.PreserveAspectFit;
mipmap: true; mipmap: true;
cache: false;
} }
RalewayRegular { RalewayRegular {

View file

@ -27,23 +27,28 @@ Item {
id: root; id: root;
property string referrerURL: "https://metaverse.highfidelity.com/marketplace?"; property string referrerURL: "https://metaverse.highfidelity.com/marketplace?";
readonly property int additionalDropdownHeight: usernameDropdown.height - myUsernameButton.anchors.bottomMargin; readonly property int additionalDropdownHeight: usernameDropdown.height - myUsernameButton.anchors.bottomMargin;
property alias usernameDropdownVisible: usernameDropdown.visible;
height: mainContainer.height + additionalDropdownHeight; height: mainContainer.height + additionalDropdownHeight;
Hifi.QmlCommerce { Hifi.QmlCommerce {
id: commerce; id: commerce;
onLoginStatusResult: { onWalletStatusResult: {
if (!isLoggedIn) { if (walletStatus === 0) {
sendToParent({method: "needsLogIn"}); sendToParent({method: "needsLogIn"});
} else if (walletStatus === 3) {
commerce.getSecurityImage();
} else {
console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus);
} }
} }
onAccountResult: { onLoginStatusResult: {
if (result.status === "success") { if (!isLoggedIn) {
commerce.getKeyFilePathIfExists(); sendToParent({method: "needsLogIn"});
} else { } else {
// unsure how to handle a failure here. We definitely cannot proceed. commerce.getWalletStatus();
} }
} }
@ -56,8 +61,7 @@ Item {
} }
Component.onCompleted: { Component.onCompleted: {
commerce.getLoginStatus(); commerce.getWalletStatus();
commerce.getSecurityImage();
} }
Connections { Connections {
@ -210,6 +214,7 @@ Item {
anchors.bottomMargin: 16; anchors.bottomMargin: 16;
width: height; width: height;
mipmap: true; mipmap: true;
cache: false;
MouseArea { MouseArea {
enabled: securityImage.visible; enabled: securityImage.visible;

View file

@ -0,0 +1,68 @@
//
// SortableListModel.qml
// qml/hifi/commerce/common
//
// SortableListModel
//
// Created by Zach Fox on 2017-09-28
// 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;
property string sortColumnName: "";
property bool isSortingDescending: true;
function swap(a, b) {
if (a < b) {
move(a, b, 1);
move (b - 1, a, 1);
} else if (a > b) {
move(b, a, 1);
move(a - 1, b, 1);
}
}
function partition(begin, end, pivot) {
var piv = get(pivot)[sortColumnName];
swap(pivot, end - 1);
var store = begin;
for (var i = begin; i < end - 1; ++i) {
if (isSortingDescending) {
if (get(i)[sortColumnName] < piv) {
swap(store, i);
++store;
}
} else {
if (get(i)[sortColumnName] > piv) {
swap(store, i);
++store;
}
}
}
swap(end - 1, store);
return store;
}
function qsort(begin, end) {
if (end - 1 > begin) {
var pivot = begin + Math.floor(Math.random() * (end - begin));
pivot = partition(begin, end, pivot);
qsort(begin, pivot);
qsort(pivot + 1, end);
}
}
function quickSort() {
qsort(0, count)
}
}

View file

@ -30,12 +30,20 @@ Rectangle {
property string itemOwner: "--"; property string itemOwner: "--";
property string itemEdition: "--"; property string itemEdition: "--";
property string dateOfPurchase: ""; property string dateOfPurchase: "";
property bool closeGoesToPurchases: false; property bool isLightbox: false;
// Style // Style
color: hifi.colors.faintGray; color: hifi.colors.faintGray;
Hifi.QmlCommerce { Hifi.QmlCommerce {
id: commerce; id: commerce;
} }
// 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;
}
Image { Image {
anchors.fill: parent; anchors.fill: parent;
@ -262,7 +270,11 @@ Rectangle {
height: 50; height: 50;
text: "close"; text: "close";
onClicked: { onClicked: {
sendToScript({method: 'inspectionCertificate_closeClicked', closeGoesToPurchases: root.closeGoesToPurchases}); if (root.isLightbox) {
root.visible = false;
} else {
sendToScript({method: 'inspectionCertificate_closeClicked', closeGoesToPurchases: root.closeGoesToPurchases});
}
} }
} }
@ -303,7 +315,6 @@ Rectangle {
switch (message.method) { switch (message.method) {
case 'inspectionCertificate_setMarketplaceId': case 'inspectionCertificate_setMarketplaceId':
root.marketplaceId = message.marketplaceId; root.marketplaceId = message.marketplaceId;
root.closeGoesToPurchases = message.closeGoesToPurchases;
break; break;
case 'inspectionCertificate_setItemInfo': case 'inspectionCertificate_setItemInfo':
root.itemName = message.itemName; root.itemName = message.itemName;

View file

@ -13,6 +13,7 @@
import Hifi 1.0 as Hifi import Hifi 1.0 as Hifi
import QtQuick 2.5 import QtQuick 2.5
import QtGraphicalEffects 1.0
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import "../../../styles-uit" import "../../../styles-uit"
import "../../../controls-uit" as HifiControlsUit import "../../../controls-uit" as HifiControlsUit
@ -24,40 +25,133 @@ Rectangle {
HifiConstants { id: hifi; } HifiConstants { id: hifi; }
id: root; id: root;
property string activeView: "step_1"; property int activeView: 1;
// Style
color: hifi.colors.baseGray; Image {
anchors.fill: parent;
source: "images/Purchase-First-Run-" + root.activeView + ".jpg";
}
// 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;
}
Item {
id: header;
anchors.top: parent.top;
anchors.left: parent.left;
anchors.right: parent.right;
height: childrenRect.height;
Image {
id: marketplaceHeaderImage;
source: "../common/images/marketplaceHeaderImage.png";
anchors.top: parent.top;
anchors.topMargin: 2;
anchors.left: parent.left;
anchors.leftMargin: 8;
width: 140;
height: 58;
fillMode: Image.PreserveAspectFit;
visible: false;
}
ColorOverlay {
anchors.fill: marketplaceHeaderImage;
source: marketplaceHeaderImage;
color: "#FFFFFF"
}
RalewayRegular {
id: introText1;
text: "INTRODUCTION TO";
// Text size
size: 15;
// Anchors
anchors.top: marketplaceHeaderImage.bottom;
anchors.topMargin: 8;
anchors.left: parent.left;
anchors.leftMargin: 12;
anchors.right: parent.right;
height: paintedHeight;
// Style
color: hifi.colors.white;
}
RalewayRegular {
id: introText2;
text: "My Purchases";
// Text size
size: 28;
// Anchors
anchors.top: introText1.bottom;
anchors.left: parent.left;
anchors.leftMargin: 12;
anchors.right: parent.right;
height: paintedHeight;
// Style
color: hifi.colors.white;
}
}
// //
// "STEP 1" START // "STEP 1" START
// //
Item { Item {
id: step_1; id: step_1;
visible: root.activeView === "step_1"; visible: root.activeView === 1;
anchors.top: parent.top; anchors.top: header.bottom;
anchors.topMargin: 100;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 30;
anchors.right: parent.right; anchors.right: parent.right;
anchors.bottom: tutorialActionButtonsContainer.top; anchors.bottom: parent.bottom;
RalewayRegular { RalewayRegular {
id: step1text; id: step1text;
text: "<b>This is the first-time Purchases tutorial.</b><br><br>Here is some <b>bold text</b> " + text: "The <b>'REZ IT'</b> button makes your purchase appear in front of you.";
"inside Step 1.";
// Text size // Text size
size: 24; size: 20;
// Anchors // Anchors
anchors.top: parent.top; anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 16; width: 180;
height: paintedHeight;
// Style
color: hifi.colors.white;
wrapMode: Text.WordWrap;
}
// "Next" button
HifiControlsUit.Button {
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.dark;
anchors.top: step1text.bottom;
anchors.topMargin: 16;
anchors.left: parent.left;
width: 150;
height: 40;
text: "Next";
onClicked: {
root.activeView++;
}
}
// "SKIP" button
HifiControlsUit.Button {
color: hifi.buttons.noneBorderlessGray;
colorScheme: hifi.colorSchemes.dark;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 32;
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 16; anchors.rightMargin: 16;
// Style width: 150;
color: hifi.colors.faintGray; height: 40;
wrapMode: Text.WordWrap; text: "SKIP";
// Alignment onClicked: {
horizontalAlignment: Text.AlignHCenter; sendSignalToParent({method: 'tutorial_finished'});
verticalAlignment: Text.AlignVCenter; }
} }
} }
// //
@ -69,127 +163,52 @@ Rectangle {
// //
Item { Item {
id: step_2; id: step_2;
visible: root.activeView === "step_2"; visible: root.activeView === 2;
anchors.top: parent.top; anchors.top: header.bottom;
anchors.topMargin: 45;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 30;
anchors.right: parent.right; anchors.right: parent.right;
anchors.bottom: tutorialActionButtonsContainer.top; anchors.bottom: parent.bottom;
RalewayRegular { RalewayRegular {
id: step2text; id: step2text;
text: "<b>STEP TWOOO!!!</b>"; text: "If you rez an item twice, the first one will disappear.";
// Text size // Text size
size: 24; size: 20;
// Anchors // Anchors
anchors.top: parent.top; anchors.top: parent.top;
anchors.bottom: parent.bottom;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 16; width: 180;
anchors.right: parent.right; height: paintedHeight;
anchors.rightMargin: 16;
// Style // Style
color: hifi.colors.faintGray; color: hifi.colors.white;
wrapMode: Text.WordWrap; wrapMode: Text.WordWrap;
// Alignment }
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter; // "GOT IT" button
HifiControlsUit.Button {
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.dark;
anchors.top: step2text.bottom;
anchors.topMargin: 16;
anchors.left: parent.left;
width: 150;
height: 40;
text: "GOT IT";
onClicked: {
sendSignalToParent({method: 'tutorial_finished'});
}
} }
} }
// //
// "STEP 2" END // "STEP 2" END
// //
Item {
id: tutorialActionButtonsContainer;
// Size
width: root.width;
height: 70;
// Anchors
anchors.left: parent.left;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 24;
// "Skip" or "Back" button
HifiControlsUit.Button {
id: skipOrBackButton;
color: hifi.buttons.black;
colorScheme: hifi.colorSchemes.dark;
anchors.top: parent.top;
anchors.topMargin: 3;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 3;
anchors.left: parent.left;
anchors.leftMargin: 20;
width: parent.width/2 - anchors.leftMargin*2;
text: root.activeView === "step_1" ? "Skip" : "Back";
onClicked: {
if (root.activeView === "step_1") {
sendSignalToParent({method: 'tutorial_skipClicked'});
} else {
root.activeView = "step_" + (parseInt(root.activeView.split("_")[1]) - 1);
}
}
}
// "Next" or "Finish" button
HifiControlsUit.Button {
id: nextButton;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.dark;
anchors.top: parent.top;
anchors.topMargin: 3;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 3;
anchors.right: parent.right;
anchors.rightMargin: 20;
width: parent.width/2 - anchors.rightMargin*2;
text: root.activeView === "step_2" ? "Finish" : "Next";
onClicked: {
// If this is the final step...
if (root.activeView === "step_2") {
sendSignalToParent({method: 'tutorial_finished'});
} else {
root.activeView = "step_" + (parseInt(root.activeView.split("_")[1]) + 1);
}
}
}
}
// //
// FUNCTION DEFINITIONS START // FUNCTION DEFINITIONS START
// //
//
// Function Name: fromScript()
//
// Relevant Variables:
// None
//
// Arguments:
// message: The message sent from the JavaScript, in this case the Marketplaces JavaScript.
// Messages are in format "{method, params}", like json-rpc.
//
// Description:
// Called when a message is received from a script.
//
function fromScript(message) {
switch (message.method) {
case 'updatePurchases':
referrerURL = message.referrerURL;
break;
case 'purchases_getIsFirstUseResult':
if (message.isFirstUseOfPurchases && root.activeView !== "firstUseTutorial") {
root.activeView = "firstUseTutorial";
} else if (!message.isFirstUseOfPurchases && root.activeView === "initialize") {
root.activeView = "purchasesMain";
commerce.inventory();
}
break;
default:
console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
}
}
signal sendSignalToParent(var message); signal sendSignalToParent(var message);
// //
// FUNCTION DEFINITIONS END // FUNCTION DEFINITIONS END
// //

View file

@ -34,14 +34,19 @@ Item {
property string itemId; property string itemId;
property string itemPreviewImageUrl; property string itemPreviewImageUrl;
property string itemHref; property string itemHref;
property int ownedItemCount; property int displayedItemCount;
property int itemEdition; property int itemEdition;
property string originalStatusText;
property string originalStatusColor;
height: 110; height: 110;
width: parent.width; width: parent.width;
onPurchaseStatusChangedChanged: { onPurchaseStatusChangedChanged: {
if (root.purchaseStatusChanged === true && root.purchaseStatus === "confirmed") { if (root.purchaseStatusChanged === true && root.purchaseStatus === "confirmed") {
root.originalStatusText = statusText.text;
root.originalStatusColor = statusText.color;
statusText.text = "CONFIRMED!"; statusText.text = "CONFIRMED!";
statusText.color = hifi.colors.blueAccent; statusText.color = hifi.colors.blueAccent;
confirmedTimer.start(); confirmedTimer.start();
@ -53,7 +58,8 @@ Item {
id: confirmedTimer; id: confirmedTimer;
interval: 3000; interval: 3000;
onTriggered: { onTriggered: {
root.purchaseStatus = ""; statusText.text = root.originalStatusText;
statusText.color = root.originalStatusColor;
} }
} }
@ -174,9 +180,30 @@ Item {
} }
Item { Item {
id: statusContainer; id: editionContainer;
visible: root.displayedItemCount > 1 && !statusContainer.visible;
anchors.left: itemName.left;
anchors.top: certificateContainer.bottom;
anchors.topMargin: 8;
anchors.bottom: parent.bottom;
anchors.right: buttonContainer.left;
anchors.rightMargin: 2;
visible: root.purchaseStatus || root.ownedItemCount > 1; FiraSansRegular {
anchors.left: parent.left;
anchors.top: parent.top;
anchors.bottom: parent.bottom;
width: paintedWidth;
text: "#" + root.itemEdition;
size: 15;
color: "#cc6a6a6a";
verticalAlignment: Text.AlignTop;
}
}
Item {
id: statusContainer;
visible: root.purchaseStatus === "pending" || root.purchaseStatus === "invalidated";
anchors.left: itemName.left; anchors.left: itemName.left;
anchors.top: certificateContainer.bottom; anchors.top: certificateContainer.bottom;
anchors.topMargin: 8; anchors.topMargin: 8;
@ -195,8 +222,6 @@ Item {
"PENDING..." "PENDING..."
} else if (root.purchaseStatus === "invalidated") { } else if (root.purchaseStatus === "invalidated") {
"INVALIDATED" "INVALIDATED"
} else if (root.ownedItemCount > 1) {
"<font color='#6a6a6a'>(#" + root.itemEdition + ")</font> <u>You own " + root.ownedItemCount + " others</u>"
} else { } else {
"" ""
} }
@ -207,8 +232,6 @@ Item {
hifi.colors.blueAccent hifi.colors.blueAccent
} else if (root.purchaseStatus === "invalidated") { } else if (root.purchaseStatus === "invalidated") {
hifi.colors.redAccent hifi.colors.redAccent
} else if (root.ownedItemCount > 1) {
hifi.colors.blueAccent
} else { } else {
hifi.colors.baseGray hifi.colors.baseGray
} }
@ -240,8 +263,6 @@ Item {
hifi.colors.blueAccent hifi.colors.blueAccent
} else if (root.purchaseStatus === "invalidated") { } else if (root.purchaseStatus === "invalidated") {
hifi.colors.redAccent hifi.colors.redAccent
} else if (root.ownedItemCount > 1) {
hifi.colors.blueAccent
} else { } else {
hifi.colors.baseGray hifi.colors.baseGray
} }
@ -257,8 +278,6 @@ Item {
sendToPurchases({method: 'showPendingLightbox'}); sendToPurchases({method: 'showPendingLightbox'});
} else if (root.purchaseStatus === "invalidated") { } else if (root.purchaseStatus === "invalidated") {
sendToPurchases({method: 'showInvalidatedLightbox'}); sendToPurchases({method: 'showInvalidatedLightbox'});
} else if (root.ownedItemCount > 1) {
sendToPurchases({method: 'setFilterText', filterText: root.itemName});
} }
} }
onEntered: { onEntered: {
@ -268,9 +287,6 @@ Item {
} else if (root.purchaseStatus === "invalidated") { } else if (root.purchaseStatus === "invalidated") {
statusText.color = hifi.colors.redAccent; statusText.color = hifi.colors.redAccent;
statusIcon.color = hifi.colors.redAccent; statusIcon.color = hifi.colors.redAccent;
} else if (root.ownedItemCount > 1) {
statusText.color = hifi.colors.blueHighlight;
statusIcon.color = hifi.colors.blueHighlight;
} }
} }
onExited: { onExited: {
@ -280,9 +296,6 @@ Item {
} else if (root.purchaseStatus === "invalidated") { } else if (root.purchaseStatus === "invalidated") {
statusText.color = hifi.colors.redHighlight; statusText.color = hifi.colors.redHighlight;
statusIcon.color = hifi.colors.redHighlight; statusIcon.color = hifi.colors.redHighlight;
} else if (root.ownedItemCount > 1) {
statusText.color = hifi.colors.blueAccent;
statusIcon.color = hifi.colors.blueAccent;
} }
} }
} }

View file

@ -19,6 +19,7 @@ import "../../../controls-uit" as HifiControlsUit
import "../../../controls" as HifiControls import "../../../controls" as HifiControls
import "../wallet" as HifiWallet import "../wallet" as HifiWallet
import "../common" as HifiCommerceCommon import "../common" as HifiCommerceCommon
import "../inspectionCertificate" as HifiInspectionCertificate
// references XXX from root context // references XXX from root context
@ -31,54 +32,46 @@ Rectangle {
property bool securityImageResultReceived: false; property bool securityImageResultReceived: false;
property bool purchasesReceived: false; property bool purchasesReceived: false;
property bool punctuationMode: false; property bool punctuationMode: false;
property bool canRezCertifiedItems: false; property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified;
property bool pendingInventoryReply: true; property bool pendingInventoryReply: true;
property bool isShowingMyItems: false;
property bool isDebuggingFirstUseTutorial: false;
// Style // Style
color: hifi.colors.white; color: hifi.colors.white;
Hifi.QmlCommerce { Hifi.QmlCommerce {
id: commerce; id: commerce;
onWalletStatusResult: {
if (walletStatus === 0) {
if (root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn";
}
} else if (walletStatus === 1) {
if (root.activeView !== "notSetUp") {
root.activeView = "notSetUp";
notSetUpTimer.start();
}
} else if (walletStatus === 2) {
if (root.activeView !== "passphraseModal") {
root.activeView = "passphraseModal";
}
} else if (walletStatus === 3) {
if ((Settings.getValue("isFirstUseOfPurchases", true) || root.isDebuggingFirstUseTutorial) && root.activeView !== "firstUseTutorial") {
root.activeView = "firstUseTutorial";
} else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") {
root.activeView = "purchasesMain";
commerce.inventory();
}
} else {
console.log("ERROR in Purchases.qml: Unknown wallet status: " + walletStatus);
}
}
onLoginStatusResult: { onLoginStatusResult: {
if (!isLoggedIn && root.activeView !== "needsLogIn") { if (!isLoggedIn && root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn"; root.activeView = "needsLogIn";
} else if (isLoggedIn) {
root.activeView = "initialize";
commerce.account();
}
}
onAccountResult: {
if (result.status === "success") {
commerce.getKeyFilePathIfExists();
} else { } else {
// unsure how to handle a failure here. We definitely cannot proceed. commerce.getWalletStatus();
}
}
onKeyFilePathIfExistsResult: {
if (path === "" && root.activeView !== "notSetUp") {
root.activeView = "notSetUp";
notSetUpTimer.start();
} else if (path !== "" && root.activeView === "initialize") {
commerce.getSecurityImage();
}
}
onSecurityImageResult: {
securityImageResultReceived = true;
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
root.activeView = "notSetUp";
notSetUpTimer.start();
} else if (exists && root.activeView === "initialize") {
commerce.getWalletAuthenticatedStatus();
}
}
onWalletAuthenticatedStatusResult: {
if (!isAuthenticated && root.activeView !== "passphraseModal") {
root.activeView = "passphraseModal";
} else if (isAuthenticated) {
sendToScript({method: 'purchases_getIsFirstUse'});
} }
} }
@ -121,6 +114,19 @@ Rectangle {
} }
} }
HifiInspectionCertificate.InspectionCertificate {
id: inspectionCertificate;
z: 999;
visible: false;
anchors.fill: parent;
Connections {
onSendToScript: {
sendToScript(message);
}
}
}
HifiCommerceCommon.CommerceLightbox { HifiCommerceCommon.CommerceLightbox {
id: lightboxPopup; id: lightboxPopup;
visible: false; visible: false;
@ -165,6 +171,13 @@ Rectangle {
} }
} }
} }
MouseArea {
enabled: titleBarContainer.usernameDropdownVisible;
anchors.fill: parent;
onClicked: {
titleBarContainer.usernameDropdownVisible = false;
}
}
// //
// TITLE BAR END // TITLE BAR END
// //
@ -182,7 +195,7 @@ Rectangle {
Component.onCompleted: { Component.onCompleted: {
securityImageResultReceived = false; securityImageResultReceived = false;
purchasesReceived = false; purchasesReceived = false;
commerce.getLoginStatus(); commerce.getWalletStatus();
} }
} }
@ -218,7 +231,7 @@ Rectangle {
onSendSignalToParent: { onSendSignalToParent: {
if (msg.method === "authSuccess") { if (msg.method === "authSuccess") {
root.activeView = "initialize"; root.activeView = "initialize";
sendToScript({method: 'purchases_getIsFirstUse'}); commerce.getWalletStatus();
} else { } else {
sendToScript(msg); sendToScript(msg);
} }
@ -228,19 +241,16 @@ Rectangle {
FirstUseTutorial { FirstUseTutorial {
id: firstUseTutorial; id: firstUseTutorial;
z: 999;
visible: root.activeView === "firstUseTutorial"; visible: root.activeView === "firstUseTutorial";
anchors.top: titleBarContainer.bottom; anchors.fill: parent;
anchors.topMargin: -titleBarContainer.additionalDropdownHeight;
anchors.bottom: parent.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
Connections { Connections {
onSendSignalToParent: { onSendSignalToParent: {
switch (message.method) { switch (message.method) {
case 'tutorial_skipClicked': case 'tutorial_skipClicked':
case 'tutorial_finished': case 'tutorial_finished':
sendToScript({method: 'purchases_setIsFirstUse'}); Settings.setValue("isFirstUseOfPurchases", false);
root.activeView = "purchasesMain"; root.activeView = "purchasesMain";
commerce.inventory(); commerce.inventory();
break; break;
@ -278,7 +288,7 @@ Rectangle {
anchors.topMargin: 4; anchors.topMargin: 4;
RalewayRegular { RalewayRegular {
id: myPurchasesText; id: myText;
anchors.top: parent.top; anchors.top: parent.top;
anchors.topMargin: 10; anchors.topMargin: 10;
anchors.bottom: parent.bottom; anchors.bottom: parent.bottom;
@ -286,7 +296,7 @@ Rectangle {
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 4; anchors.leftMargin: 4;
width: paintedWidth; width: paintedWidth;
text: "My Purchases"; text: isShowingMyItems ? "My Items" : "My Purchases";
color: hifi.colors.baseGray; color: hifi.colors.baseGray;
size: 28; size: 28;
} }
@ -296,7 +306,7 @@ Rectangle {
colorScheme: hifi.colorSchemes.faintGray; colorScheme: hifi.colorSchemes.faintGray;
hasClearButton: true; hasClearButton: true;
hasRoundedBorder: true; hasRoundedBorder: true;
anchors.left: myPurchasesText.right; anchors.left: myText.right;
anchors.leftMargin: 16; anchors.leftMargin: 16;
anchors.top: parent.top; anchors.top: parent.top;
anchors.bottom: parent.bottom; anchors.bottom: parent.bottom;
@ -331,7 +341,7 @@ Rectangle {
ListModel { ListModel {
id: previousPurchasesModel; id: previousPurchasesModel;
} }
ListModel { HifiCommerceCommon.SortableListModel {
id: filteredPurchasesModel; id: filteredPurchasesModel;
} }
@ -400,7 +410,7 @@ Rectangle {
ListView { ListView {
id: purchasesContentsList; id: purchasesContentsList;
visible: purchasesModel.count !== 0; visible: (root.isShowingMyItems && filteredPurchasesModel.count !== 0) || (!root.isShowingMyItems && filteredPurchasesModel.count !== 0);
clip: true; clip: true;
model: filteredPurchasesModel; model: filteredPurchasesModel;
// Anchors // Anchors
@ -417,6 +427,8 @@ Rectangle {
itemHref: root_file_url; itemHref: root_file_url;
purchaseStatus: status; purchaseStatus: status;
purchaseStatusChanged: statusChanged; purchaseStatusChanged: statusChanged;
itemEdition: model.edition_number;
displayedItemCount: model.displayedItemCount;
anchors.topMargin: 12; anchors.topMargin: 12;
anchors.bottomMargin: 12; anchors.bottomMargin: 12;
@ -425,6 +437,8 @@ Rectangle {
if (msg.method === 'purchases_itemInfoClicked') { if (msg.method === 'purchases_itemInfoClicked') {
sendToScript({method: 'purchases_itemInfoClicked', itemId: itemId}); sendToScript({method: 'purchases_itemInfoClicked', itemId: itemId});
} else if (msg.method === 'purchases_itemCertificateClicked') { } else if (msg.method === 'purchases_itemCertificateClicked') {
inspectionCertificate.visible = true;
inspectionCertificate.isLightbox = true;
sendToScript(msg); sendToScript(msg);
} else if (msg.method === "showInvalidatedLightbox") { } else if (msg.method === "showInvalidatedLightbox") {
lightboxPopup.titleText = "Item Invalidated"; lightboxPopup.titleText = "Item Invalidated";
@ -448,9 +462,55 @@ Rectangle {
} }
} }
Item {
id: noItemsAlertContainer;
visible: !purchasesContentsList.visible && root.purchasesReceived && root.isShowingMyItems && filterBar.text === "";
anchors.top: filterBarContainer.bottom;
anchors.topMargin: 12;
anchors.left: parent.left;
anchors.bottom: parent.bottom;
width: parent.width;
// Explanitory text
RalewayRegular {
id: noItemsYet;
text: "<b>You haven't submitted anything to the Marketplace yet!</b><br><br>Submit an item to the Marketplace to add it to My Items.";
// Text size
size: 22;
// Anchors
anchors.top: parent.top;
anchors.topMargin: 150;
anchors.left: parent.left;
anchors.leftMargin: 24;
anchors.right: parent.right;
anchors.rightMargin: 24;
height: paintedHeight;
// Style
color: hifi.colors.baseGray;
wrapMode: Text.WordWrap;
// Alignment
horizontalAlignment: Text.AlignHCenter;
}
// "Go To Marketplace" button
HifiControlsUit.Button {
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.dark;
anchors.top: noItemsYet.bottom;
anchors.topMargin: 20;
anchors.horizontalCenter: parent.horizontalCenter;
width: parent.width * 2 / 3;
height: 50;
text: "Visit Marketplace";
onClicked: {
sendToScript({method: 'purchases_goToMarketplaceClicked'});
}
}
}
Item { Item {
id: noPurchasesAlertContainer; id: noPurchasesAlertContainer;
visible: !purchasesContentsList.visible && root.purchasesReceived; visible: !purchasesContentsList.visible && root.purchasesReceived && !root.isShowingMyItems && filterBar.text === "";
anchors.top: filterBarContainer.bottom; anchors.top: filterBarContainer.bottom;
anchors.topMargin: 12; anchors.topMargin: 12;
anchors.left: parent.left; anchors.left: parent.left;
@ -478,7 +538,7 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter; horizontalAlignment: Text.AlignHCenter;
} }
// "Set Up" button // "Go To Marketplace" button
HifiControlsUit.Button { HifiControlsUit.Button {
color: hifi.buttons.blue; color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.dark; colorScheme: hifi.colorSchemes.dark;
@ -530,17 +590,43 @@ Rectangle {
// FUNCTION DEFINITIONS START // FUNCTION DEFINITIONS START
// //
function populateDisplayedItemCounts() {
var itemCountDictionary = {};
var currentItemId;
for (var i = 0; i < filteredPurchasesModel.count; i++) {
currentItemId = filteredPurchasesModel.get(i).id;
if (itemCountDictionary[currentItemId] === undefined) {
itemCountDictionary[currentItemId] = 1;
} else {
itemCountDictionary[currentItemId]++;
}
}
for (var i = 0; i < filteredPurchasesModel.count; i++) {
filteredPurchasesModel.setProperty(i, "displayedItemCount", itemCountDictionary[filteredPurchasesModel.get(i).id]);
}
}
function sortByDate() {
filteredPurchasesModel.sortColumnName = "purchase_date";
filteredPurchasesModel.isSortingDescending = false;
filteredPurchasesModel.quickSort();
}
function buildFilteredPurchasesModel() { function buildFilteredPurchasesModel() {
filteredPurchasesModel.clear(); filteredPurchasesModel.clear();
for (var i = 0; i < purchasesModel.count; i++) { for (var i = 0; i < purchasesModel.count; i++) {
if (purchasesModel.get(i).title.toLowerCase().indexOf(filterBar.text.toLowerCase()) !== -1) { if (purchasesModel.get(i).title.toLowerCase().indexOf(filterBar.text.toLowerCase()) !== -1) {
if (purchasesModel.get(i).status !== "confirmed") { if (purchasesModel.get(i).status !== "confirmed" && !root.isShowingMyItems) {
filteredPurchasesModel.insert(0, purchasesModel.get(i)); filteredPurchasesModel.insert(0, purchasesModel.get(i));
} else { } else if ((root.isShowingMyItems && purchasesModel.get(i).edition_number === -1) || !root.isShowingMyItems) {
filteredPurchasesModel.append(purchasesModel.get(i)); filteredPurchasesModel.append(purchasesModel.get(i));
} }
} }
} }
populateDisplayedItemCounts();
sortByDate();
} }
function checkIfAnyItemStatusChanged() { function checkIfAnyItemStatusChanged() {
@ -581,16 +667,14 @@ Rectangle {
case 'updatePurchases': case 'updatePurchases':
referrerURL = message.referrerURL; referrerURL = message.referrerURL;
titleBarContainer.referrerURL = message.referrerURL; titleBarContainer.referrerURL = message.referrerURL;
root.canRezCertifiedItems = message.canRezCertifiedItems;
filterBar.text = message.filterText ? message.filterText : ""; filterBar.text = message.filterText ? message.filterText : "";
break; break;
case 'purchases_getIsFirstUseResult': case 'inspectionCertificate_setMarketplaceId':
if (message.isFirstUseOfPurchases && root.activeView !== "firstUseTutorial") { case 'inspectionCertificate_setItemInfo':
root.activeView = "firstUseTutorial"; inspectionCertificate.fromScript(message);
} else if (!message.isFirstUseOfPurchases && root.activeView === "initialize") { break;
root.activeView = "purchasesMain"; case 'purchases_showMyItems':
commerce.inventory(); root.isShowingMyItems = true;
}
break; break;
default: default:
console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message)); console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View file

@ -90,7 +90,7 @@ Item {
} else { } else {
// Error submitting new passphrase // Error submitting new passphrase
resetSubmitButton(); resetSubmitButton();
passphraseSelection.setErrorText("Backend error"); passphraseSelection.setErrorText("Current passphrase incorrect - try again");
} }
} else { } else {
sendSignalToWallet(msg); sendSignalToWallet(msg);
@ -137,9 +137,10 @@ Item {
width: 150; width: 150;
text: "Submit"; text: "Submit";
onClicked: { onClicked: {
if (passphraseSelection.validateAndSubmitPassphrase()) { passphraseSubmitButton.text = "Submitting...";
passphraseSubmitButton.text = "Submitting..."; passphraseSubmitButton.enabled = false;
passphraseSubmitButton.enabled = false; if (!passphraseSelection.validateAndSubmitPassphrase()) {
resetSubmitButton();
} }
} }
} }

View file

@ -129,6 +129,7 @@ Item {
width: height; width: height;
fillMode: Image.PreserveAspectFit; fillMode: Image.PreserveAspectFit;
mipmap: true; mipmap: true;
cache: false;
MouseArea { MouseArea {
enabled: titleBarSecurityImage.visible; enabled: titleBarSecurityImage.visible;

View file

@ -26,6 +26,7 @@ Item {
id: root; id: root;
property bool isChangingPassphrase: false; property bool isChangingPassphrase: false;
property bool isShowingTip: false; property bool isShowingTip: false;
property bool shouldImmediatelyFocus: true;
// This object is always used in a popup. // This object is always used in a popup.
// This MouseArea is used to prevent a user from being // This MouseArea is used to prevent a user from being
@ -42,8 +43,8 @@ Item {
passphrasePageSecurityImage.source = "image://security/securityImage"; passphrasePageSecurityImage.source = "image://security/securityImage";
} }
onWalletAuthenticatedStatusResult: { onChangePassphraseStatusResult: {
sendMessageToLightbox({method: 'statusResult', status: isAuthenticated}); sendMessageToLightbox({method: 'statusResult', status: changeSuccess});
} }
} }
@ -53,10 +54,8 @@ Item {
// TODO: Fix this unlikely bug // TODO: Fix this unlikely bug
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
if (root.isChangingPassphrase) { if (root.shouldImmediatelyFocus) {
currentPassphraseField.focus = true; focusFirstTextField();
} else {
passphraseField.focus = true;
} }
sendMessageToLightbox({method: 'disableHmdPreview'}); sendMessageToLightbox({method: 'disableHmdPreview'});
} else { } else {
@ -311,7 +310,7 @@ Item {
passphraseFieldAgain.error = false; passphraseFieldAgain.error = false;
currentPassphraseField.error = false; currentPassphraseField.error = false;
setErrorText(""); setErrorText("");
commerce.setPassphrase(passphraseField.text); commerce.changePassphrase(currentPassphraseField.text, passphraseField.text);
return true; return true;
} }
} }
@ -327,5 +326,13 @@ Item {
setErrorText(""); setErrorText("");
} }
function focusFirstTextField() {
if (root.isChangingPassphrase) {
currentPassphraseField.focus = true;
} else {
passphraseField.focus = true;
}
}
signal sendMessageToLightbox(var msg); signal sendMessageToLightbox(var msg);
} }

View file

@ -280,6 +280,34 @@ Item {
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;
} }
Rectangle {
id: removeHmdContainer;
z: 998;
visible: false;
color: hifi.colors.blueHighlight;
anchors.fill: backupInstructionsButton;
radius: 5;
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
}
RalewayBold {
anchors.fill: parent;
text: "INSTRUCTIONS OPEN ON DESKTOP";
size: 15;
color: hifi.colors.white;
verticalAlignment: Text.AlignVCenter;
horizontalAlignment: Text.AlignHCenter;
}
Timer {
id: removeHmdContainerTimer;
interval: 5000;
onTriggered: removeHmdContainer.visible = false
}
}
HifiControlsUit.Button { HifiControlsUit.Button {
id: backupInstructionsButton; id: backupInstructionsButton;
text: "View Backup Instructions"; text: "View Backup Instructions";
@ -293,6 +321,9 @@ Item {
onClicked: { onClicked: {
Qt.openUrlExternally("https://www.highfidelity.com/"); Qt.openUrlExternally("https://www.highfidelity.com/");
Qt.openUrlExternally("file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/')));
removeHmdContainer.visible = true;
removeHmdContainerTimer.start();
} }
} }
} }

View file

@ -65,6 +65,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter; anchors.verticalCenter: parent.verticalCenter;
fillMode: Image.PreserveAspectFit; fillMode: Image.PreserveAspectFit;
mipmap: true; mipmap: true;
cache: false;
} }
} }
MouseArea { MouseArea {

View file

@ -38,48 +38,41 @@ Rectangle {
Hifi.QmlCommerce { Hifi.QmlCommerce {
id: commerce; id: commerce;
onWalletStatusResult: {
if (walletStatus === 0) {
if (root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn";
}
} else if (walletStatus === 1) {
if (root.activeView !== "walletSetup") {
root.activeView = "walletSetup";
}
} else if (walletStatus === 2) {
if (root.activeView !== "passphraseModal") {
root.activeView = "passphraseModal";
}
} else if (walletStatus === 3) {
root.activeView = "walletHome";
commerce.getSecurityImage();
} else {
console.log("ERROR in Wallet.qml: Unknown wallet status: " + walletStatus);
}
}
onLoginStatusResult: { onLoginStatusResult: {
if (!isLoggedIn && root.activeView !== "needsLogIn") { if (!isLoggedIn && root.activeView !== "needsLogIn") {
root.activeView = "needsLogIn"; root.activeView = "needsLogIn";
} else if (isLoggedIn) { } else if (isLoggedIn) {
root.activeView = "initialize"; commerce.getWalletStatus();
commerce.account();
}
}
onAccountResult: {
if (result.status === "success") {
commerce.getKeyFilePathIfExists();
} else {
// unsure how to handle a failure here. We definitely cannot proceed.
}
}
onKeyFilePathIfExistsResult: {
if (path === "" && root.activeView !== "walletSetup") {
root.activeView = "walletSetup";
} else if (path !== "" && root.activeView === "initialize") {
commerce.getSecurityImage();
} }
} }
onSecurityImageResult: { onSecurityImageResult: {
if (!exists && root.activeView !== "walletSetup") { // "If security image is not set up" if (exists) {
root.activeView = "walletSetup";
} else if (exists && root.activeView === "initialize") {
commerce.getWalletAuthenticatedStatus();
titleBarSecurityImage.source = ""; titleBarSecurityImage.source = "";
titleBarSecurityImage.source = "image://security/securityImage"; titleBarSecurityImage.source = "image://security/securityImage";
} }
} }
onWalletAuthenticatedStatusResult: {
if (!isAuthenticated && passphraseModal && root.activeView !== "passphraseModal") {
root.activeView = "passphraseModal";
} else if (isAuthenticated) {
root.activeView = "walletHome";
}
}
} }
SecurityImageModel { SecurityImageModel {
@ -149,6 +142,7 @@ Rectangle {
anchors.bottomMargin: 6; anchors.bottomMargin: 6;
width: height; width: height;
mipmap: true; mipmap: true;
cache: false;
MouseArea { MouseArea {
enabled: titleBarSecurityImage.visible; enabled: titleBarSecurityImage.visible;
@ -179,7 +173,7 @@ Rectangle {
if (msg.method === 'walletSetup_finished') { if (msg.method === 'walletSetup_finished') {
if (msg.referrer === '') { if (msg.referrer === '') {
root.activeView = "initialize"; root.activeView = "initialize";
commerce.getLoginStatus(); commerce.getWalletStatus();
} else if (msg.referrer === 'purchases') { } else if (msg.referrer === 'purchases') {
sendToScript({method: 'goToPurchases'}); sendToScript({method: 'goToPurchases'});
} }
@ -254,7 +248,7 @@ Rectangle {
color: hifi.colors.baseGray; color: hifi.colors.baseGray;
Component.onCompleted: { Component.onCompleted: {
commerce.getLoginStatus(); commerce.getWalletStatus();
} }
} }

View file

@ -26,6 +26,7 @@ Item {
id: root; id: root;
property bool historyReceived: false; property bool historyReceived: false;
property int pendingCount: 0;
Hifi.QmlCommerce { Hifi.QmlCommerce {
id: commerce; id: commerce;
@ -39,6 +40,8 @@ Item {
if (result.status === 'success') { if (result.status === 'success') {
transactionHistoryModel.clear(); transactionHistoryModel.clear();
transactionHistoryModel.append(result.data.history); transactionHistoryModel.append(result.data.history);
calculatePendingAndInvalidated();
} }
} }
} }
@ -200,55 +203,74 @@ Item {
model: transactionHistoryModel; model: transactionHistoryModel;
delegate: Item { delegate: Item {
width: parent.width; width: parent.width;
height: transactionText.height + 30; height: (model.transaction_type === "pendingCount" && root.pendingCount !== 0) ? 40 : ((model.status === "confirmed" || model.status === "invalidated") ? transactionText.height + 30 : 0);
HifiControlsUit.Separator { Item {
visible: index === 0; visible: model.transaction_type === "pendingCount" && root.pendingCount !== 0;
colorScheme: 1; anchors.top: parent.top;
anchors.left: parent.left;
anchors.right: parent.right;
anchors.top: parent.top;
}
AnonymousProRegular {
id: dateText;
text: getFormattedDate(model.created_at * 1000);
// Style
size: 18;
anchors.left: parent.left; anchors.left: parent.left;
anchors.top: parent.top; width: parent.width;
anchors.topMargin: 15; height: visible ? parent.height : 0;
width: 118;
height: paintedHeight;
color: hifi.colors.blueAccent;
wrapMode: Text.WordWrap;
// Alignment
horizontalAlignment: Text.AlignRight;
}
AnonymousProRegular { AnonymousProRegular {
id: transactionText; id: pendingCountText;
text: model.text; anchors.fill: parent;
size: 18; text: root.pendingCount + ' Transaction' + (root.pendingCount > 1 ? 's' : '') + ' Pending';
anchors.top: parent.top; size: 18;
anchors.topMargin: 15; color: hifi.colors.blueAccent;
anchors.left: dateText.right; verticalAlignment: Text.AlignVCenter;
anchors.leftMargin: 20; horizontalAlignment: Text.AlignHCenter;
anchors.right: parent.right;
height: paintedHeight;
color: hifi.colors.baseGrayHighlight;
wrapMode: Text.WordWrap;
onLinkActivated: {
sendSignalToWallet({method: 'transactionHistory_linkClicked', marketplaceLink: link});
} }
} }
HifiControlsUit.Separator { Item {
colorScheme: 1; visible: model.transaction_type !== "pendingCount" && (model.status === "confirmed" || model.status === "invalidated");
anchors.top: parent.top;
anchors.left: parent.left; anchors.left: parent.left;
anchors.right: parent.right; width: parent.width;
anchors.bottom: parent.bottom; height: visible ? parent.height : 0;
AnonymousProRegular {
id: dateText;
text: model.created_at ? getFormattedDate(model.created_at * 1000) : "";
// Style
size: 18;
anchors.left: parent.left;
anchors.top: parent.top;
anchors.topMargin: 15;
width: 118;
height: paintedHeight;
color: hifi.colors.blueAccent;
wrapMode: Text.WordWrap;
// Alignment
horizontalAlignment: Text.AlignRight;
}
AnonymousProRegular {
id: transactionText;
text: model.text ? (model.status === "invalidated" ? ("INVALIDATED: " + model.text) : model.text) : "";
size: 18;
anchors.top: parent.top;
anchors.topMargin: 15;
anchors.left: dateText.right;
anchors.leftMargin: 20;
anchors.right: parent.right;
height: paintedHeight;
color: model.status === "invalidated" ? hifi.colors.redAccent : hifi.colors.baseGrayHighlight;
wrapMode: Text.WordWrap;
font.strikeout: model.status === "invalidated";
onLinkActivated: {
sendSignalToWallet({method: 'transactionHistory_linkClicked', marketplaceLink: link});
}
}
HifiControlsUit.Separator {
colorScheme: 1;
anchors.left: parent.left;
anchors.right: parent.right;
anchors.bottom: parent.bottom;
}
} }
} }
onAtYEndChanged: { onAtYEndChanged: {
@ -299,6 +321,19 @@ Item {
return year + '-' + month + '-' + day + '<br>' + drawnHour + ':' + min + amOrPm; return year + '-' + month + '-' + day + '<br>' + drawnHour + ':' + min + amOrPm;
} }
function calculatePendingAndInvalidated(startingPendingCount) {
var pendingCount = startingPendingCount ? startingPendingCount : 0;
for (var i = 0; i < transactionHistoryModel.count; i++) {
if (transactionHistoryModel.get(i).status === "pending") {
pendingCount++;
}
}
root.pendingCount = pendingCount;
transactionHistoryModel.insert(0, {"transaction_type": "pendingCount"});
}
// //
// Function Name: fromScript() // Function Name: fromScript()
// //

View file

@ -43,7 +43,7 @@ Item {
if (!exists && root.lastPage === "step_2") { if (!exists && root.lastPage === "step_2") {
// ERROR! Invalid security image. // ERROR! Invalid security image.
root.activeView = "step_2"; root.activeView = "step_2";
} else { } else if (exists) {
titleBarSecurityImage.source = ""; titleBarSecurityImage.source = "";
titleBarSecurityImage.source = "image://security/securityImage"; titleBarSecurityImage.source = "image://security/securityImage";
} }
@ -116,7 +116,7 @@ Item {
Image { Image {
id: titleBarSecurityImage; id: titleBarSecurityImage;
source: ""; source: "";
visible: !securityImageTip.visible && titleBarSecurityImage.source !== ""; visible: !securityImageTip.visible && titleBarSecurityImage.source !== "" && root.activeView !== "step_1" && root.activeView !== "step_2";
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 6; anchors.rightMargin: 6;
anchors.top: parent.top; anchors.top: parent.top;
@ -125,6 +125,7 @@ Item {
anchors.bottomMargin: 6; anchors.bottomMargin: 6;
width: height; width: height;
mipmap: true; mipmap: true;
cache: false;
MouseArea { MouseArea {
enabled: titleBarSecurityImage.visible; enabled: titleBarSecurityImage.visible;
@ -422,6 +423,7 @@ Item {
onClicked: { onClicked: {
root.hasShownSecurityImageTip = true; root.hasShownSecurityImageTip = true;
securityImageTip.visible = false; securityImageTip.visible = false;
passphraseSelection.focusFirstTextField();
} }
} }
} }
@ -466,6 +468,7 @@ Item {
PassphraseSelection { PassphraseSelection {
id: passphraseSelection; id: passphraseSelection;
shouldImmediatelyFocus: root.hasShownSecurityImageTip;
isShowingTip: securityImageTip.visible; isShowingTip: securityImageTip.visible;
anchors.top: passphraseTitleHelper.bottom; anchors.top: passphraseTitleHelper.bottom;
anchors.topMargin: 30; anchors.topMargin: 30;
@ -680,6 +683,7 @@ Item {
instructions02Container.visible = true; instructions02Container.visible = true;
keysReadyPageFinishButton.visible = true; keysReadyPageFinishButton.visible = true;
Qt.openUrlExternally("https://www.highfidelity.com/"); Qt.openUrlExternally("https://www.highfidelity.com/");
Qt.openUrlExternally("file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/')));
} }
} }
} }

View file

@ -167,6 +167,7 @@
#include "scripting/ControllerScriptingInterface.h" #include "scripting/ControllerScriptingInterface.h"
#include "scripting/RatesScriptingInterface.h" #include "scripting/RatesScriptingInterface.h"
#include "scripting/SelectionScriptingInterface.h" #include "scripting/SelectionScriptingInterface.h"
#include "scripting/WalletScriptingInterface.h"
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
#include "SpeechRecognizer.h" #include "SpeechRecognizer.h"
#endif #endif
@ -687,6 +688,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<ContextOverlayInterface>(); DependencyManager::set<ContextOverlayInterface>();
DependencyManager::set<Ledger>(); DependencyManager::set<Ledger>();
DependencyManager::set<Wallet>(); DependencyManager::set<Wallet>();
DependencyManager::set<WalletScriptingInterface>();
DependencyManager::set<FadeEffect>(); DependencyManager::set<FadeEffect>();
@ -2331,6 +2333,7 @@ void Application::initializeUi() {
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data()); surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get())); surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get()));
@ -6058,6 +6061,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance()); scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance());
scriptEngine->registerGlobalObject("Selection", DependencyManager::get<SelectionScriptingInterface>().data()); scriptEngine->registerGlobalObject("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
scriptEngine->registerGlobalObject("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue);

View file

@ -164,11 +164,7 @@ void Ledger::historySuccess(QNetworkReply& reply) {
// turns out on my machine, toLocalTime convert to some weird timezone, yet the // turns out on my machine, toLocalTime convert to some weird timezone, yet the
// systemTimeZone is correct. To avoid a strange bug with other's systems too, lets // systemTimeZone is correct. To avoid a strange bug with other's systems too, lets
// be explicit // be explicit
#ifdef Q_OS_MAC
QDateTime createdAt = QDateTime::fromTime_t(valueObject["created_at"].toInt(), Qt::UTC);
#else
QDateTime createdAt = QDateTime::fromSecsSinceEpoch(valueObject["created_at"].toInt(), Qt::UTC); QDateTime createdAt = QDateTime::fromSecsSinceEpoch(valueObject["created_at"].toInt(), Qt::UTC);
#endif
QDateTime localCreatedAt = createdAt.toTimeZone(QTimeZone::systemTimeZone()); QDateTime localCreatedAt = createdAt.toTimeZone(QTimeZone::systemTimeZone());
valueObject["text"] = QString("%1 sent %2 %3 with message \"%4\""). valueObject["text"] = QString("%1 sent %2 %3 with message \"%4\"").
arg(from, to, coloredQuantityAndAssetTitle, valueObject["message"].toString()); arg(from, to, coloredQuantityAndAssetTitle, valueObject["message"].toString());

View file

@ -15,6 +15,7 @@
#include "Ledger.h" #include "Ledger.h"
#include "Wallet.h" #include "Wallet.h"
#include <AccountManager.h> #include <AccountManager.h>
#include "scripting/WalletScriptingInterface.h"
HIFI_QML_DEF(QmlCommerce) HIFI_QML_DEF(QmlCommerce)
@ -28,6 +29,37 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
connect(ledger.data(), &Ledger::historyResult, this, &QmlCommerce::historyResult); connect(ledger.data(), &Ledger::historyResult, this, &QmlCommerce::historyResult);
connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult); connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult);
connect(ledger.data(), &Ledger::accountResult, this, &QmlCommerce::accountResult); connect(ledger.data(), &Ledger::accountResult, this, &QmlCommerce::accountResult);
connect(ledger.data(), &Ledger::accountResult, this, [&]() {
auto wallet = DependencyManager::get<Wallet>();
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
uint status;
if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) {
status = (uint)WalletStatus::WALLET_STATUS_NOT_SET_UP;
} else if (!wallet->walletIsAuthenticatedWithPassphrase()) {
status = (uint)WalletStatus::WALLET_STATUS_NOT_AUTHENTICATED;
} else {
status = (uint)WalletStatus::WALLET_STATUS_READY;
}
walletScriptingInterface->setWalletStatus(status);
emit walletStatusResult(status);
});
}
void QmlCommerce::getWalletStatus() {
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
uint status;
if (DependencyManager::get<AccountManager>()->isLoggedIn()) {
// This will set account info for the wallet, allowing us to decrypt and display the security image.
account();
} else {
status = (uint)WalletStatus::WALLET_STATUS_NOT_LOGGED_IN;
emit walletStatusResult(status);
walletScriptingInterface->setWalletStatus(status);
return;
}
} }
void QmlCommerce::getLoginStatus() { void QmlCommerce::getLoginStatus() {
@ -36,7 +68,7 @@ void QmlCommerce::getLoginStatus() {
void QmlCommerce::getKeyFilePathIfExists() { void QmlCommerce::getKeyFilePathIfExists() {
auto wallet = DependencyManager::get<Wallet>(); auto wallet = DependencyManager::get<Wallet>();
wallet->sendKeyFilePathIfExists(); emit keyFilePathIfExistsResult(wallet->getKeyFilePath());
} }
void QmlCommerce::getWalletAuthenticatedStatus() { void QmlCommerce::getWalletAuthenticatedStatus() {
@ -85,13 +117,18 @@ void QmlCommerce::history() {
ledger->history(wallet->listPublicKeys()); ledger->history(wallet->listPublicKeys());
} }
void QmlCommerce::changePassphrase(const QString& oldPassphrase, const QString& newPassphrase) {
auto wallet = DependencyManager::get<Wallet>();
if ((wallet->getPassphrase()->isEmpty() || wallet->getPassphrase() == oldPassphrase) && !newPassphrase.isEmpty()) {
emit changePassphraseStatusResult(wallet->changePassphrase(newPassphrase));
} else {
emit changePassphraseStatusResult(false);
}
}
void QmlCommerce::setPassphrase(const QString& passphrase) { void QmlCommerce::setPassphrase(const QString& passphrase) {
auto wallet = DependencyManager::get<Wallet>(); auto wallet = DependencyManager::get<Wallet>();
if(wallet->getPassphrase() && !wallet->getPassphrase()->isEmpty() && !passphrase.isEmpty()) { wallet->setPassphrase(passphrase);
wallet->changePassphrase(passphrase);
} else {
wallet->setPassphrase(passphrase);
}
getWalletAuthenticatedStatus(); getWalletAuthenticatedStatus();
} }

View file

@ -27,11 +27,21 @@ class QmlCommerce : public OffscreenQmlDialog {
public: public:
QmlCommerce(QQuickItem* parent = nullptr); QmlCommerce(QQuickItem* parent = nullptr);
enum WalletStatus {
WALLET_STATUS_NOT_LOGGED_IN = 0,
WALLET_STATUS_NOT_SET_UP,
WALLET_STATUS_NOT_AUTHENTICATED,
WALLET_STATUS_READY
};
signals: signals:
void walletStatusResult(uint walletStatus);
void loginStatusResult(bool isLoggedIn); void loginStatusResult(bool isLoggedIn);
void keyFilePathIfExistsResult(const QString& path); void keyFilePathIfExistsResult(const QString& path);
void securityImageResult(bool exists); void securityImageResult(bool exists);
void walletAuthenticatedStatusResult(bool isAuthenticated); void walletAuthenticatedStatusResult(bool isAuthenticated);
void changePassphraseStatusResult(bool changeSuccess);
void buyResult(QJsonObject result); void buyResult(QJsonObject result);
// Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and // Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and
@ -42,6 +52,8 @@ signals:
void accountResult(QJsonObject result); void accountResult(QJsonObject result);
protected: protected:
Q_INVOKABLE void getWalletStatus();
Q_INVOKABLE void getLoginStatus(); Q_INVOKABLE void getLoginStatus();
Q_INVOKABLE void getKeyFilePathIfExists(); Q_INVOKABLE void getKeyFilePathIfExists();
Q_INVOKABLE void getSecurityImage(); Q_INVOKABLE void getSecurityImage();
@ -49,6 +61,7 @@ protected:
Q_INVOKABLE void chooseSecurityImage(const QString& imageFile); Q_INVOKABLE void chooseSecurityImage(const QString& imageFile);
Q_INVOKABLE void setPassphrase(const QString& passphrase); Q_INVOKABLE void setPassphrase(const QString& passphrase);
Q_INVOKABLE void changePassphrase(const QString& oldPassphrase, const QString& newPassphrase);
Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false); Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false);
Q_INVOKABLE void balance(); Q_INVOKABLE void balance();

View file

@ -284,7 +284,7 @@ Wallet::Wallet() {
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
auto& packetReceiver = nodeList->getPacketReceiver(); auto& packetReceiver = nodeList->getPacketReceiver();
packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "verifyOwnerChallenge"); packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnershipPacket");
} }
Wallet::~Wallet() { Wallet::~Wallet() {
@ -468,7 +468,7 @@ bool Wallet::generateKeyPair() {
// TODO: redo this soon -- need error checking and so on // TODO: redo this soon -- need error checking and so on
writeSecurityImage(_securityImage, keyFilePath()); writeSecurityImage(_securityImage, keyFilePath());
sendKeyFilePathIfExists(); emit keyFilePathIfExistsResult(getKeyFilePath());
QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last(); QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last();
QString key = keyPair.first->toBase64(); QString key = keyPair.first->toBase64();
_publicKeys.push_back(key); _publicKeys.push_back(key);
@ -559,14 +559,14 @@ void Wallet::chooseSecurityImage(const QString& filename) {
emit securityImageResult(success); emit securityImageResult(success);
} }
void Wallet::getSecurityImage() { bool Wallet::getSecurityImage() {
unsigned char* data; unsigned char* data;
int dataLen; int dataLen;
// if already decrypted, don't do it again // if already decrypted, don't do it again
if (_securityImage) { if (_securityImage) {
emit securityImageResult(true); emit securityImageResult(true);
return; return true;
} }
bool success = false; bool success = false;
@ -585,14 +585,15 @@ void Wallet::getSecurityImage() {
success = true; success = true;
} }
emit securityImageResult(success); emit securityImageResult(success);
return success;
} }
void Wallet::sendKeyFilePathIfExists() { QString Wallet::getKeyFilePath() {
QString filePath(keyFilePath()); QString filePath(keyFilePath());
QFileInfo fileInfo(filePath); QFileInfo fileInfo(filePath);
if (fileInfo.exists()) { if (fileInfo.exists()) {
emit keyFilePathIfExistsResult(filePath); return filePath;
} else { } else {
emit keyFilePathIfExistsResult(""); return "";
} }
} }

View file

@ -32,8 +32,8 @@ public:
QStringList listPublicKeys(); QStringList listPublicKeys();
QString signWithKey(const QByteArray& text, const QString& key); QString signWithKey(const QByteArray& text, const QString& key);
void chooseSecurityImage(const QString& imageFile); void chooseSecurityImage(const QString& imageFile);
void getSecurityImage(); bool getSecurityImage();
void sendKeyFilePathIfExists(); QString getKeyFilePath();
void setSalt(const QByteArray& salt) { _salt = salt; } void setSalt(const QByteArray& salt) { _salt = salt; }
QByteArray getSalt() { return _salt; } QByteArray getSalt() { return _salt; }

View file

@ -0,0 +1,47 @@
//
// WalletScriptingInterface.cpp
// interface/src/scripting
//
// Created by Zach Fox on 2017-09-29.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "WalletScriptingInterface.h"
CheckoutProxy::CheckoutProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(qmlObject, parent) {
Q_ASSERT(QThread::currentThread() == qApp->thread());
}
WalletScriptingInterface::WalletScriptingInterface() {
}
static const QString CHECKOUT_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/checkout/Checkout.qml";
void WalletScriptingInterface::buy(const QString& name, const QString& id, const int& price, const QString& href) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "buy", Q_ARG(const QString&, name), Q_ARG(const QString&, id), Q_ARG(const int&, price), Q_ARG(const QString&, href));
return;
}
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
tablet->loadQMLSource(CHECKOUT_QML_PATH);
DependencyManager::get<HMDScriptingInterface>()->openTablet();
QQuickItem* root = nullptr;
if (tablet->getToolbarMode() || (!tablet->getTabletRoot() && !qApp->isHMDMode())) {
root = DependencyManager::get<OffscreenUi>()->getRootItem();
} else {
root = tablet->getTabletRoot();
}
CheckoutProxy* checkout = new CheckoutProxy(root->findChild<QObject*>("checkout"));
// Example: Wallet.buy("Test Flaregun", "0d90d21c-ce7a-4990-ad18-e9d2cf991027", 17, "http://mpassets.highfidelity.com/0d90d21c-ce7a-4990-ad18-e9d2cf991027-v1/flaregun.json");
checkout->writeProperty("itemName", name);
checkout->writeProperty("itemId", id);
checkout->writeProperty("itemPrice", price);
checkout->writeProperty("itemHref", href);
}

View file

@ -0,0 +1,51 @@
// WalletScriptingInterface.h
// interface/src/scripting
//
// Created by Zach Fox on 2017-09-29.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_WalletScriptingInterface_h
#define hifi_WalletScriptingInterface_h
#include <QtCore/QObject>
#include <DependencyManager.h>
#include "scripting/HMDScriptingInterface.h"
#include <ui/TabletScriptingInterface.h>
#include <ui/QmlWrapper.h>
#include <OffscreenUi.h>
#include "Application.h"
class CheckoutProxy : public QmlWrapper {
Q_OBJECT
public:
CheckoutProxy(QObject* qmlObject, QObject* parent = nullptr);
};
class WalletScriptingInterface : public QObject, public Dependency {
Q_OBJECT
Q_PROPERTY(uint walletStatus READ getWalletStatus WRITE setWalletStatus NOTIFY walletStatusChanged)
public:
WalletScriptingInterface();
Q_INVOKABLE uint getWalletStatus() { return _walletStatus; }
void setWalletStatus(const uint& status) { _walletStatus = status; }
Q_INVOKABLE void buy(const QString& name, const QString& id, const int& price, const QString& href);
signals:
void walletStatusChanged();
private:
uint _walletStatus;
};
#endif // hifi_WalletScriptingInterface_h

View file

@ -201,7 +201,8 @@ bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityIt
void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) { void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
if (overlayID == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) { if (overlayID == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) {
qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "Overlay ID:" << overlayID; qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "Overlay ID:" << overlayID;
if (_commerceSettingSwitch.get()) { Setting::Handle<bool> _settingSwitch{ "commerce", false };
if (_settingSwitch.get()) {
openInspectionCertificate(); openInspectionCertificate();
} else { } else {
openMarketplace(); openMarketplace();

View file

@ -79,8 +79,6 @@ private:
bool _isInMarketplaceInspectionMode { false }; bool _isInMarketplaceInspectionMode { false };
Setting::Handle<bool> _commerceSettingSwitch{ "commerce", false };
void openInspectionCertificate(); void openInspectionCertificate();
void openMarketplace(); void openMarketplace();
void enableEntityHighlight(const EntityItemID& entityItemID); void enableEntityHighlight(const EntityItemID& entityItemID);

View file

@ -61,7 +61,7 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info)
// During the period in which we have HFC commerce in the system, but not applied everywhere: // During the period in which we have HFC commerce in the system, but not applied everywhere:
const QString tokenStringCommerce{ "Chrome/48.0 (HighFidelityInterface WithHFC)" }; const QString tokenStringCommerce{ "Chrome/48.0 (HighFidelityInterface WithHFC)" };
static Setting::Handle<bool> _settingSwitch{ "commerce", false }; Setting::Handle<bool> _settingSwitch{ "commerce", false };
bool isMoney = _settingSwitch.get(); bool isMoney = _settingSwitch.get();
const QString tokenString = !isAuthable ? tokenStringMobile : (isMoney ? tokenStringCommerce : tokenStringMetaverse); const QString tokenString = !isAuthable ? tokenStringMobile : (isMoney ? tokenStringCommerce : tokenStringMetaverse);

View file

@ -78,6 +78,7 @@
onButtonClicked(); onButtonClicked();
break; break;
case 'walletReset': case 'walletReset':
Settings.setValue("isFirstUseOfPurchases", true);
onButtonClicked(); onButtonClicked();
onButtonClicked(); onButtonClicked();
break; break;

View file

@ -28,6 +28,7 @@
var confirmAllPurchases = false; // Set this to "true" to cause Checkout.qml to popup for all items, even if free var confirmAllPurchases = false; // Set this to "true" to cause Checkout.qml to popup for all items, even if free
var userIsLoggedIn = false; var userIsLoggedIn = false;
var walletNeedsSetup = false;
function injectCommonCode(isDirectoryPage) { function injectCommonCode(isDirectoryPage) {
@ -91,6 +92,48 @@
}); });
} }
emitWalletSetupEvent = function() {
EventBridge.emitWebEvent(JSON.stringify({
type: "WALLET_SETUP"
}));
}
function maybeAddSetupWalletButton() {
if (userIsLoggedIn && walletNeedsSetup) {
var resultsElement = document.getElementById('results');
var setupWalletElement = document.createElement('div');
setupWalletElement.classList.add("row");
setupWalletElement.id = "setupWalletDiv";
setupWalletElement.style = "height:60px;margin:20px 10px 10px 10px;padding:12px 5px;" +
"background-color:#D6F4D8;border-color:#aee9b2;border-width:2px;border-style:solid;border-radius:5px;";
var span = document.createElement('span');
span.style = "margin:10px 5px;color:#1b6420;font-size:15px;";
span.innerHTML = "<a href='#' onclick='emitWalletSetupEvent(); return false;'>Setup your Wallet</a> to get money and shop in Marketplace.";
var xButton = document.createElement('a');
xButton.id = "xButton";
xButton.setAttribute('href', "#");
xButton.style = "width:50px;height:100%;margin:0;color:#ccc;font-size:20px;";
xButton.innerHTML = "X";
xButton.onclick = function () {
setupWalletElement.remove();
dummyRow.remove();
};
setupWalletElement.appendChild(span);
setupWalletElement.appendChild(xButton);
resultsElement.insertBefore(setupWalletElement, resultsElement.firstChild);
// Dummy row for padding
var dummyRow = document.createElement('div');
dummyRow.classList.add("row");
dummyRow.style = "height:15px;";
resultsElement.insertBefore(dummyRow, resultsElement.firstChild);
}
}
function maybeAddLogInButton() { function maybeAddLogInButton() {
if (!userIsLoggedIn) { if (!userIsLoggedIn) {
var resultsElement = document.getElementById('results'); var resultsElement = document.getElementById('results');
@ -149,7 +192,7 @@
var dropDownElement = document.getElementById('user-dropdown'); var dropDownElement = document.getElementById('user-dropdown');
purchasesElement.id = "purchasesButton"; purchasesElement.id = "purchasesButton";
purchasesElement.setAttribute('href', "#"); purchasesElement.setAttribute('href', "#");
purchasesElement.innerHTML = "MY PURCHASES"; purchasesElement.innerHTML = "My Purchases";
// FRONTEND WEBDEV RANT: The username dropdown should REALLY not be programmed to be on the same // FRONTEND WEBDEV RANT: The username dropdown should REALLY not be programmed to be on the same
// line as the search bar, overlaid on top of the search bar, floated right, and then relatively bumped up using "top:-50px". // line as the search bar, overlaid on top of the search bar, floated right, and then relatively bumped up using "top:-50px".
purchasesElement.style = "height:100%;margin-top:18px;font-weight:bold;float:right;margin-right:" + (dropDownElement.offsetWidth + 30) + purchasesElement.style = "height:100%;margin-top:18px;font-weight:bold;float:right;margin-right:" + (dropDownElement.offsetWidth + 30) +
@ -164,12 +207,34 @@
} }
} }
function changeDropdownMenu() {
var logInOrOutButton = document.createElement('a');
logInOrOutButton.id = "logInOrOutButton";
logInOrOutButton.setAttribute('href', "#");
logInOrOutButton.innerHTML = userIsLoggedIn ? "Log Out" : "Log In";
logInOrOutButton.onclick = function () {
EventBridge.emitWebEvent(JSON.stringify({
type: "LOGIN"
}));
};
$($('.dropdown-menu').find('li')[0]).append(logInOrOutButton);
$('a[href="/marketplace?view=mine"]').each(function () {
$(this).attr('href', '#');
$(this).on('click', function () {
EventBridge.emitWebEvent(JSON.stringify({
type: "MY_ITEMS"
}));
});
});
}
function buyButtonClicked(id, name, author, price, href) { function buyButtonClicked(id, name, author, price, href) {
EventBridge.emitWebEvent(JSON.stringify({ EventBridge.emitWebEvent(JSON.stringify({
type: "CHECKOUT", type: "CHECKOUT",
itemId: id, itemId: id,
itemName: name, itemName: name,
itemAuthor: author,
itemPrice: price ? parseInt(price, 10) : 0, itemPrice: price ? parseInt(price, 10) : 0,
itemHref: href itemHref: href
})); }));
@ -235,9 +300,13 @@
} }
function injectHiFiCode() { function injectHiFiCode() {
if (confirmAllPurchases) { if (!$('body').hasClass("code-injected") && confirmAllPurchases) {
$('body').addClass("code-injected");
maybeAddLogInButton(); maybeAddLogInButton();
maybeAddSetupWalletButton();
changeDropdownMenu();
var target = document.getElementById('templated-items'); var target = document.getElementById('templated-items');
// MutationObserver is necessary because the DOM is populated after the page is loaded. // MutationObserver is necessary because the DOM is populated after the page is loaded.
@ -260,9 +329,13 @@
} }
function injectHiFiItemPageCode() { function injectHiFiItemPageCode() {
if (confirmAllPurchases) { if (!$('body').hasClass("code-injected") && confirmAllPurchases) {
$('body').addClass("code-injected");
maybeAddLogInButton(); maybeAddLogInButton();
maybeAddSetupWalletButton();
changeDropdownMenu();
var purchaseButton = $('#side-info').find('.btn').first(); var purchaseButton = $('#side-info').find('.btn').first();
@ -551,7 +624,8 @@
if (parsedJsonMessage.type === "marketplaces") { if (parsedJsonMessage.type === "marketplaces") {
if (parsedJsonMessage.action === "commerceSetting") { if (parsedJsonMessage.action === "commerceSetting") {
confirmAllPurchases = !!parsedJsonMessage.data.commerceMode; confirmAllPurchases = !!parsedJsonMessage.data.commerceMode;
userIsLoggedIn = !!parsedJsonMessage.data.userIsLoggedIn userIsLoggedIn = !!parsedJsonMessage.data.userIsLoggedIn;
walletNeedsSetup = !!parsedJsonMessage.data.walletNeedsSetup;
injectCode(); injectCode();
} }
} }
@ -567,4 +641,5 @@
// Load / unload. // Load / unload.
window.addEventListener("load", onLoad); // More robust to Web site issues than using $(document).ready(). window.addEventListener("load", onLoad); // More robust to Web site issues than using $(document).ready().
window.addEventListener("page:change", onLoad); // Triggered after Marketplace HTML is changed
}()); }());

View file

@ -19,7 +19,8 @@
var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page. var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page.
var MARKETPLACES_URL = Script.resolvePath("../html/marketplaces.html"); var MARKETPLACES_URL = Script.resolvePath("../html/marketplaces.html");
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js"); var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
var MARKETPLACE_CHECKOUT_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/checkout/Checkout.qml"; var MARKETPLACE_CHECKOUT_QML_PATH_BASE = "qml/hifi/commerce/checkout/Checkout.qml";
var MARKETPLACE_CHECKOUT_QML_PATH = Script.resourcesPath() + MARKETPLACE_CHECKOUT_QML_PATH_BASE;
var MARKETPLACE_PURCHASES_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/purchases/Purchases.qml"; var MARKETPLACE_PURCHASES_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/purchases/Purchases.qml";
var MARKETPLACE_WALLET_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/wallet/Wallet.qml"; var MARKETPLACE_WALLET_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/wallet/Wallet.qml";
var MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH = "commerce/inspectionCertificate/InspectionCertificate.qml"; var MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH = "commerce/inspectionCertificate/InspectionCertificate.qml";
@ -60,6 +61,7 @@
var onCommerceScreen = false; var onCommerceScreen = false;
var debugCheckout = false; var debugCheckout = false;
var debugError = false;
function showMarketplace() { function showMarketplace() {
if (!debugCheckout) { if (!debugCheckout) {
UserActivityLogger.openedMarketplace(); UserActivityLogger.openedMarketplace();
@ -70,8 +72,7 @@
method: 'updateCheckoutQML', params: { method: 'updateCheckoutQML', params: {
itemId: '0d90d21c-ce7a-4990-ad18-e9d2cf991027', itemId: '0d90d21c-ce7a-4990-ad18-e9d2cf991027',
itemName: 'Test Flaregun', itemName: 'Test Flaregun',
itemAuthor: 'hifiDave', itemPrice: (debugError ? 10 : 17),
itemPrice: 17,
itemHref: 'http://mpassets.highfidelity.com/0d90d21c-ce7a-4990-ad18-e9d2cf991027-v1/flaregun.json', itemHref: 'http://mpassets.highfidelity.com/0d90d21c-ce7a-4990-ad18-e9d2cf991027-v1/flaregun.json',
}, },
canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified
@ -106,8 +107,8 @@
var referrerURL; // Used for updating Purchases QML var referrerURL; // Used for updating Purchases QML
var filterText; // Used for updating Purchases QML var filterText; // Used for updating Purchases QML
function onScreenChanged(type, url) { function onScreenChanged(type, url) {
onMarketplaceScreen = type === "Web" && url === MARKETPLACE_URL_INITIAL; onMarketplaceScreen = type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1;
onCommerceScreen = type === "QML" && (url === MARKETPLACE_CHECKOUT_QML_PATH || url === MARKETPLACE_PURCHASES_QML_PATH || url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1); onCommerceScreen = type === "QML" && (url.indexOf(MARKETPLACE_CHECKOUT_QML_PATH_BASE) !== -1 || url === MARKETPLACE_PURCHASES_QML_PATH || url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1);
wireEventBridge(onCommerceScreen); wireEventBridge(onCommerceScreen);
if (url === MARKETPLACE_PURCHASES_QML_PATH) { if (url === MARKETPLACE_PURCHASES_QML_PATH) {
@ -128,12 +129,11 @@
} }
} }
function setCertificateInfo(currentEntityWithContextOverlay, itemMarketplaceId, closeGoesToPurchases) { function setCertificateInfo(currentEntityWithContextOverlay, itemMarketplaceId) {
wireEventBridge(true); wireEventBridge(true);
tablet.sendToQml({ tablet.sendToQml({
method: 'inspectionCertificate_setMarketplaceId', method: 'inspectionCertificate_setMarketplaceId',
marketplaceId: itemMarketplaceId || Entities.getEntityProperties(currentEntityWithContextOverlay, ['marketplaceID']).marketplaceID, marketplaceId: itemMarketplaceId || Entities.getEntityProperties(currentEntityWithContextOverlay, ['marketplaceID']).marketplaceID
closeGoesToPurchases: closeGoesToPurchases
}); });
// ZRF FIXME! Make a call to the endpoint to get item info instead of this silliness // ZRF FIXME! Make a call to the endpoint to get item info instead of this silliness
Script.setTimeout(function () { Script.setTimeout(function () {
@ -203,7 +203,8 @@
action: "commerceSetting", action: "commerceSetting",
data: { data: {
commerceMode: Settings.getValue("commerce", false), commerceMode: Settings.getValue("commerce", false),
userIsLoggedIn: Account.loggedIn userIsLoggedIn: Account.loggedIn,
walletNeedsSetup: Wallet.walletStatus === 1
} }
})); }));
} else if (parsedJsonMessage.type === "PURCHASES") { } else if (parsedJsonMessage.type === "PURCHASES") {
@ -212,6 +213,16 @@
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH); tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
} else if (parsedJsonMessage.type === "LOGIN") { } else if (parsedJsonMessage.type === "LOGIN") {
openLoginWindow(); openLoginWindow();
} else if (parsedJsonMessage.type === "WALLET_SETUP") {
tablet.pushOntoStack(MARKETPLACE_WALLET_QML_PATH);
} else if (parsedJsonMessage.type === "MY_ITEMS") {
referrerURL = MARKETPLACE_URL_INITIAL;
filterText = "";
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
wireEventBridge(true);
tablet.sendToQml({
method: 'purchases_showMyItems'
});
} }
} }
} }
@ -325,36 +336,26 @@
case 'maybeEnableHmdPreview': case 'maybeEnableHmdPreview':
Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled); Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled);
break; break;
case 'purchases_getIsFirstUse':
tablet.sendToQml({
method: 'purchases_getIsFirstUseResult',
isFirstUseOfPurchases: Settings.getValue("isFirstUseOfPurchases", true)
});
break;
case 'purchases_setIsFirstUse':
Settings.setValue("isFirstUseOfPurchases", false);
break;
case 'purchases_openGoTo': case 'purchases_openGoTo':
tablet.loadQMLSource("TabletAddressDialog.qml"); tablet.loadQMLSource("TabletAddressDialog.qml");
break; break;
case 'purchases_itemCertificateClicked': case 'purchases_itemCertificateClicked':
tablet.loadQMLSource("../commerce/inspectionCertificate/InspectionCertificate.qml"); setCertificateInfo("", message.itemMarketplaceId);
setCertificateInfo("", message.itemMarketplaceId, true);
break; break;
case 'inspectionCertificate_closeClicked': case 'inspectionCertificate_closeClicked':
if (message.closeGoesToPurchases) { tablet.gotoHomeScreen();
referrerURL = MARKETPLACE_URL_INITIAL;
filterText = "";
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
} else {
tablet.gotoHomeScreen();
}
break; break;
case 'inspectionCertificate_showInMarketplaceClicked': case 'inspectionCertificate_showInMarketplaceClicked':
tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + message.itemId, MARKETPLACES_INJECT_SCRIPT_URL); tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + message.itemId, MARKETPLACES_INJECT_SCRIPT_URL);
break; break;
case 'header_myItemsClicked': case 'header_myItemsClicked':
tablet.gotoWebScreen(MARKETPLACE_URL + '?view=mine', MARKETPLACES_INJECT_SCRIPT_URL); referrerURL = MARKETPLACE_URL_INITIAL;
filterText = "";
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
wireEventBridge(true);
tablet.sendToQml({
method: 'purchases_showMyItems'
});
break; break;
default: default:
print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message)); print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message));