Merge branch 'master' of https://github.com/highfidelity/hifi into commerce_extendedCerts_1

This commit is contained in:
Zach Fox 2018-02-09 15:59:38 -08:00
commit ffea8104fc
10 changed files with 464 additions and 269 deletions

View file

@ -19,21 +19,31 @@ import "../../../controls-uit" as HifiControlsUit
import "../../../controls" as HifiControls import "../../../controls" as HifiControls
import "../wallet" as HifiWallet import "../wallet" as HifiWallet
// references XXX from root context
Rectangle { Rectangle {
HifiConstants { id: hifi; } HifiConstants { id: hifi; }
id: root; id: root;
property string marketplaceUrl; property string marketplaceUrl: "";
property string certificateId; property string entityId: "";
property string certificateId: "";
property string itemName: "--"; property string itemName: "--";
property string itemOwner: "--"; property string itemOwner: "--";
property string itemEdition: "--"; property string itemEdition: "--";
property string dateOfPurchase: "--"; property string dateOfPurchase: "--";
property string itemCost: "--";
property string certTitleTextColor: hifi.colors.darkGray;
property string certTextColor: hifi.colors.white;
property string infoTextColor: hifi.colors.blueAccent;
// 0 means replace none
// 4 means replace all but "Item Edition"
// 5 means replace all 5 replaceable fields
property int certInfoReplaceMode: 5;
property bool isLightbox: false; property bool isLightbox: false;
property bool isMyCert: false; property bool isMyCert: false;
property bool isCertificateInvalid: false; property bool useGoldCert: true;
property bool certificateInfoPending: true;
property int certificateStatus: 0;
property bool certificateStatusPending: true;
// Style // Style
color: hifi.colors.faintGray; color: hifi.colors.faintGray;
Connections { Connections {
@ -45,72 +55,135 @@ Rectangle {
} else { } else {
root.marketplaceUrl = result.data.marketplace_item_url; root.marketplaceUrl = result.data.marketplace_item_url;
root.isMyCert = result.isMyCert ? result.isMyCert : false; root.isMyCert = result.isMyCert ? result.isMyCert : false;
root.itemOwner = root.isCertificateInvalid ? "--" : (root.isMyCert ? Account.username :
"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"); if (root.certInfoReplaceMode > 3) {
root.itemEdition = root.isCertificateInvalid ? "Uncertified Copy" : root.itemName = result.data.marketplace_item_name;
(result.data.edition_number + "/" + (result.data.limited_run === -1 ? "\u221e" : result.data.limited_run)); // "\u2022" is the Unicode character 'BULLET' - it's what's used in password fields on the web, etc
root.dateOfPurchase = root.isCertificateInvalid ? "" : getFormattedDate(result.data.transfer_created_at * 1000); root.itemOwner = root.isMyCert ? Account.username :
root.itemName = result.data.marketplace_item_name; "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
root.dateOfPurchase = root.isMyCert ? getFormattedDate(result.data.transfer_created_at * 1000) : "Undisclosed";
root.itemCost = (root.isMyCert && result.data.cost !== undefined) ? result.data.cost : "Undisclosed";
}
if (root.certInfoReplaceMode > 4) {
root.itemEdition = result.data.edition_number + "/" + (result.data.limited_run === -1 ? "\u221e" : result.data.limited_run);
}
if (root.certificateStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED
if (root.isMyCert) {
errorText.text = "This item is an uncertified copy of an item you purchased.";
} else {
errorText.text = "The person who placed this item doesn't own it.";
}
}
if (result.data.invalid_reason || result.data.transfer_status[0] === "failed") { if (result.data.invalid_reason || result.data.transfer_status[0] === "failed") {
titleBarText.text = "Invalid Certificate"; root.useGoldCert = false;
titleBarText.color = hifi.colors.redHighlight; root.certTitleTextColor = hifi.colors.redHighlight;
root.certTextColor = hifi.colors.redHighlight;
root.infoTextColor = hifi.colors.redHighlight;
titleBarText.text = "Certificate\nNo Longer Valid";
popText.text = ""; popText.text = "";
showInMarketplaceButton.visible = false;
// "Edition" text previously set above in this function
// "Owner" text previously set above in this function
// "Purchase Date" text previously set above in this function
// "Purchase Price" text previously set above in this function
if (result.data.invalid_reason) { if (result.data.invalid_reason) {
errorText.text = result.data.invalid_reason; errorText.text = result.data.invalid_reason;
} }
} else if (result.data.transfer_status[0] === "pending") { } else if (result.data.transfer_status[0] === "pending") {
root.useGoldCert = false;
root.certTitleTextColor = hifi.colors.redHighlight;
root.certTextColor = hifi.colors.redHighlight;
root.infoTextColor = hifi.colors.redHighlight;
titleBarText.text = "Certificate Pending"; titleBarText.text = "Certificate Pending";
popText.text = "";
showInMarketplaceButton.visible = true;
// "Edition" text previously set above in this function
// "Owner" text previously set above in this function
// "Purchase Date" text previously set above in this function
// "Purchase Price" text previously set above in this function
errorText.text = "The status of this item is still pending confirmation. If the purchase is not confirmed, " + errorText.text = "The status of this item is still pending confirmation. If the purchase is not confirmed, " +
"this entity will be cleaned up by the domain."; "this entity will be cleaned up by the domain.";
errorText.color = hifi.colors.baseGray;
} }
} }
root.certificateInfoPending = false;
} }
onUpdateCertificateStatus: { onUpdateCertificateStatus: {
if (certStatus === 1) { // CERTIFICATE_STATUS_VERIFICATION_SUCCESS updateCertificateStatus(certStatus);
// NOP
} else if (certStatus === 2) { // CERTIFICATE_STATUS_VERIFICATION_TIMEOUT
root.isCertificateInvalid = true;
errorText.text = "Verification of this certificate timed out.";
errorText.color = hifi.colors.redHighlight;
} else if (certStatus === 3) { // CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED
root.isCertificateInvalid = true;
titleBarText.text = "Invalid Certificate";
titleBarText.color = hifi.colors.redHighlight;
popText.text = "";
root.itemOwner = "";
dateOfPurchaseHeader.text = "";
root.dateOfPurchase = "";
root.itemEdition = "Uncertified Copy";
errorText.text = "The information associated with this item has been modified and it no longer matches the original certified item.";
errorText.color = hifi.colors.baseGray;
} else if (certStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED
root.isCertificateInvalid = true;
titleBarText.text = "Invalid Certificate";
titleBarText.color = hifi.colors.redHighlight;
popText.text = "";
root.itemOwner = "";
dateOfPurchaseHeader.text = "";
root.dateOfPurchase = "";
root.itemEdition = "Uncertified Copy";
errorText.text = "The avatar who rezzed this item doesn't own it.";
errorText.color = hifi.colors.baseGray;
} else {
console.log("Unknown certificate status received from ledger signal!");
}
} }
} }
onCertificateIdChanged: { function updateCertificateStatus(status) {
if (certificateId !== "") { root.certificateStatus = status;
Commerce.certificateInfo(certificateId); if (root.certificateStatus === 1) { // CERTIFICATE_STATUS_VERIFICATION_SUCCESS
root.useGoldCert = true;
root.certTitleTextColor = hifi.colors.darkGray;
root.certTextColor = hifi.colors.white;
root.infoTextColor = hifi.colors.blueAccent;
titleBarText.text = "Certificate";
popText.text = "PROOF OF PROVENANCE";
showInMarketplaceButton.visible = true;
root.certInfoReplaceMode = 5;
// "Item Name" text will be set in "onCertificateInfoResult()"
// "Edition" text will be set in "onCertificateInfoResult()"
// "Owner" text will be set in "onCertificateInfoResult()"
// "Purchase Date" text will be set in "onCertificateInfoResult()"
// "Purchase Price" text will be set in "onCertificateInfoResult()"
errorText.text = "";
} else if (root.certificateStatus === 2) { // CERTIFICATE_STATUS_VERIFICATION_TIMEOUT
root.useGoldCert = false;
root.certTitleTextColor = hifi.colors.redHighlight;
root.certTextColor = hifi.colors.redHighlight;
root.infoTextColor = hifi.colors.redHighlight;
titleBarText.text = "Request Timed Out";
popText.text = "";
showInMarketplaceButton.visible = false;
root.certInfoReplaceMode = 0;
root.itemName = "";
root.itemEdition = "";
root.itemOwner = "";
root.dateOfPurchase = "";
root.itemCost = "";
errorText.text = "Your request to inspect this item timed out. Please try again later.";
} else if (root.certificateStatus === 3) { // CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED
root.useGoldCert = false;
root.certTitleTextColor = hifi.colors.redHighlight;
root.certTextColor = hifi.colors.redHighlight;
root.infoTextColor = hifi.colors.redHighlight;
titleBarText.text = "Certificate\nNo Longer Valid";
popText.text = "";
showInMarketplaceButton.visible = true;
root.certInfoReplaceMode = 5;
// "Item Name" text will be set in "onCertificateInfoResult()"
// "Edition" text will be set in "onCertificateInfoResult()"
// "Owner" text will be set in "onCertificateInfoResult()"
// "Purchase Date" text will be set in "onCertificateInfoResult()"
// "Purchase Price" text will be set in "onCertificateInfoResult()"
errorText.text = "The information associated with this item has been modified and it no longer matches the original certified item.";
} else if (root.certificateStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED
root.useGoldCert = false;
root.certTitleTextColor = hifi.colors.redHighlight;
root.certTextColor = hifi.colors.redHighlight;
root.infoTextColor = hifi.colors.redHighlight;
titleBarText.text = "Invalid Certificate";
popText.text = "";
showInMarketplaceButton.visible = true;
root.certInfoReplaceMode = 4;
// "Item Name" text will be set in "onCertificateInfoResult()"
root.itemEdition = "Uncertified Copy"
// "Owner" text will be set in "onCertificateInfoResult()"
// "Purchase Date" text will be set in "onCertificateInfoResult()"
// "Purchase Price" text will be set in "onCertificateInfoResult()"
// "Error Text" text will be set in "onCertificateInfoResult()"
} else {
console.log("Unknown certificate status received from ledger signal!");
} }
root.certificateStatusPending = false;
// We've gotten cert status - we are GO on getting the cert info
Commerce.certificateInfo(root.certificateId);
} }
// This object is always used in a popup. // This object is always used in a popup.
@ -122,9 +195,35 @@ Rectangle {
hoverEnabled: true; hoverEnabled: true;
} }
Image { Rectangle {
id: loadingOverlay;
z: 998;
visible: root.certificateInfoPending || root.certificateStatusPending;
anchors.fill: parent; anchors.fill: parent;
source: "images/cert-bg.jpg"; color: Qt.rgba(0.0, 0.0, 0.0, 0.7);
// This object is always used in a popup or full-screen Wallet section.
// This MouseArea is used to prevent a user from being
// able to click on a button/mouseArea underneath the popup/section.
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
}
AnimatedImage {
source: "../common/images/loader.gif"
width: 96;
height: width;
anchors.verticalCenter: parent.verticalCenter;
anchors.horizontalCenter: parent.horizontalCenter;
}
}
Image {
id: backgroundImage;
anchors.fill: parent;
source: root.useGoldCert ? "images/cert-bg-gold-split.png" : "images/nocert-bg-split.png";
} }
// Title text // Title text
@ -137,16 +236,17 @@ Rectangle {
anchors.top: parent.top; anchors.top: parent.top;
anchors.topMargin: 40; anchors.topMargin: 40;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 45; anchors.leftMargin: 36;
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 8;
height: paintedHeight; height: paintedHeight;
// Style // Style
color: hifi.colors.darkGray; color: root.certTitleTextColor;
wrapMode: Text.WordWrap;
} }
// Title text // Title text
RalewayRegular { RalewayRegular {
id: popText; id: popText;
text: "Proof of Provenance";
// Text size // Text size
size: 16; size: 16;
// Anchors // Anchors
@ -154,9 +254,39 @@ Rectangle {
anchors.topMargin: 4; anchors.topMargin: 4;
anchors.left: titleBarText.left; anchors.left: titleBarText.left;
anchors.right: titleBarText.right; anchors.right: titleBarText.right;
height: paintedHeight; height: text === "" ? 0 : paintedHeight;
// Style // Style
color: hifi.colors.darkGray; color: root.certTitleTextColor;
}
// "Close" button
HiFiGlyphs {
z: 999;
id: closeGlyphButton;
text: hifi.glyphs.close;
color: hifi.colors.white;
size: 26;
anchors.top: parent.top;
anchors.topMargin: 10;
anchors.right: parent.right;
anchors.rightMargin: 10;
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
onEntered: {
parent.text = hifi.glyphs.closeInverted;
}
onExited: {
parent.text = hifi.glyphs.close;
}
onClicked: {
if (root.isLightbox) {
root.visible = false;
} else {
sendToScript({method: 'inspectionCertificate_closeClicked', closeGoesToPurchases: root.closeGoesToPurchases});
}
}
}
} }
// //
@ -164,11 +294,13 @@ Rectangle {
// //
Item { Item {
id: certificateContainer; id: certificateContainer;
anchors.top: popText.bottom; anchors.top: titleBarText.top;
anchors.topMargin: 30; anchors.topMargin: 110;
anchors.bottom: buttonsContainer.top; anchors.bottom: infoContainer.top;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: titleBarText.anchors.leftMargin;
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 24;
RalewayRegular { RalewayRegular {
id: itemNameHeader; id: itemNameHeader;
@ -178,9 +310,7 @@ Rectangle {
// Anchors // Anchors
anchors.top: parent.top; anchors.top: parent.top;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 45;
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 16;
height: paintedHeight; height: paintedHeight;
// Style // Style
color: hifi.colors.darkGray; color: hifi.colors.darkGray;
@ -197,79 +327,30 @@ Rectangle {
anchors.right: itemNameHeader.right; anchors.right: itemNameHeader.right;
height: paintedHeight; height: paintedHeight;
// Style // Style
color: hifi.colors.white; color: root.certTextColor;
elide: Text.ElideRight; elide: Text.ElideRight;
MouseArea { MouseArea {
enabled: showInMarketplaceButton.visible;
anchors.fill: parent; anchors.fill: parent;
hoverEnabled: enabled; hoverEnabled: enabled;
onClicked: { onClicked: {
sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', marketplaceUrl: root.marketplaceUrl}); sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', marketplaceUrl: root.marketplaceUrl});
} }
onEntered: itemName.color = hifi.colors.blueHighlight; onEntered: itemName.color = hifi.colors.blueHighlight;
onExited: itemName.color = hifi.colors.white; onExited: itemName.color = root.certTextColor;
} }
} }
RalewayRegular {
id: ownedByHeader;
text: "OWNER";
// Text size
size: 16;
// Anchors
anchors.top: itemName.bottom;
anchors.topMargin: 28;
anchors.left: parent.left;
anchors.leftMargin: 45;
anchors.right: parent.right;
anchors.rightMargin: 16;
height: paintedHeight;
// Style
color: hifi.colors.darkGray;
}
RalewayRegular {
id: ownedBy;
text: root.itemOwner;
// Text size
size: 22;
// Anchors
anchors.top: ownedByHeader.bottom;
anchors.topMargin: 8;
anchors.left: ownedByHeader.left;
height: paintedHeight;
// Style
color: hifi.colors.white;
elide: Text.ElideRight;
}
AnonymousProRegular {
id: isMyCertText;
visible: root.isMyCert && !root.isCertificateInvalid;
text: "(Private)";
size: 18;
// Anchors
anchors.top: ownedBy.top;
anchors.topMargin: 4;
anchors.bottom: ownedBy.bottom;
anchors.left: ownedBy.right;
anchors.leftMargin: 6;
anchors.right: ownedByHeader.right;
// Style
color: hifi.colors.white;
elide: Text.ElideRight;
verticalAlignment: Text.AlignVCenter;
}
RalewayRegular { RalewayRegular {
id: editionHeader; id: editionHeader;
text: "EDITION"; text: "EDITION";
// Text size // Text size
size: 16; size: 16;
// Anchors // Anchors
anchors.top: ownedBy.bottom; anchors.top: itemName.bottom;
anchors.topMargin: 28; anchors.topMargin: 28;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 45;
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 16;
height: paintedHeight; height: paintedHeight;
// Style // Style
color: hifi.colors.darkGray; color: hifi.colors.darkGray;
@ -286,21 +367,117 @@ Rectangle {
anchors.right: editionHeader.right; anchors.right: editionHeader.right;
height: paintedHeight; height: paintedHeight;
// Style // Style
color: hifi.colors.white; color: root.certTextColor;
}
// "Show In Marketplace" button
HifiControlsUit.Button {
id: showInMarketplaceButton;
enabled: root.marketplaceUrl;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.light;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 48;
anchors.right: parent.right;
width: 200;
height: 40;
text: "View In Market"
onClicked: {
sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', marketplaceUrl: root.marketplaceUrl});
}
}
}
//
// "CERTIFICATE" END
//
//
// "INFO CONTAINER" START
//
Item {
id: infoContainer;
anchors.bottom: parent.bottom;
anchors.left: parent.left;
anchors.leftMargin: titleBarText.anchors.leftMargin;
anchors.right: parent.right;
anchors.rightMargin: 24;
height: root.useGoldCert ? 220 : 372;
RalewayRegular {
id: errorText;
visible: !root.useGoldCert;
// Text size
size: 20;
// Anchors
anchors.top: parent.top;
anchors.topMargin: 36;
anchors.left: parent.left;
anchors.right: parent.right;
height: 116;
// Style
wrapMode: Text.WordWrap;
color: hifi.colors.baseGray;
verticalAlignment: Text.AlignTop;
}
RalewayRegular {
id: ownedByHeader;
text: "OWNER";
// Text size
size: 16;
// Anchors
anchors.top: errorText.visible ? errorText.bottom : parent.top;
anchors.topMargin: 28;
anchors.left: parent.left;
anchors.right: parent.right;
height: paintedHeight;
// Style
color: hifi.colors.darkGray;
}
RalewayRegular {
id: ownedBy;
text: root.itemOwner;
// Text size
size: 22;
// Anchors
anchors.top: ownedByHeader.bottom;
anchors.topMargin: 8;
anchors.left: ownedByHeader.left;
height: paintedHeight;
// Style
color: root.infoTextColor;
elide: Text.ElideRight;
}
AnonymousProRegular {
id: isMyCertText;
visible: root.isMyCert && ownedBy.text !== "--" && ownedBy.text !== "";
text: "(Private)";
size: 18;
// Anchors
anchors.top: ownedBy.top;
anchors.topMargin: 4;
anchors.bottom: ownedBy.bottom;
anchors.left: ownedBy.right;
anchors.leftMargin: 6;
anchors.right: ownedByHeader.right;
// Style
color: root.infoTextColor;
elide: Text.ElideRight;
verticalAlignment: Text.AlignVCenter;
} }
RalewayRegular { RalewayRegular {
id: dateOfPurchaseHeader; id: dateOfPurchaseHeader;
text: "DATE OF PURCHASE"; text: "PURCHASE DATE";
// Text size // Text size
size: 16; size: 16;
// Anchors // Anchors
anchors.top: edition.bottom; anchors.top: ownedBy.bottom;
anchors.topMargin: 28; anchors.topMargin: 28;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: 45; anchors.right: parent.horizontalCenter;
anchors.right: parent.right; anchors.rightMargin: 8;
anchors.rightMargin: 16;
height: paintedHeight; height: paintedHeight;
// Style // Style
color: hifi.colors.darkGray; color: hifi.colors.darkGray;
@ -317,73 +494,58 @@ Rectangle {
anchors.right: dateOfPurchaseHeader.right; anchors.right: dateOfPurchaseHeader.right;
height: paintedHeight; height: paintedHeight;
// Style // Style
color: hifi.colors.white; color: root.infoTextColor;
} }
RalewayRegular { RalewayRegular {
id: errorText; id: priceHeader;
text: "PURCHASE PRICE";
// Text size // Text size
size: 20; size: 16;
// Anchors // Anchors
anchors.top: dateOfPurchase.bottom; anchors.top: ownedBy.bottom;
anchors.topMargin: 36; anchors.topMargin: 28;
anchors.left: dateOfPurchase.left; anchors.left: parent.horizontalCenter;
anchors.right: dateOfPurchase.right;
anchors.bottom: parent.bottom;
// Style
wrapMode: Text.WordWrap;
color: hifi.colors.redHighlight;
verticalAlignment: Text.AlignTop;
}
}
//
// "CERTIFICATE" END
//
Item {
id: buttonsContainer;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 30;
anchors.left: parent.left;
anchors.right: parent.right;
height: 50;
// "Cancel" button
HifiControlsUit.Button {
color: hifi.buttons.noneBorderlessWhite;
colorScheme: hifi.colorSchemes.light;
anchors.top: parent.top;
anchors.left: parent.left;
anchors.leftMargin: 30;
width: parent.width/2 - 50;
height: 50;
text: "close";
onClicked: {
if (root.isLightbox) {
root.visible = false;
} else {
sendToScript({method: 'inspectionCertificate_closeClicked', closeGoesToPurchases: root.closeGoesToPurchases});
}
}
}
// "Show In Marketplace" button
HifiControlsUit.Button {
id: showInMarketplaceButton;
enabled: root.marketplaceUrl;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.light;
anchors.top: parent.top;
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 30; height: paintedHeight;
width: parent.width/2 - 50; // Style
height: 50; color: hifi.colors.darkGray;
text: "View In Market" }
onClicked: { HiFiGlyphs {
sendToScript({method: 'inspectionCertificate_showInMarketplaceClicked', marketplaceUrl: root.marketplaceUrl}); id: hfcGlyph;
} visible: priceText.text !== "Undisclosed" && priceText.text !== "";
text: hifi.glyphs.hfc;
// Size
size: 24;
// Anchors
anchors.top: priceHeader.bottom;
anchors.topMargin: 8;
anchors.left: priceHeader.left;
width: visible ? paintedWidth + 6 : 0;
height: 40;
// Style
color: root.infoTextColor;
verticalAlignment: Text.AlignTop;
horizontalAlignment: Text.AlignLeft;
}
AnonymousProRegular {
id: priceText;
text: root.itemCost;
// Text size
size: 18;
// Anchors
anchors.top: priceHeader.bottom;
anchors.topMargin: 8;
anchors.left: hfcGlyph.right;
anchors.right: priceHeader.right;
height: paintedHeight;
// Style
color: root.infoTextColor;
} }
} }
//
// "INFO CONTAINER" END
//
// //
// FUNCTION DEFINITIONS START // FUNCTION DEFINITIONS START
@ -404,19 +566,17 @@ Rectangle {
function fromScript(message) { function fromScript(message) {
switch (message.method) { switch (message.method) {
case 'inspectionCertificate_setCertificateId': case 'inspectionCertificate_setCertificateId':
resetCert(false);
root.certificateId = message.certificateId; root.certificateId = message.certificateId;
if (message.entityId === "") {
updateCertificateStatus(1); // CERTIFICATE_STATUS_VERIFICATION_SUCCESS
} else {
root.entityId = message.entityId;
sendToScript({method: 'inspectionCertificate_requestOwnershipVerification', entity: root.entityId});
}
break; break;
case 'inspectionCertificate_resetCert': case 'inspectionCertificate_resetCert':
titleBarText.text = "Certificate"; resetCert(true);
popText.text = "PROOF OF PURCHASE";
root.certificateId = "";
root.itemName = "--";
root.itemOwner = "--";
root.itemEdition = "--";
root.dateOfPurchase = "--";
root.marketplaceUrl = "";
root.isMyCert = false;
errorText.text = "";
break; break;
default: default:
console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message)); console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message));
@ -424,7 +584,34 @@ Rectangle {
} }
signal sendToScript(var message); signal sendToScript(var message);
function resetCert(alsoResetCertID) {
if (alsoResetCertID) {
root.entityId = "";
root.certificateId = "";
}
root.certInfoReplaceMode = 5;
root.certificateInfoPending = true;
root.certificateStatusPending = true;
root.useGoldCert = true;
root.certTitleTextColor = hifi.colors.darkGray;
root.certTextColor = hifi.colors.white;
root.infoTextColor = hifi.colors.blueAccent;
titleBarText.text = "Certificate";
popText.text = "";
root.itemName = "--";
root.itemOwner = "--";
root.itemEdition = "--";
root.dateOfPurchase = "--";
root.marketplaceUrl = "";
root.itemCost = "--";
root.isMyCert = false;
errorText.text = "";
}
function getFormattedDate(timestamp) { function getFormattedDate(timestamp) {
if (timestamp === "--") {
return "--";
}
function addLeadingZero(n) { function addLeadingZero(n) {
return n < 10 ? '0' + n : '' + n; return n < 10 ? '0' + n : '' + n;
} }
@ -449,7 +636,7 @@ Rectangle {
var min = addLeadingZero(a.getMinutes()); var min = addLeadingZero(a.getMinutes());
var sec = addLeadingZero(a.getSeconds()); var sec = addLeadingZero(a.getSeconds());
return year + '-' + month + '-' + day + '<br>' + drawnHour + ':' + min + amOrPm; return year + '-' + month + '-' + day + ' ' + drawnHour + ':' + min + amOrPm;
} }
// //
// FUNCTION DEFINITIONS END // FUNCTION DEFINITIONS END

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -1115,7 +1115,7 @@ Item {
AnimatedImage { AnimatedImage {
id: sendingMoneyImage; id: sendingMoneyImage;
source: "./images/loader.gif" source: "../../common/images/loader.gif"
width: 96; width: 96;
height: width; height: width;
anchors.verticalCenter: parent.verticalCenter; anchors.verticalCenter: parent.verticalCenter;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

View file

@ -274,82 +274,88 @@ void ContextOverlayInterface::requestOwnershipVerification(const QUuid& entityID
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
if (entityProperties.getClientOnly()) { if (entityProperties.verifyStaticCertificateProperties()) {
if (entityProperties.verifyStaticCertificateProperties()) { if (entityProperties.getClientOnly()) {
SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer); SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
if (entityServer) { if (entityServer) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest; QNetworkRequest networkRequest;
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL(); QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer"); requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
QJsonObject request; QJsonObject request;
request["certificate_id"] = entityProperties.getCertificateID(); request["certificate_id"] = entityProperties.getCertificateID();
networkRequest.setUrl(requestURL); networkRequest.setUrl(requestURL);
QNetworkReply* networkReply = NULL; QNetworkReply* networkReply = NULL;
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
connect(networkReply, &QNetworkReply::finished, [=]() { connect(networkReply, &QNetworkReply::finished, [=]() {
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
jsonObject = jsonObject["data"].toObject(); jsonObject = jsonObject["data"].toObject();
if (networkReply->error() == QNetworkReply::NoError) { if (networkReply->error() == QNetworkReply::NoError) {
if (!jsonObject["invalid_reason"].toString().isEmpty()) { if (!jsonObject["invalid_reason"].toString().isEmpty()) {
qCDebug(entities) << "invalid_reason not empty"; qCDebug(entities) << "invalid_reason not empty";
} else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") { } else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
qCDebug(entities) << "'transfer_status' is 'failed'"; qCDebug(entities) << "'transfer_status' is 'failed'";
} else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") { } else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") {
qCDebug(entities) << "'transfer_status' is 'pending'"; qCDebug(entities) << "'transfer_status' is 'pending'";
} else {
QString ownerKey = jsonObject["transfer_recipient_key"].toString();
QByteArray certID = entityProperties.getCertificateID().toUtf8();
QByteArray text = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeNonce(certID, ownerKey);
QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
int certIDByteArraySize = certID.length();
int textByteArraySize = text.length();
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
certIDByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
true);
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
challengeOwnershipPacket->writePrimitive(textByteArraySize);
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
challengeOwnershipPacket->write(certID);
challengeOwnershipPacket->write(text);
challengeOwnershipPacket->write(nodeToChallengeByteArray);
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
// Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer");
return;
} else { } else {
startChallengeOwnershipTimer(); QString ownerKey = jsonObject["transfer_recipient_key"].toString();
}
}
} else {
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() <<
"More info:" << networkReply->readAll();
}
networkReply->deleteLater(); QByteArray certID = entityProperties.getCertificateID().toUtf8();
}); QByteArray text = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeNonce(certID, ownerKey);
} else { QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
qCWarning(context_overlay) << "Couldn't get Entity Server!";
} int certIDByteArraySize = certID.length();
int textByteArraySize = text.length();
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
certIDByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
true);
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
challengeOwnershipPacket->writePrimitive(textByteArraySize);
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
challengeOwnershipPacket->write(certID);
challengeOwnershipPacket->write(text);
challengeOwnershipPacket->write(nodeToChallengeByteArray);
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
// Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer");
return;
} else {
startChallengeOwnershipTimer();
}
}
} else {
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() <<
"More info:" << networkReply->readAll();
}
networkReply->deleteLater();
});
} else {
qCWarning(context_overlay) << "Couldn't get Entity Server!";
}
} else { } else {
// We don't currently verify ownership of entities that aren't Avatar Entities,
// so they always pass Ownership Verification. It's necessary to emit this signal
// so that the Inspection Certificate can continue its information-grabbing process.
auto ledger = DependencyManager::get<Ledger>(); auto ledger = DependencyManager::get<Ledger>();
_challengeOwnershipTimeoutTimer.stop(); emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS));
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED));
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!";
} }
} else {
auto ledger = DependencyManager::get<Ledger>();
_challengeOwnershipTimeoutTimer.stop();
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED));
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!";
} }
} }
@ -357,12 +363,10 @@ static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspection
void ContextOverlayInterface::openInspectionCertificate() { void ContextOverlayInterface::openInspectionCertificate() {
// lets open the tablet to the inspection certificate QML // lets open the tablet to the inspection certificate QML
if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) { if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {
setLastInspectedEntity(_currentEntityWithContextOverlay);
auto tablet = dynamic_cast<TabletProxy*>(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); auto tablet = dynamic_cast<TabletProxy*>(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
tablet->loadQMLSource(INSPECTION_CERTIFICATE_QML_PATH); tablet->loadQMLSource(INSPECTION_CERTIFICATE_QML_PATH);
_hmdScriptingInterface->openTablet(); _hmdScriptingInterface->openTablet();
setLastInspectedEntity(_currentEntityWithContextOverlay);
requestOwnershipVerification(_lastInspectedEntity);
} }
} }

View file

@ -57,7 +57,7 @@ public:
bool getEnabled() { return _enabled; } bool getEnabled() { return _enabled; }
bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; } bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; }
void setIsInMarketplaceInspectionMode(bool mode) { _isInMarketplaceInspectionMode = mode; } void setIsInMarketplaceInspectionMode(bool mode) { _isInMarketplaceInspectionMode = mode; }
void requestOwnershipVerification(const QUuid& entityID); Q_INVOKABLE void requestOwnershipVerification(const QUuid& entityID);
EntityPropertyFlags getEntityPropertyFlags() { return _entityPropertyFlags; } EntityPropertyFlags getEntityPropertyFlags() { return _entityPropertyFlags; }
signals: signals:

View file

@ -75,10 +75,10 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie
) { ) {
// Rotate surface normal and eye direction // Rotate surface normal and eye direction
vec3 ambientSpaceSurfaceNormal = (ambient.transform * vec4(surface.normal, 0.0)).xyz; vec3 ambientSpaceSurfaceNormal = (ambient.transform * vec4(surface.normal, 0.0)).xyz;
vec3 ambientSpaceSurfaceEyeDir = (ambient.transform * vec4(surface.eyeDir, 0.0)).xyz; vec3 ambientSpaceSurfaceEyeDir = (ambient.transform * vec4(surface.eyeDir, 0.0)).xyz;
<@if supportScattering@> <@if supportScattering@>
vec3 ambientSpaceLowNormalCurvature = (ambient.transform * lowNormalCurvature).xyz; vec3 ambientSpaceLowNormal = (ambient.transform * vec4(lowNormalCurvature.xyz, 0.0)).xyz;
<@endif@> <@endif@>
vec3 ambientFresnel = fresnelSchlickAmbient(fresnelF0, surface.ndotv, 1.0-surface.roughness); vec3 ambientFresnel = fresnelSchlickAmbient(fresnelF0, surface.ndotv, 1.0-surface.roughness);
@ -99,7 +99,7 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie
obscurance = min(obscurance, ambientOcclusion); obscurance = min(obscurance, ambientOcclusion);
// Diffuse from ambient // Diffuse from ambient
diffuse = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), ambientSpaceLowNormalCurvature).xyz; diffuse = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), ambientSpaceLowNormal).xyz;
// Scattering ambient specular is the same as non scattering for now // Scattering ambient specular is the same as non scattering for now
// TODO: we should use the same specular answer as for direct lighting // TODO: we should use the same specular answer as for direct lighting

View file

@ -163,6 +163,7 @@ var selectionDisplay = null; // for gridTool.js to ignore
var certificateId = itemCertificateId || (Entities.getEntityProperties(currentEntityWithContextOverlay, ['certificateID']).certificateID); var certificateId = itemCertificateId || (Entities.getEntityProperties(currentEntityWithContextOverlay, ['certificateID']).certificateID);
tablet.sendToQml({ tablet.sendToQml({
method: 'inspectionCertificate_setCertificateId', method: 'inspectionCertificate_setCertificateId',
entityId: currentEntityWithContextOverlay,
certificateId: certificateId certificateId: certificateId
}); });
} }
@ -584,6 +585,9 @@ var selectionDisplay = null; // for gridTool.js to ignore
case 'inspectionCertificate_closeClicked': case 'inspectionCertificate_closeClicked':
tablet.gotoHomeScreen(); tablet.gotoHomeScreen();
break; break;
case 'inspectionCertificate_requestOwnershipVerification':
ContextOverlay.requestOwnershipVerification(message.entity);
break;
case 'inspectionCertificate_showInMarketplaceClicked': case 'inspectionCertificate_showInMarketplaceClicked':
tablet.gotoWebScreen(message.marketplaceUrl, MARKETPLACES_INJECT_SCRIPT_URL); tablet.gotoWebScreen(message.marketplaceUrl, MARKETPLACES_INJECT_SCRIPT_URL);
break; break;