diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml index 208cf2f49e..24753e7b6a 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml @@ -558,7 +558,7 @@ Item { // "Make a Connection" instructions Rectangle { id: connectionInstructions; - visible: connectionsModel.count === 0 && !connectionsLoading.visible; + visible: connectionsModel.count === 0 && !connectionsModel.searchFilter && !connectionsLoading.visible; anchors.fill: parent; color: "white"; diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index efd51bfdf3..b23f6ec16c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -147,7 +147,7 @@ Item { if (transactionHistory.atYBeginning) { console.log("Refreshing 1st Page of Recent Activity..."); Commerce.balance(); - transactionHistoryModel.getFirstPage(); + transactionHistoryModel.getFirstPage("delayedClear"); } } } diff --git a/interface/resources/qml/hifi/models/PSFListModel.qml b/interface/resources/qml/hifi/models/PSFListModel.qml index ece229bea8..4dc96857af 100644 --- a/interface/resources/qml/hifi/models/PSFListModel.qml +++ b/interface/resources/qml/hifi/models/PSFListModel.qml @@ -32,17 +32,9 @@ Item { onSortKeyChanged: getFirstPage(); onSearchFilterChanged: { if (searchItemTest) { - var filteredCopy = copyOfItems.filter(function (item) { - return searchItemTest(searchFilter, item); - }); + var filteredCopy = applySearchItemTest(copyOfItems); finalModel.clear(); finalModel.append(filteredCopy); - /*for (var index = 0; index < finalModel.count; index++) { - if (!searchItemTest(searchFilter, finalModel.get(index))) { - finalModel.remove(index); - index--; // Don't skip over anything now that the indices have shifted. - } - }*/ } else { // TODO: fancy timer against fast typing. getFirstPage(); } @@ -57,9 +49,11 @@ Item { // State. property int currentPageToRetrieve: 0; // 0 = before first page. -1 = we have them all. Otherwise 1-based page number. property bool retrievedAtLeastOnePage: false; - // Resets both internal `ListModel`s and resets the page to retrieve to "1". + // We normally clear on reset. But if we want to "refresh", we can delay clearing the model until we get a result. + // Not normally set directly, but rather by giving a truthy argument to getFirstPage(true); + property bool delayedClear: false; function resetModel() { - finalModel.clear(); + if (!delayedClear) { finalModel.clear(); } currentPageToRetrieve = 1; retrievedAtLeastOnePage = false; copyOfItems = []; @@ -78,6 +72,7 @@ Item { console.warn("Warning", listModelName, JSON.stringify(message)); current_page_to_retrieve = -1; requestPending = false; + delayedClear = false; } if (error || (response.status !== 'success')) { return fail(error || response.status); @@ -93,14 +88,21 @@ Item { if (searchItemTest) { copyOfItems = copyOfItems.concat(processed); if (searchFilter) { - processed = processed.filter(function (item) { - return searchItemTest(searchFilter, item); - }); + processed = applySearchItemTest(processed); } } + if (delayedClear) { + finalModel.clear(); + delayedClear = false; + } finalModel.append(processed); // FIXME keep index steady, and apply any post sort/filter retrievedAtLeastOnePage = true; } + function applySearchItemTest(items) { + return items.filter(function (item) { + return searchItemTest(searchFilter, item); + }); + } // Override either http or getPage. property var http: null; // An Item that has a request function. @@ -120,7 +122,8 @@ Item { // Start the show by retrieving data according to `getPage()`. // It can be custom-defined by this item's Parent. - property var getFirstPage: function () { + property var getFirstPage: function (delayClear) { + delayedClear = !!delayClear; resetModel(); requestPending = true; getPage(); diff --git a/scripts/system/request-service.js b/scripts/system/request-service.js new file mode 100644 index 0000000000..84e80489fa --- /dev/null +++ b/scripts/system/request-service.js @@ -0,0 +1,50 @@ +"use strict"; +// +// request-service.js +// +// Created by Howard Stearns on May 22, 2018 +// Copyright 2018 High Fidelity, Inc +// +// Distributed under the Apache License, Version 2.0 +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { // BEGIN LOCAL_SCOPE + + // QML has its own XMLHttpRequest, but: + // - npm request is easier to use. + // - It is not easy to hack QML's XMLHttpRequest to use our MetaverseServer, and to supply the user's auth when contacting it. + // a. Our custom XMLHttpRequestClass object only works with QScriptEngine, not QML's javascript. + // b. We have hacked profiles that intercept requests to our MetavserseServer (providing the correct auth), but those + // only work in QML WebEngineView. Setting up communication between ordinary QML and a hiddent WebEngineView is + // tantamount to the following anyway, and would still have to duplicate the code from request.js. + + // So, this script does two things: + // 1. Allows any root .qml to signal sendToScript({id: aString, method: 'http.request', params: byNameOptions}) + // We will then asynchonously call fromScript({id: theSameString, method: 'http.response', error: errorOrFalsey, response: body}) + // on that root object. + // 2. If the uri used (computed from byNameOptions, see request.js) begins with '/', we will: + // a. Prepend Account.metaverseServerUR. + // b. Use the appropriate auth. + + var request = Script.require('request').request; + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + function fromQml(message) { // messages are {id, method, params}, like json-rpc. See also sendToQml. + switch (message.method) { + case 'http.request': + request(message.params, function (error, response) { + console.log('HRS FIXME request-service got', JSON.stringify(error), JSON.stringify(response)); + tablet.sendToQml({ + id: message.id, + method: 'http.response', + error: error, // Alas, this isn't always a JSON-RPC conforming error object. + response: response, + jsonrpc: '2.0' + }); + }); + break; + } + } + tablet.fromQml.connect(fromQml); + Script.scriptEnding.connect(function () { tablet.fromQml.disconnect(fromQml); }); +}()); // END LOCAL_SCOPE