From 7d4fd995f29529c32547fe795d62292625ec6ff3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 7 Aug 2017 14:29:47 -0700 Subject: [PATCH 01/13] First steps --- scripts/system/html/js/marketplacesInject.js | 20 +++++++++++++++++++- scripts/system/marketplaces/marketplaces.js | 5 +++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 8a8cf62008..89caa02d9e 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -87,8 +87,26 @@ }); } + function buyButtonClicked(name, author, price) { + EventBridge.emitWebEvent(JSON.stringify({ + type: "CHECKOUT", + itemName: name, + itemAuthor: author, + itemPrice: price + })); + } + function injectHiFiCode() { - // Nothing to do. + $('#side-info').find('.btn').attr('href', '#') + $('#side-info').find('.btn').on('click', function () { + buyButtonClicked("TEST ITEM", "Zach Fox", 10); + }); + + $('.item-footer').find('#price-or-edit').find('a').attr('href', '#') + $('.item-footer').find('#price-or-edit').find('a').on('click', function () { + buyButtonClicked("TEST ITEM", "Zach Fox", 10); + }); + } function updateClaraCode() { diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 7b25589e92..3eebd044e5 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -59,6 +59,11 @@ tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL); tablet.webEventReceived.connect(function (message) { + if (message.type === "CHECKOUT") { + print("ZRF: Buy Button Clicked: ", JSON.stringify(message)); + //tablet.pushOntoStack(""); + } + if (message === GOTO_DIRECTORY) { tablet.gotoWebScreen(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL); } From d7dd3316850cac0d2da24a7aafc734b6efd4d2d6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 7 Aug 2017 14:39:31 -0700 Subject: [PATCH 02/13] Bugfixes --- scripts/system/html/js/marketplacesInject.js | 16 +++++++++++----- scripts/system/marketplaces/marketplaces.js | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 89caa02d9e..61c421f96b 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -97,16 +97,19 @@ } function injectHiFiCode() { - $('#side-info').find('.btn').attr('href', '#') - $('#side-info').find('.btn').on('click', function () { - buyButtonClicked("TEST ITEM", "Zach Fox", 10); - }); - + console.log("ZRF INJECTING HIFI CODE"); $('.item-footer').find('#price-or-edit').find('a').attr('href', '#') $('.item-footer').find('#price-or-edit').find('a').on('click', function () { buyButtonClicked("TEST ITEM", "Zach Fox", 10); }); + } + function injectHiFiItemPageCode() { + console.log("ZRF INJECTING HIFI ITEM PAGE CODE"); + $('#side-info').find('.btn').attr('href', '#') + $('#side-info').find('.btn').on('click', function () { + buyButtonClicked("TEST ITEM", "Zach Fox", 10); + }); } function updateClaraCode() { @@ -354,6 +357,9 @@ case HIFI: injectHiFiCode(); break; + case HIFI_ITEM_PAGE: + injectHiFiItemPageCode(); + break; case CLARA: injectClaraCode(); break; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 3eebd044e5..c06192c9a4 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -60,7 +60,7 @@ tablet.webEventReceived.connect(function (message) { if (message.type === "CHECKOUT") { - print("ZRF: Buy Button Clicked: ", JSON.stringify(message)); + console.log("ZRF: Buy Button Clicked: ", JSON.stringify(message)); //tablet.pushOntoStack(""); } From 517128a939763e48a2e81723f80f23c83668b088 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 7 Aug 2017 16:03:42 -0700 Subject: [PATCH 03/13] More steps --- .../resources/qml/hifi/commerce/Checkout.qml | 225 ++++++++++++++++++ scripts/system/html/js/marketplacesInject.js | 6 +- scripts/system/marketplaces/marketplaces.js | 10 +- 3 files changed, 234 insertions(+), 7 deletions(-) create mode 100644 interface/resources/qml/hifi/commerce/Checkout.qml diff --git a/interface/resources/qml/hifi/commerce/Checkout.qml b/interface/resources/qml/hifi/commerce/Checkout.qml new file mode 100644 index 0000000000..9f689bd349 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/Checkout.qml @@ -0,0 +1,225 @@ +// +// Checkout.qml +// qml/hifi/commerce +// +// Checkout +// +// Created by Zach Fox on 2017-08-07 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import Hifi 1.0 as Hifi +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit +import "../../controls" as HifiControls + +// references XXX from root context + +Rectangle { + HifiConstants { id: hifi; } + + id: checkoutRoot; + // Style + color: hifi.colors.baseGray; + + // + // TITLE BAR START + // + Item { + id: titleBarContainer; + // Size + width: checkoutRoot.width; + height: 50; + // Anchors + anchors.left: parent.left; + anchors.top: parent.top; + + // Title Bar text + RalewaySemiBold { + id: titleBarText; + text: "Checkout"; + // Text size + size: hifi.fontSizes.overlayTitle; + // Anchors + anchors.fill: parent; + anchors.leftMargin: 16; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // Separator + HifiControlsUit.Separator { + anchors.left: parent.left; + anchors.right: parent.right; + anchors.bottom: parent.bottom; + } + } + // + // TITLE BAR END + // + + // + // ITEM DESCRIPTION START + // + Item { + id: itemDescriptionContainer; + // Size + width: checkoutRoot.width; + height: 150; + // Anchors + anchors.left: parent.left; + anchors.top: titleBarContainer.bottom; + + // Item Name text + RalewaySemiBold { + id: itemNameTextLabel; + text: "Item Name:"; + // Text size + size: 16; + // Anchors + anchors.top: parent.top; + anchors.topMargin: 4; + anchors.left: parent.left; + anchors.leftMargin: 16; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + RalewayRegular { + id: itemNameText; + // Text size + size: itemNameTextLabel.size; + // Anchors + anchors.top: itemNameTextLabel.top; + anchors.topMargin: itemNameTextLabel.anchors.topMargin; + anchors.left: itemNameTextLabel.right; + anchors.leftMargin: 16; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // Item Author text + RalewaySemiBold { + id: itemAuthorTextLabel; + text: "Item Author:"; + // Text size + size: 16; + // Anchors + anchors.top: itemNameTextLabel.bottom; + anchors.topMargin: 4; + anchors.left: parent.left; + anchors.leftMargin: 16; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + RalewayRegular { + id: itemAuthorText; + // Text size + size: itemAuthorTextLabel.size; + // Anchors + anchors.top: itemAuthorTextLabel.top; + anchors.topMargin: itemAuthorTextLabel.anchors.topMargin; + anchors.left: itemAuthorTextLabel.right; + anchors.leftMargin: 16; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // Item Price text + RalewaySemiBold { + id: itemPriceTextLabel; + text: "Item Price:"; + // Text size + size: 16; + // Anchors + anchors.top: itemAuthorTextLabel.bottom; + anchors.topMargin: 4; + anchors.left: parent.left; + anchors.leftMargin: 16; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + RalewayRegular { + id: itemPriceText; + // Text size + size: itemPriceTextLabel.size; + // Anchors + anchors.top: itemPriceTextLabel.top; + anchors.topMargin: itemPriceTextLabel.anchors.topMargin; + anchors.left: itemPriceTextLabel.right; + anchors.leftMargin: 16; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // Separator + HifiControlsUit.Separator { + anchors.left: parent.left; + anchors.right: parent.right; + anchors.bottom: parent.bottom; + } + } + // + // ITEM DESCRIPTION END + // + + // + // FUNCTION DEFINITIONS START + // + // + // Function Name: fromScript() + // + // Relevant Variables: + // None + // + // Arguments: + // message: The message sent from the JavaScript, in this case the Marketplaces JavaScript. + // Messages are in format "{method, params}", like json-rpc. + // + // Description: + // Called when a message is received from a script. + // + function fromScript(message) { + console.log("ZRF:", JSON.stringify(message)); + switch (message.method) { + case 'updateCheckoutQML': + console.log("ZRF:", JSON.stringify(message)); + itemNameText.text = message.itemName; + itemAuthorText.text = message.itemAuthor; + itemAuthorText.text = message.itemPrice; + break; + default: + console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message)); + } + } + signal sendToScript(var message); + + // + // FUNCTION DEFINITIONS END + // +} diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 61c421f96b..068625b792 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -97,7 +97,6 @@ } function injectHiFiCode() { - console.log("ZRF INJECTING HIFI CODE"); $('.item-footer').find('#price-or-edit').find('a').attr('href', '#') $('.item-footer').find('#price-or-edit').find('a').on('click', function () { buyButtonClicked("TEST ITEM", "Zach Fox", 10); @@ -105,10 +104,9 @@ } function injectHiFiItemPageCode() { - console.log("ZRF INJECTING HIFI ITEM PAGE CODE"); $('#side-info').find('.btn').attr('href', '#') $('#side-info').find('.btn').on('click', function () { - buyButtonClicked("TEST ITEM", "Zach Fox", 10); + buyButtonClicked($('#top-center').find('h1').text(), $('#creator').find('.value').text(), 10); }); } @@ -344,9 +342,11 @@ var DIRECTORY = 0; var HIFI = 1; var CLARA = 2; + var HIFI_ITEM_PAGE = 3; var pageType = DIRECTORY; if (location.href.indexOf("highfidelity.com/") !== -1) { pageType = HIFI; } + if (location.href.indexOf("highfidelity.com/marketplace/items/") !== -1) { pageType = HIFI_ITEM_PAGE; } if (location.href.indexOf("clara.io/") !== -1) { pageType = CLARA; } injectCommonCode(pageType === DIRECTORY); diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index c06192c9a4..19d66b7418 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -19,6 +19,7 @@ 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_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js"); + var MARKETPLACE_CHECKOUT_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/Checkout.qml"; var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; // var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; @@ -58,10 +59,11 @@ UserActivityLogger.openedMarketplace(); tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL); tablet.webEventReceived.connect(function (message) { - - if (message.type === "CHECKOUT") { - console.log("ZRF: Buy Button Clicked: ", JSON.stringify(message)); - //tablet.pushOntoStack(""); + var parsedJsonMessage = JSON.parse(message); + if (parsedJsonMessage.type === "CHECKOUT") { + console.log("ZRF: Buy Button Clicked: " + JSON.stringify(parsedJsonMessage)); + tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH); + tablet.sendToQml({ method: 'updateCheckoutQML', params: message }); } if (message === GOTO_DIRECTORY) { From 7e922cb2c2f3e54f7b6f49cb4a77abdd227be048 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 7 Aug 2017 16:16:17 -0700 Subject: [PATCH 04/13] Layout --- .../resources/qml/hifi/commerce/Checkout.qml | 212 ++++++++++-------- scripts/system/marketplaces/marketplaces.js | 2 +- 2 files changed, 125 insertions(+), 89 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/Checkout.qml b/interface/resources/qml/hifi/commerce/Checkout.qml index 9f689bd349..eae1847d89 100644 --- a/interface/resources/qml/hifi/commerce/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/Checkout.qml @@ -73,121 +73,158 @@ Rectangle { id: itemDescriptionContainer; // Size width: checkoutRoot.width; - height: 150; + height: childrenRect.height + 20; // Anchors anchors.left: parent.left; anchors.top: titleBarContainer.bottom; // Item Name text - RalewaySemiBold { - id: itemNameTextLabel; - text: "Item Name:"; - // Text size - size: 16; + Item { + id: itemNameContainer; // Anchors anchors.top: parent.top; anchors.topMargin: 4; anchors.left: parent.left; anchors.leftMargin: 16; - // Style - color: hifi.colors.lightGrayText; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - RalewayRegular { - id: itemNameText; - // Text size - size: itemNameTextLabel.size; - // Anchors - anchors.top: itemNameTextLabel.top; - anchors.topMargin: itemNameTextLabel.anchors.topMargin; - anchors.left: itemNameTextLabel.right; - anchors.leftMargin: 16; - // Style - color: hifi.colors.lightGrayText; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: childrenRect.height; + + RalewaySemiBold { + id: itemNameTextLabel; + text: "Item Name:"; + // Anchors + anchors.top: parent.top; + anchors.left: parent.left; + width: paintedWidth; + // Text size + size: 16; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + RalewayRegular { + id: itemNameText; + // Text size + size: itemNameTextLabel.size; + // Anchors + anchors.top: parent.top; + anchors.left: itemNameTextLabel.right; + anchors.leftMargin: 16; + width: paintedWidth; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } } + // Item Author text - RalewaySemiBold { - id: itemAuthorTextLabel; - text: "Item Author:"; - // Text size - size: 16; + Item { + id: itemAuthorContainer; // Anchors - anchors.top: itemNameTextLabel.bottom; + anchors.top: itemNameContainer.bottom; anchors.topMargin: 4; anchors.left: parent.left; anchors.leftMargin: 16; - // Style - color: hifi.colors.lightGrayText; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - RalewayRegular { - id: itemAuthorText; - // Text size - size: itemAuthorTextLabel.size; - // Anchors - anchors.top: itemAuthorTextLabel.top; - anchors.topMargin: itemAuthorTextLabel.anchors.topMargin; - anchors.left: itemAuthorTextLabel.right; - anchors.leftMargin: 16; - // Style - color: hifi.colors.lightGrayText; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; + anchors.right: parent.right; + anchors.rightMargin: 16; + height: childrenRect.height; + + RalewaySemiBold { + id: itemAuthorTextLabel; + text: "Item Author:"; + // Anchors + anchors.top: parent.top; + anchors.left: parent.left; + width: paintedWidth; + // Text size + size: 16; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + RalewayRegular { + id: itemAuthorText; + // Text size + size: itemAuthorTextLabel.size; + // Anchors + anchors.top: parent.top; + anchors.left: itemAuthorTextLabel.right; + anchors.leftMargin: 16; + width: paintedWidth; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } } // Item Price text - RalewaySemiBold { - id: itemPriceTextLabel; - text: "Item Price:"; - // Text size - size: 16; + Item { + id: itemPriceContainer; // Anchors - anchors.top: itemAuthorTextLabel.bottom; + anchors.top: itemAuthorContainer.bottom; anchors.topMargin: 4; anchors.left: parent.left; anchors.leftMargin: 16; - // Style - color: hifi.colors.lightGrayText; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - RalewayRegular { - id: itemPriceText; - // Text size - size: itemPriceTextLabel.size; - // Anchors - anchors.top: itemPriceTextLabel.top; - anchors.topMargin: itemPriceTextLabel.anchors.topMargin; - anchors.left: itemPriceTextLabel.right; - anchors.leftMargin: 16; - // Style - color: hifi.colors.lightGrayText; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - - // Separator - HifiControlsUit.Separator { - anchors.left: parent.left; anchors.right: parent.right; - anchors.bottom: parent.bottom; + anchors.rightMargin: 16; + height: childrenRect.height; + + RalewaySemiBold { + id: itemPriceTextLabel; + text: "Item Price:"; + // Anchors + anchors.top: parent.top; + anchors.left: parent.left; + width: paintedWidth; + // Text size + size: 20; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + RalewayRegular { + id: itemPriceText; + // Text size + size: itemPriceTextLabel.size; + // Anchors + anchors.top: parent.top; + anchors.left: itemPriceTextLabel.right; + anchors.leftMargin: 16; + width: paintedWidth; + // Style + color: hifi.colors.lightGrayText; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } } } // // ITEM DESCRIPTION END // + + // + // ACTION BUTTONS START + // + + + // + // ACTION BUTTONS END + // + // // FUNCTION DEFINITIONS START // @@ -205,13 +242,12 @@ Rectangle { // Called when a message is received from a script. // function fromScript(message) { - console.log("ZRF:", JSON.stringify(message)); switch (message.method) { case 'updateCheckoutQML': console.log("ZRF:", JSON.stringify(message)); - itemNameText.text = message.itemName; - itemAuthorText.text = message.itemAuthor; - itemAuthorText.text = message.itemPrice; + itemNameText.text = message.params.itemName; + itemAuthorText.text = message.params.itemAuthor; + itemPriceText.text = message.params.itemPrice; break; default: console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message)); diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 19d66b7418..b3020d1d82 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -63,7 +63,7 @@ if (parsedJsonMessage.type === "CHECKOUT") { console.log("ZRF: Buy Button Clicked: " + JSON.stringify(parsedJsonMessage)); tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH); - tablet.sendToQml({ method: 'updateCheckoutQML', params: message }); + tablet.sendToQml({ method: 'updateCheckoutQML', params: parsedJsonMessage }); } if (message === GOTO_DIRECTORY) { From 45424f0cfe98575cdcab0ab031225ae4b9cd75c9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 7 Aug 2017 16:25:42 -0700 Subject: [PATCH 05/13] Prototype V1 --- .../resources/qml/hifi/commerce/Checkout.qml | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/commerce/Checkout.qml b/interface/resources/qml/hifi/commerce/Checkout.qml index eae1847d89..dcf659c78c 100644 --- a/interface/resources/qml/hifi/commerce/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/Checkout.qml @@ -219,8 +219,45 @@ Rectangle { // // ACTION BUTTONS START // + Item { + id: actionButtonsContainer; + // Size + width: checkoutRoot.width; + height: 40; + // Anchors + anchors.left: parent.left; + anchors.top: itemDescriptionContainer.bottom; - + // "Cancel" button + HifiControlsUit.Button { + color: hifi.buttons.black; + colorScheme: hifi.colorSchemes.dark; + anchors.top: parent.top; + anchors.topMargin: 3; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 3; + anchors.left: parent.left; + anchors.leftMargin: 20; + width: parent.width/2 - anchors.leftMargin*2; + text: "Cancel" + //onClicked: deleteAttachment(root.attachment); + } + + // "Buy" button + HifiControlsUit.Button { + color: hifi.buttons.black; + colorScheme: hifi.colorSchemes.dark; + anchors.top: parent.top; + anchors.topMargin: 3; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 3; + anchors.right: parent.right; + anchors.rightMargin: 20; + width: parent.width/2 - anchors.rightMargin*2; + text: "Buy" + //onClicked: deleteAttachment(root.attachment); + } + } // // ACTION BUTTONS END // From 1493a310af6f9ae4b599fe5ca65bb91f0e9c4f9c Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 7 Aug 2017 17:02:24 -0700 Subject: [PATCH 06/13] Beginning of stack stuff --- .../resources/qml/hifi/commerce/Checkout.qml | 9 ++-- scripts/system/marketplaces/marketplaces.js | 51 ++++++++++++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/Checkout.qml b/interface/resources/qml/hifi/commerce/Checkout.qml index dcf659c78c..941846a484 100644 --- a/interface/resources/qml/hifi/commerce/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/Checkout.qml @@ -240,7 +240,9 @@ Rectangle { anchors.leftMargin: 20; width: parent.width/2 - anchors.leftMargin*2; text: "Cancel" - //onClicked: deleteAttachment(root.attachment); + onClicked: { + sendToScript({method: 'checkout_cancelClicked'}); + } } // "Buy" button @@ -255,7 +257,9 @@ Rectangle { anchors.rightMargin: 20; width: parent.width/2 - anchors.rightMargin*2; text: "Buy" - //onClicked: deleteAttachment(root.attachment); + onClicked: { + sendToScript({method: 'checkout_buyClicked'}); + } } } // @@ -281,7 +285,6 @@ Rectangle { function fromScript(message) { switch (message.method) { case 'updateCheckoutQML': - console.log("ZRF:", JSON.stringify(message)); itemNameText.text = message.params.itemName; itemAuthorText.text = message.params.itemAuthor; itemPriceText.text = message.params.itemPrice; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index b3020d1d82..503eb69cc3 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -131,7 +131,8 @@ } function onScreenChanged(type, url) { - onMarketplaceScreen = type === "Web" && url === MARKETPLACE_URL_INITIAL + onMarketplaceScreen = type === "Web" && url === MARKETPLACE_URL_INITIAL; + wireEventBridge(type === "QML" && url === MARKETPLACE_CHECKOUT_QML_PATH); // for toolbar mode: change button to active when window is first openend, false otherwise. marketplaceButton.editProperties({ isActive: onMarketplaceScreen }); if (type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1) { @@ -154,4 +155,52 @@ Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged); }); + + + // Function Name: wireEventBridge() + // + // Description: + // -Used to connect/disconnect the script's response to the tablet's "fromQml" signal. Set the "on" argument to enable or + // disable to event bridge. + // + // Relevant Variables: + // -hasEventBridge: true/false depending on whether we've already connected the event bridge. + var hasEventBridge = false; + function wireEventBridge(on) { + if (!tablet) { + print("Warning in wireEventBridge(): 'tablet' undefined!"); + return; + } + if (on) { + if (!hasEventBridge) { + tablet.fromQml.connect(fromQml); + hasEventBridge = true; + } + } else { + if (hasEventBridge) { + tablet.fromQml.disconnect(fromQml); + hasEventBridge = false; + } + } + } + + // Function Name: fromQml() + // + // Description: + // -Called when a message is received from Checkout.qml. The "message" argument is what is sent from the Checkout QML + // in the format "{method, params}", like json-rpc. + function fromQml(message) { + switch (message.method) { + case 'checkout_cancelClicked': + print('fromQml: ' + JSON.stringify(message)); + tablet.popFromStack(); + break; + case 'checkout_buyClicked': + tablet.popFromStack(); + break; + default: + print('Unrecognized message from Checkout.qml: ' + JSON.stringify(message)); + } + } + }()); // END LOCAL_SCOPE From 7d26d2d88b84f55e66703a2481fe7500fce765cd Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 8 Aug 2017 14:29:44 -0700 Subject: [PATCH 07/13] Switch and fix overlay clicks --- .../ui/overlays/ContextOverlayInterface.cpp | 3 ++- scripts/system/html/js/marketplacesInject.js | 22 ++++++++++++------- scripts/system/marketplaces/marketplaces.js | 1 - 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 77b9424d2f..50778d26e8 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -241,6 +241,7 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI } static const QString MARKETPLACE_BASE_URL = "https://metaverse.highfidelity.com/marketplace/items/"; +static const QString MARKETPLACES_INJECT_SCRIPT_URL = PathUtils::resourcesPath() + "../scripts/system/html/js/marketplacesInject.js"; void ContextOverlayInterface::openMarketplace() { // lets open the tablet and go to the current item in @@ -250,7 +251,7 @@ void ContextOverlayInterface::openMarketplace() { auto tablet = dynamic_cast(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); // construct the url to the marketplace item QString url = MARKETPLACE_BASE_URL + _entityMarketplaceID; - tablet->gotoWebScreen(url); + tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_URL); _hmdScriptingInterface->openTablet(); _isInMarketplaceInspectionMode = true; } diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 068625b792..93f2258810 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -25,6 +25,8 @@ var canWriteAssets = false; var xmlHttpRequest = null; var isPreparing = false; // Explicitly track download request status. + + var confirmPurchases = true; function injectCommonCode(isDirectoryPage) { @@ -97,17 +99,21 @@ } function injectHiFiCode() { - $('.item-footer').find('#price-or-edit').find('a').attr('href', '#') - $('.item-footer').find('#price-or-edit').find('a').on('click', function () { - buyButtonClicked("TEST ITEM", "Zach Fox", 10); - }); + if (confirmPurchases) { + $('.item-footer').find('#price-or-edit').find('a').attr('href', '#') + $('.item-footer').find('#price-or-edit').find('a').on('click', function () { + buyButtonClicked("TEST ITEM", "Zach Fox", 10); + }); + } } function injectHiFiItemPageCode() { - $('#side-info').find('.btn').attr('href', '#') - $('#side-info').find('.btn').on('click', function () { - buyButtonClicked($('#top-center').find('h1').text(), $('#creator').find('.value').text(), 10); - }); + if (confirmPurchases) { + $('#side-info').find('.btn').attr('href', '#') + $('#side-info').find('.btn').on('click', function () { + buyButtonClicked($('#top-center').find('h1').text(), $('#creator').find('.value').text(), 10); + }); + } } function updateClaraCode() { diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 503eb69cc3..87b920fab1 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -192,7 +192,6 @@ function fromQml(message) { switch (message.method) { case 'checkout_cancelClicked': - print('fromQml: ' + JSON.stringify(message)); tablet.popFromStack(); break; case 'checkout_buyClicked': From 69fc69cffbd56c48a032297067a3c1e4c5245233 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 8 Aug 2017 15:52:59 -0700 Subject: [PATCH 08/13] Comment fix and overlay click fix --- interface/src/ui/overlays/ContextOverlayInterface.cpp | 4 ++-- scripts/system/marketplaces/marketplaces.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 50778d26e8..37dfe0d3aa 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -241,7 +241,7 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI } static const QString MARKETPLACE_BASE_URL = "https://metaverse.highfidelity.com/marketplace/items/"; -static const QString MARKETPLACES_INJECT_SCRIPT_URL = PathUtils::resourcesPath() + "../scripts/system/html/js/marketplacesInject.js"; +static const QString MARKETPLACES_INJECT_SCRIPT_PATH = PathUtils::resourcesPath() + "../scripts/system/html/js/marketplacesInject.js"; void ContextOverlayInterface::openMarketplace() { // lets open the tablet and go to the current item in @@ -251,7 +251,7 @@ void ContextOverlayInterface::openMarketplace() { auto tablet = dynamic_cast(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); // construct the url to the marketplace item QString url = MARKETPLACE_BASE_URL + _entityMarketplaceID; - tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_URL); + tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_PATH); _hmdScriptingInterface->openTablet(); _isInMarketplaceInspectionMode = true; } diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 87b920fab1..2713bbf054 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -61,9 +61,9 @@ tablet.webEventReceived.connect(function (message) { var parsedJsonMessage = JSON.parse(message); if (parsedJsonMessage.type === "CHECKOUT") { - console.log("ZRF: Buy Button Clicked: " + JSON.stringify(parsedJsonMessage)); - tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH); + console.log("ZRF: Checkout (Get) Button Clicked: " + JSON.stringify(parsedJsonMessage)); tablet.sendToQml({ method: 'updateCheckoutQML', params: parsedJsonMessage }); + tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH); } if (message === GOTO_DIRECTORY) { From 03729bf165e725be186892819c7f7c0dc0137ae9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 8 Aug 2017 16:38:12 -0700 Subject: [PATCH 09/13] Actually fix context menu --- interface/src/ui/overlays/ContextOverlayInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 37dfe0d3aa..03a75c71dd 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -241,7 +241,6 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI } static const QString MARKETPLACE_BASE_URL = "https://metaverse.highfidelity.com/marketplace/items/"; -static const QString MARKETPLACES_INJECT_SCRIPT_PATH = PathUtils::resourcesPath() + "../scripts/system/html/js/marketplacesInject.js"; void ContextOverlayInterface::openMarketplace() { // lets open the tablet and go to the current item in @@ -251,6 +250,7 @@ void ContextOverlayInterface::openMarketplace() { auto tablet = dynamic_cast(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); // construct the url to the marketplace item QString url = MARKETPLACE_BASE_URL + _entityMarketplaceID; + QString MARKETPLACES_INJECT_SCRIPT_PATH = "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js"; tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_PATH); _hmdScriptingInterface->openTablet(); _isInMarketplaceInspectionMode = true; From b2c5a1f899d0295e38f033744ef3a8859c15bcd7 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 8 Aug 2017 17:12:06 -0700 Subject: [PATCH 10/13] Fancy MutationObserver! --- scripts/system/html/js/marketplacesInject.js | 23 ++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 93f2258810..efdea61b5d 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -100,16 +100,31 @@ function injectHiFiCode() { if (confirmPurchases) { - $('.item-footer').find('#price-or-edit').find('a').attr('href', '#') - $('.item-footer').find('#price-or-edit').find('a').on('click', function () { - buyButtonClicked("TEST ITEM", "Zach Fox", 10); + var target = document.getElementById('templated-items'); + // MutationObserver is necessary because the DOM is populated after the page is loaded. + // We're searching for changes to the element whose ID is '#templated-items' - this is + // the element that gets filled in by the AJAX. + var observer = new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + console.log(mutation.type); + $('.grid-item').find('#price-or-edit').find('a').attr('href', '#'); + $('.grid-item').find('#price-or-edit').find('.price').text("BUY"); + $('.grid-item').find('#price-or-edit').find('a').on('click', function () { + buyButtonClicked($(this).closest('.grid-item').find('.item-title').text(), $(this).closest('.grid-item').find('.creator').find('.value').text(), 10); + }); + }); + + //observer.disconnect(); }); + var config = { attributes: true, childList: true, characterData: true }; + observer.observe(target, config); } } function injectHiFiItemPageCode() { if (confirmPurchases) { - $('#side-info').find('.btn').attr('href', '#') + $('#side-info').find('.btn').attr('href', '#'); + $('#side-info').find('.btn').html('Buy Item '); $('#side-info').find('.btn').on('click', function () { buyButtonClicked($('#top-center').find('h1').text(), $('#creator').find('.value').text(), 10); }); From 4f859235171b964f1b31e9896693890463641165 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 8 Aug 2017 17:58:41 -0700 Subject: [PATCH 11/13] Tons of fixes and improvements! --- .../resources/qml/hifi/commerce/Checkout.qml | 6 ++-- scripts/system/html/js/marketplacesInject.js | 35 +++++++++++++------ scripts/system/marketplaces/marketplaces.js | 7 ++-- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/Checkout.qml b/interface/resources/qml/hifi/commerce/Checkout.qml index 941846a484..6cbd8ace3c 100644 --- a/interface/resources/qml/hifi/commerce/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/Checkout.qml @@ -24,6 +24,7 @@ Rectangle { HifiConstants { id: hifi; } id: checkoutRoot; + property string itemId; // Style color: hifi.colors.baseGray; @@ -241,7 +242,7 @@ Rectangle { width: parent.width/2 - anchors.leftMargin*2; text: "Cancel" onClicked: { - sendToScript({method: 'checkout_cancelClicked'}); + sendToScript({method: 'checkout_cancelClicked', params: itemId}); } } @@ -258,7 +259,7 @@ Rectangle { width: parent.width/2 - anchors.rightMargin*2; text: "Buy" onClicked: { - sendToScript({method: 'checkout_buyClicked'}); + sendToScript({method: 'checkout_buyClicked', params: itemId}); } } } @@ -285,6 +286,7 @@ Rectangle { function fromScript(message) { switch (message.method) { case 'updateCheckoutQML': + itemId = message.params.itemId; itemNameText.text = message.params.itemName; itemAuthorText.text = message.params.itemAuthor; itemPriceText.text = message.params.itemPrice; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index efdea61b5d..f2cd91852b 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -67,7 +67,7 @@ // Footer actions. $("#back-button").on("click", function () { - (window.history.state != null) ? window.history.back() : window.location = "https://metaverse.highfidelity.com/marketplace?"; + (document.referrer !== "") ? window.history.back() : window.location = "https://metaverse.highfidelity.com/marketplace?"; }); $("#all-markets").on("click", function () { EventBridge.emitWebEvent(GOTO_DIRECTORY); @@ -89,35 +89,45 @@ }); } - function buyButtonClicked(name, author, price) { + function buyButtonClicked(id, name, author, price) { EventBridge.emitWebEvent(JSON.stringify({ type: "CHECKOUT", + itemId: id, itemName: name, itemAuthor: author, itemPrice: price })); } + function injectBuyButtonOnMainPage() { + $('.grid-item').find('#price-or-edit').find('a').attr('href', '#'); + $('.grid-item').find('#price-or-edit').find('.price').text("BUY"); + $('.grid-item').find('#price-or-edit').find('a').on('click', function () { + buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'), + $(this).closest('.grid-item').find('.item-title').text(), + $(this).closest('.grid-item').find('.creator').find('.value').text(), + 10); + }); + } + function injectHiFiCode() { if (confirmPurchases) { var target = document.getElementById('templated-items'); // MutationObserver is necessary because the DOM is populated after the page is loaded. // We're searching for changes to the element whose ID is '#templated-items' - this is - // the element that gets filled in by the AJAX. + // the element that gets filled in by the AJAX. var observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { - console.log(mutation.type); - $('.grid-item').find('#price-or-edit').find('a').attr('href', '#'); - $('.grid-item').find('#price-or-edit').find('.price').text("BUY"); - $('.grid-item').find('#price-or-edit').find('a').on('click', function () { - buyButtonClicked($(this).closest('.grid-item').find('.item-title').text(), $(this).closest('.grid-item').find('.creator').find('.value').text(), 10); - }); + injectBuyButtonOnMainPage(); }); - //observer.disconnect(); }); var config = { attributes: true, childList: true, characterData: true }; observer.observe(target, config); + + // Try this here in case it works (it will if the user just pressed the "back" button, + // since that doesn't trigger another AJAX request. + injectBuyButtonOnMainPage(); } } @@ -126,7 +136,10 @@ $('#side-info').find('.btn').attr('href', '#'); $('#side-info').find('.btn').html('Buy Item '); $('#side-info').find('.btn').on('click', function () { - buyButtonClicked($('#top-center').find('h1').text(), $('#creator').find('.value').text(), 10); + buyButtonClicked(window.location.pathname.split("/")[3], + $('#top-center').find('h1').text(), + $('#creator').find('.value').text(), + 10); }); } } diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 2713bbf054..1a224f7735 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -192,10 +192,13 @@ function fromQml(message) { switch (message.method) { case 'checkout_cancelClicked': - tablet.popFromStack(); + tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + message.params, MARKETPLACES_INJECT_SCRIPT_URL); + // TODO: Make Marketplace a QML app that's a WebView wrapper so we can use the app stack. + // I don't think this is trivial to do since we also want to inject some JS into the DOM. + //tablet.popFromStack(); break; case 'checkout_buyClicked': - tablet.popFromStack(); + //tablet.popFromStack(); break; default: print('Unrecognized message from Checkout.qml: ' + JSON.stringify(message)); From 9d60d5153ff44e983f3c06ddfe440edce320c6d5 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 8 Aug 2017 18:00:17 -0700 Subject: [PATCH 12/13] Clarifying comment and turn setting off first --- scripts/system/html/js/marketplacesInject.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index f2cd91852b..f4136de933 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -26,7 +26,7 @@ var xmlHttpRequest = null; var isPreparing = false; // Explicitly track download request status. - var confirmPurchases = true; + var confirmAllPurchases = false; // Set this to "true" to cause Checkout.qml to popup for all items, even if free function injectCommonCode(isDirectoryPage) { @@ -111,7 +111,7 @@ } function injectHiFiCode() { - if (confirmPurchases) { + if (confirmAllPurchases) { var target = document.getElementById('templated-items'); // MutationObserver is necessary because the DOM is populated after the page is loaded. // We're searching for changes to the element whose ID is '#templated-items' - this is @@ -132,7 +132,7 @@ } function injectHiFiItemPageCode() { - if (confirmPurchases) { + if (confirmAllPurchases) { $('#side-info').find('.btn').attr('href', '#'); $('#side-info').find('.btn').html('Buy Item '); $('#side-info').find('.btn').on('click', function () { From 61526256bcd56d569964f068f7f78aa5776a9520 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 9 Aug 2017 09:30:18 -0700 Subject: [PATCH 13/13] Remove personalized comment --- scripts/system/marketplaces/marketplaces.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 1a224f7735..74812bb013 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -61,7 +61,6 @@ tablet.webEventReceived.connect(function (message) { var parsedJsonMessage = JSON.parse(message); if (parsedJsonMessage.type === "CHECKOUT") { - console.log("ZRF: Checkout (Get) Button Clicked: " + JSON.stringify(parsedJsonMessage)); tablet.sendToQml({ method: 'updateCheckoutQML', params: parsedJsonMessage }); tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH); }