diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml index dcb67f3f12..c5aaf20a8f 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml @@ -29,7 +29,7 @@ Rectangle { "forward": function(resource, assetType, resourceObjectId){ switch(assetType) { case "application": - Commerce.openApp(resource); + Commerce.installApp(resource, true); break; case "avatar": MyAvatar.useFullAvatarURL(resource); @@ -137,7 +137,7 @@ Rectangle { "entity": hifi.glyphs.wand, "trash": hifi.glyphs.trash, "unknown": hifi.glyphs.circleSlash, - "wearable": hifi.glyphs.hat, + "wearable": hifi.glyphs.hat } property int color: hifi.buttons.blue; property int colorScheme: hifi.colorSchemes.dark; @@ -149,7 +149,18 @@ Rectangle { enabled: comboBox.model[comboBox.currentIndex] !== "unknown" onClicked: { - root.actions["forward"](resource, comboBox.currentText, resourceObjectId); + if (model.currentlyRecordingResources) { + model.currentlyRecordingResources = false; + } else { + model.resourceAccessEventText = ""; + model.currentlyRecordingResources = true; + root.actions["forward"](resource, comboBox.currentText, resourceObjectId); + } + sendToScript({ + method: "tester_updateResourceRecordingStatus", + objectId: resourceListModel.get(index).resourceObjectId, + status: model.currentlyRecordingResources + }); } background: Rectangle { @@ -189,7 +200,7 @@ Rectangle { contentItem: Item { HifiStylesUit.HiFiGlyphs { id: rezIcon; - text: actionButton.glyphs[comboBox.model[comboBox.currentIndex]]; + text: model.currentlyRecordingResources ? hifi.glyphs.scriptStop : actionButton.glyphs[comboBox.model[comboBox.currentIndex]]; anchors.fill: parent size: 30; horizontalAlignment: Text.AlignHCenter; @@ -304,9 +315,9 @@ Rectangle { color: hifi.colors.white text: { if (root.detailsExpanded) { - return resourceAccessEventText + return model.resourceAccessEventText } else { - return (resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..." + return (model.resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..." } } font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal }) @@ -340,7 +351,7 @@ Rectangle { anchors.top: detailsTextContainer.bottom anchors.topMargin: 8 anchors.right: parent.right - width: 150 + width: 160 height: 30 text: "Copy to Clipboard" diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml index 5f2268132c..2a4f2d0e22 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml @@ -24,17 +24,13 @@ Rectangle { id: root property string installedApps - property string resourceAccessEventText property var nextResourceObjectId: 0 - property var startDate HifiStylesUit.HifiConstants { id: hifi } ListModel { id: resourceListModel } color: hifi.colors.darkGray - Component.onCompleted: startDate = new Date() - // // TITLE BAR START // @@ -147,8 +143,7 @@ Rectangle { model: resourceListModel spacing: 8 - delegate: ItemUnderTest { - } + delegate: ItemUnderTest { } } Item { @@ -194,8 +189,6 @@ Rectangle { if (resource) { print("!!!! building resource object"); var resourceObj = buildResourceObj(resource); - print("!!!! installing resource object"); - installResourceObj(resourceObj); print("!!!! notifying script of resource object"); sendToScript({ method: 'tester_newResourceObject', @@ -235,6 +228,7 @@ Rectangle { switch (message.method) { case "newResourceObjectInTest": var resourceObject = message.resourceObject; + resourceListModel.clear(); // REMOVE THIS once we support specific referrers resourceListModel.append(resourceObject); spinner.visible = false; break; @@ -244,21 +238,9 @@ Rectangle { spinner.visible = false; break; case "resourceRequestEvent": - try { - var date = new Date(JSON.parse(message.data.date)); - } catch(err) { - print("!!!!! Date conversion failed: " + JSON.stringify(message.data)); - } - // XXX Eventually this date check goes away b/c we will - // be able to match up resouce access events to resource - // object ids, ignoring those that have -1 resource - // object ids. - if (date >= startDate) { - resourceAccessEventText += ( - "[" + date.toISOString() + "] " + - message.data.url.toString().replace("__NONE__,", "") + "\n" - ); - } + // When we support multiple items under test simultaneously, + // we'll have to replace "0" with the correct index. + resourceListModel.setProperty(0, "resourceAccessEventText", message.resourceAccessEventText); break; } } @@ -270,17 +252,13 @@ Rectangle { resource.match(/\.json\.gz$/) ? "content set" : resource.match(/\.json$/) ? "entity or wearable" : "unknown"); - return { "resourceObjectId": nextResourceObjectId++, + // Uncomment this once we support more than one item in test at the same time + //nextResourceObjectId++; + return { "resourceObjectId": nextResourceObjectId, "resource": resource, "assetType": assetType }; } - function installResourceObj(resourceObj) { - if ("application" === resourceObj.assetType) { - Commerce.installApp(resourceObj.resource); - } - } - function toUrl(resource) { var httpPattern = /^http/i; return httpPattern.test(resource) ? resource : "file:///" + resource; diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 83907df103..ffe89ffc5b 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -315,7 +315,7 @@ QString QmlCommerce::getInstalledApps(const QString& justInstalledAppID) { return installedAppsFromMarketplace; } -bool QmlCommerce::installApp(const QString& itemHref) { +bool QmlCommerce::installApp(const QString& itemHref, const bool& alsoOpenImmediately) { if (!QDir(_appsPath).exists()) { if (!QDir().mkdir(_appsPath)) { qCDebug(commerce) << "Couldn't make _appsPath directory."; @@ -325,8 +325,8 @@ bool QmlCommerce::installApp(const QString& itemHref) { QUrl appHref(itemHref); - auto request = DependencyManager::get()->createResourceRequest( - this, appHref, true, -1, "QmlCommerce::installApp"); + auto request = + DependencyManager::get()->createResourceRequest(this, appHref, true, -1, "QmlCommerce::installApp"); if (!request) { qCDebug(commerce) << "Couldn't create resource request for app."; @@ -358,13 +358,22 @@ bool QmlCommerce::installApp(const QString& itemHref) { QJsonObject appFileJsonObject = appFileJsonDocument.object(); QString scriptUrl = appFileJsonObject["scriptURL"].toString(); - if ((DependencyManager::get()->loadScript(scriptUrl.trimmed())).isNull()) { - qCDebug(commerce) << "Couldn't load script."; - return false; + // Don't try to re-load (install) a script if it's already running + QStringList runningScripts = DependencyManager::get()->getRunningScripts(); + if (!runningScripts.contains(scriptUrl)) { + if ((DependencyManager::get()->loadScript(scriptUrl.trimmed())).isNull()) { + qCDebug(commerce) << "Couldn't load script."; + return false; + } + + QFileInfo appFileInfo(appFile); + emit appInstalled(appFileInfo.baseName()); + } + + if (alsoOpenImmediately) { + QmlCommerce::openApp(itemHref); } - QFileInfo appFileInfo(appFile); - emit appInstalled(appFileInfo.baseName()); return true; }); request->send(); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index bee30e1b62..2e3c0ec24d 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -88,7 +88,7 @@ protected: Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID); Q_INVOKABLE QString getInstalledApps(const QString& justInstalledAppID = ""); - Q_INVOKABLE bool installApp(const QString& appHref); + Q_INVOKABLE bool installApp(const QString& appHref, const bool& alsoOpenImmediately = false); Q_INVOKABLE bool uninstallApp(const QString& appHref); Q_INVOKABLE bool openApp(const QString& appHref); diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index c14f4ea895..c2d2b69883 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -46,17 +46,11 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, float return retVal; } -bool ClipboardScriptingInterface::importEntities( - const QString& filename, - const bool isObservable, - const qint64 callerId -) { +bool ClipboardScriptingInterface::importEntities(const QString& filename) { bool retVal; BLOCKING_INVOKE_METHOD(qApp, "importEntities", Q_RETURN_ARG(bool, retVal), - Q_ARG(const QString&, filename), - Q_ARG(const bool, isObservable), - Q_ARG(const qint64, callerId)); + Q_ARG(const QString&, filename)); return retVal; } diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index d59a6b89d5..d6056f83a6 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -52,27 +52,30 @@ var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't writ var resourceRequestEvents = []; function signalResourceRequestEvent(data) { + // Once we can tie resource request events to specific resources, + // we will have to update the "0" in here. + resourceObjectsInTest[0].resourceAccessEventText += "[" + data.date.toISOString() + "] " + + data.url.toString().replace("__NONE__,", "") + "\n"; + ui.tablet.sendToQml({ method: "resourceRequestEvent", - data: data }); + data: data, + resourceAccessEventText: resourceObjectsInTest[0].resourceAccessEventText + }); } function onResourceRequestEvent(data) { - var resourceRequestEvent = { - "date": JSON.stringify(new Date()), - "url": data.url, - "callerId": data.callerId, - "extra": data.extra }; - resourceRequestEvents.push(resourceRequestEvent); - signalResourceRequestEvent(resourceRequestEvent); -} - -function pushResourceRequestEvents() { - var length = resourceRequestEvents.length - for (var i = 0; i < length; i++) { - if (i in resourceRequestEvents) { - signalResourceRequestEvent(resourceRequestEvents[i]); - } + // Once we can tie resource request events to specific resources, + // we will have to update the "0" in here. + if (resourceObjectsInTest[0] && resourceObjectsInTest[0].currentlyRecordingResources) { + var resourceRequestEvent = { + "date": new Date(), + "url": data.url, + "callerId": data.callerId, + "extra": data.extra + }; + resourceRequestEvents.push(resourceRequestEvent); + signalResourceRequestEvent(resourceRequestEvent); } } @@ -849,7 +852,8 @@ var resourceObjectsInTest = []; function signalNewResourceObjectInTest(resourceObject) { ui.tablet.sendToQml({ method: "newResourceObjectInTest", - resourceObject: resourceObject }); + resourceObject: resourceObject + }); } var onQmlMessageReceived = function onQmlMessageReceived(message) { @@ -915,6 +919,9 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { break; case 'tester_newResourceObject': var resourceObject = message.resourceObject; + resourceObjectsInTest = []; // REMOVE THIS once we support specific referrers + resourceObject.currentlyRecordingResources = false; + resourceObject.resourceAccessEventText = ""; resourceObjectsInTest[resourceObject.resourceObjectId] = resourceObject; signalNewResourceObjectInTest(resourceObject); break; @@ -924,6 +931,12 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { case 'tester_deleteResourceObject': delete resourceObjectsInTest[message.objectId]; break; + case 'tester_updateResourceRecordingStatus': + resourceObjectsInTest[message.objectId].currentlyRecordingResources = message.status; + if (message.status) { + resourceObjectsInTest[message.objectId].resourceAccessEventText = ""; + } + break; case 'header_marketplaceImageClicked': case 'purchases_backClicked': openMarketplace(message.referrerURL); @@ -1076,7 +1089,9 @@ function pushResourceObjectsInTest() { // that the marketplace item tester QML has heard from us, at least // so that it can indicate to the user that all of the resoruce // objects in test have been transmitted to it. - ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxResourceObjectId + 1 }); + //ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxResourceObjectId + 1 }); + // Since, for now, we only support 1 object in test, always send id: 0 + ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: 0 }); } // Function Name: onTabletScreenChanged() @@ -1165,7 +1180,6 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) { // variable amount of time to come up, in practice less than // 750ms. Script.setTimeout(pushResourceObjectsInTest, 750); - Script.setTimeout(pushResourceRequestEvents, 750); } console.debug(ui.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type +