mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-06-05 23:01:08 +02:00
Merge pull request #12108 from zfox23/commerce_pagination
Commerce: Support pagination at History endpoint; improve Purchases scrolling
This commit is contained in:
commit
928e3d2ef7
6 changed files with 137 additions and 44 deletions
|
@ -36,6 +36,7 @@ Rectangle {
|
||||||
property bool pendingInventoryReply: true;
|
property bool pendingInventoryReply: true;
|
||||||
property bool isShowingMyItems: false;
|
property bool isShowingMyItems: false;
|
||||||
property bool isDebuggingFirstUseTutorial: false;
|
property bool isDebuggingFirstUseTutorial: false;
|
||||||
|
property int pendingItemCount: 0;
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.white;
|
color: hifi.colors.white;
|
||||||
Connections {
|
Connections {
|
||||||
|
@ -79,18 +80,22 @@ Rectangle {
|
||||||
onInventoryResult: {
|
onInventoryResult: {
|
||||||
purchasesReceived = true;
|
purchasesReceived = true;
|
||||||
|
|
||||||
if (root.pendingInventoryReply) {
|
|
||||||
inventoryTimer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.status !== 'success') {
|
if (result.status !== 'success') {
|
||||||
console.log("Failed to get purchases", result.message);
|
console.log("Failed to get purchases", result.message);
|
||||||
} else {
|
} else if (!purchasesContentsList.dragging) { // Don't modify the view if the user's scrolling
|
||||||
var inventoryResult = processInventoryResult(result.data.assets);
|
var inventoryResult = processInventoryResult(result.data.assets);
|
||||||
|
|
||||||
|
var currentIndex = purchasesContentsList.currentIndex === -1 ? 0 : purchasesContentsList.currentIndex;
|
||||||
purchasesModel.clear();
|
purchasesModel.clear();
|
||||||
purchasesModel.append(inventoryResult);
|
purchasesModel.append(inventoryResult);
|
||||||
|
|
||||||
|
root.pendingItemCount = 0;
|
||||||
|
for (var i = 0; i < purchasesModel.count; i++) {
|
||||||
|
if (purchasesModel.get(i).status === "pending") {
|
||||||
|
root.pendingItemCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (previousPurchasesModel.count !== 0) {
|
if (previousPurchasesModel.count !== 0) {
|
||||||
checkIfAnyItemStatusChanged();
|
checkIfAnyItemStatusChanged();
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,6 +108,12 @@ Rectangle {
|
||||||
previousPurchasesModel.append(inventoryResult);
|
previousPurchasesModel.append(inventoryResult);
|
||||||
|
|
||||||
buildFilteredPurchasesModel();
|
buildFilteredPurchasesModel();
|
||||||
|
|
||||||
|
purchasesContentsList.positionViewAtIndex(currentIndex, ListView.Beginning);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.pendingInventoryReply && root.pendingItemCount > 0) {
|
||||||
|
inventoryTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
root.pendingInventoryReply = false;
|
root.pendingInventoryReply = false;
|
||||||
|
@ -419,6 +430,8 @@ Rectangle {
|
||||||
visible: (root.isShowingMyItems && filteredPurchasesModel.count !== 0) || (!root.isShowingMyItems && filteredPurchasesModel.count !== 0);
|
visible: (root.isShowingMyItems && filteredPurchasesModel.count !== 0) || (!root.isShowingMyItems && filteredPurchasesModel.count !== 0);
|
||||||
clip: true;
|
clip: true;
|
||||||
model: filteredPurchasesModel;
|
model: filteredPurchasesModel;
|
||||||
|
snapMode: ListView.SnapToItem;
|
||||||
|
highlightRangeMode: ListView.StrictlyEnforceRange;
|
||||||
// Anchors
|
// Anchors
|
||||||
anchors.top: root.canRezCertifiedItems ? separator.bottom : cantRezCertified.bottom;
|
anchors.top: root.canRezCertifiedItems ? separator.bottom : cantRezCertified.bottom;
|
||||||
anchors.topMargin: 12;
|
anchors.topMargin: 12;
|
||||||
|
|
|
@ -25,8 +25,12 @@ Item {
|
||||||
HifiConstants { id: hifi; }
|
HifiConstants { id: hifi; }
|
||||||
|
|
||||||
id: root;
|
id: root;
|
||||||
property bool historyReceived: false;
|
property bool initialHistoryReceived: false;
|
||||||
|
property bool historyRequestPending: true;
|
||||||
|
property bool noMoreHistoryData: false;
|
||||||
property int pendingCount: 0;
|
property int pendingCount: 0;
|
||||||
|
property int currentHistoryPage: 1;
|
||||||
|
property var pagesAlreadyAdded: new Array();
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: Commerce;
|
target: Commerce;
|
||||||
|
@ -36,32 +40,86 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
onHistoryResult : {
|
onHistoryResult : {
|
||||||
historyReceived = true;
|
root.initialHistoryReceived = true;
|
||||||
if (result.status === 'success') {
|
root.historyRequestPending = false;
|
||||||
var sameItemCount = 0;
|
|
||||||
tempTransactionHistoryModel.clear();
|
|
||||||
|
|
||||||
tempTransactionHistoryModel.append(result.data.history);
|
|
||||||
|
|
||||||
for (var i = 0; i < tempTransactionHistoryModel.count; i++) {
|
|
||||||
if (!transactionHistoryModel.get(i)) {
|
|
||||||
sameItemCount = -1;
|
|
||||||
break;
|
|
||||||
} else if (tempTransactionHistoryModel.get(i).transaction_type === transactionHistoryModel.get(i).transaction_type &&
|
|
||||||
tempTransactionHistoryModel.get(i).text === transactionHistoryModel.get(i).text) {
|
|
||||||
sameItemCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sameItemCount !== tempTransactionHistoryModel.count) {
|
if (result.status === 'success') {
|
||||||
transactionHistoryModel.clear();
|
var currentPage = parseInt(result.current_page);
|
||||||
|
|
||||||
|
if (result.data.history.length === 0) {
|
||||||
|
root.noMoreHistoryData = true;
|
||||||
|
console.log("No more data to retrieve from Commerce.history() endpoint.")
|
||||||
|
} else if (root.currentHistoryPage === 1) {
|
||||||
|
var sameItemCount = 0;
|
||||||
|
tempTransactionHistoryModel.clear();
|
||||||
|
|
||||||
|
tempTransactionHistoryModel.append(result.data.history);
|
||||||
|
|
||||||
for (var i = 0; i < tempTransactionHistoryModel.count; i++) {
|
for (var i = 0; i < tempTransactionHistoryModel.count; i++) {
|
||||||
transactionHistoryModel.append(tempTransactionHistoryModel.get(i));
|
if (!transactionHistoryModel.get(i)) {
|
||||||
|
sameItemCount = -1;
|
||||||
|
break;
|
||||||
|
} else if (tempTransactionHistoryModel.get(i).transaction_type === transactionHistoryModel.get(i).transaction_type &&
|
||||||
|
tempTransactionHistoryModel.get(i).text === transactionHistoryModel.get(i).text) {
|
||||||
|
sameItemCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sameItemCount !== tempTransactionHistoryModel.count) {
|
||||||
|
transactionHistoryModel.clear();
|
||||||
|
for (var i = 0; i < tempTransactionHistoryModel.count; i++) {
|
||||||
|
transactionHistoryModel.append(tempTransactionHistoryModel.get(i));
|
||||||
|
}
|
||||||
|
calculatePendingAndInvalidated();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (root.pagesAlreadyAdded.indexOf(currentPage) !== -1) {
|
||||||
|
console.log("Page " + currentPage + " of history has already been added to the list.");
|
||||||
|
} else {
|
||||||
|
// First, add the history result to a temporary model
|
||||||
|
tempTransactionHistoryModel.clear();
|
||||||
|
tempTransactionHistoryModel.append(result.data.history);
|
||||||
|
|
||||||
|
// Make a note that we've already added this page to the model...
|
||||||
|
root.pagesAlreadyAdded.push(currentPage);
|
||||||
|
|
||||||
|
var insertionIndex = 0;
|
||||||
|
// If there's nothing in the model right now, we don't need to modify insertionIndex.
|
||||||
|
if (transactionHistoryModel.count !== 0) {
|
||||||
|
var currentIteratorPage;
|
||||||
|
// Search through the whole transactionHistoryModel and look for the insertion point.
|
||||||
|
// The insertion point is found when the result page from the server is less than
|
||||||
|
// the page that the current item came from, OR when we've reached the end of the whole model.
|
||||||
|
for (var i = 0; i < transactionHistoryModel.count; i++) {
|
||||||
|
currentIteratorPage = transactionHistoryModel.get(i).resultIsFromPage;
|
||||||
|
|
||||||
|
if (currentPage < currentIteratorPage) {
|
||||||
|
insertionIndex = i;
|
||||||
|
break;
|
||||||
|
} else if (i === transactionHistoryModel.count - 1) {
|
||||||
|
insertionIndex = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through the results we just got back from the server, setting the "resultIsFromPage"
|
||||||
|
// property of those results and adding them to the main model.
|
||||||
|
for (var i = 0; i < tempTransactionHistoryModel.count; i++) {
|
||||||
|
tempTransactionHistoryModel.setProperty(i, "resultIsFromPage", currentPage);
|
||||||
|
transactionHistoryModel.insert(i + insertionIndex, tempTransactionHistoryModel.get(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
calculatePendingAndInvalidated();
|
||||||
}
|
}
|
||||||
calculatePendingAndInvalidated();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
refreshTimer.start();
|
|
||||||
|
// Only auto-refresh if the user hasn't scrolled
|
||||||
|
// and there is more data to grab
|
||||||
|
if (transactionHistory.atYBeginning && !root.noMoreHistoryData) {
|
||||||
|
refreshTimer.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,9 +192,13 @@ Item {
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
historyReceived = false;
|
transactionHistoryModel.clear();
|
||||||
Commerce.balance();
|
Commerce.balance();
|
||||||
Commerce.history();
|
initialHistoryReceived = false;
|
||||||
|
root.currentHistoryPage = 1;
|
||||||
|
root.noMoreHistoryData = false;
|
||||||
|
root.historyRequestPending = true;
|
||||||
|
Commerce.history(root.currentHistoryPage);
|
||||||
} else {
|
} else {
|
||||||
refreshTimer.stop();
|
refreshTimer.stop();
|
||||||
}
|
}
|
||||||
|
@ -164,9 +226,12 @@ Item {
|
||||||
id: refreshTimer;
|
id: refreshTimer;
|
||||||
interval: 4000;
|
interval: 4000;
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
console.log("Refreshing Wallet Home...");
|
if (transactionHistory.atYBeginning) {
|
||||||
Commerce.balance();
|
console.log("Refreshing 1st Page of Recent Activity...");
|
||||||
Commerce.history();
|
root.historyRequestPending = true;
|
||||||
|
Commerce.balance();
|
||||||
|
Commerce.history(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +306,7 @@ Item {
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
visible: transactionHistoryModel.count === 0 && root.historyReceived;
|
visible: transactionHistoryModel.count === 0 && root.initialHistoryReceived;
|
||||||
anchors.centerIn: parent;
|
anchors.centerIn: parent;
|
||||||
width: parent.width - 12;
|
width: parent.width - 12;
|
||||||
height: parent.height;
|
height: parent.height;
|
||||||
|
@ -364,7 +429,12 @@ Item {
|
||||||
onAtYEndChanged: {
|
onAtYEndChanged: {
|
||||||
if (transactionHistory.atYEnd) {
|
if (transactionHistory.atYEnd) {
|
||||||
console.log("User scrolled to the bottom of 'Recent Activity'.");
|
console.log("User scrolled to the bottom of 'Recent Activity'.");
|
||||||
// Grab next page of results and append to model
|
if (!root.historyRequestPending && !root.noMoreHistoryData) {
|
||||||
|
// Grab next page of results and append to model
|
||||||
|
root.historyRequestPending = true;
|
||||||
|
Commerce.history(++root.currentHistoryPage);
|
||||||
|
console.log("Fetching Page " + root.currentHistoryPage + " of Recent Activity...");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,11 +72,16 @@ void Ledger::signedSend(const QString& propertyName, const QByteArray& text, con
|
||||||
send(endpoint, success, fail, QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request);
|
send(endpoint, success, fail, QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail) {
|
void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail, QJsonObject& requestParams) {
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
QJsonObject request;
|
requestParams["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys());
|
||||||
request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys());
|
|
||||||
send(endpoint, success, fail, QNetworkAccessManager::PostOperation, AccountManagerAuth::Required, request);
|
send(endpoint, success, fail, QNetworkAccessManager::PostOperation, AccountManagerAuth::Required, requestParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail) {
|
||||||
|
QJsonObject requestParams;
|
||||||
|
keysQuery(endpoint, success, fail, requestParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure) {
|
void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure) {
|
||||||
|
@ -169,6 +174,7 @@ void Ledger::historySuccess(QNetworkReply& reply) {
|
||||||
QJsonObject newDataData;
|
QJsonObject newDataData;
|
||||||
newDataData["history"] = newHistoryArray;
|
newDataData["history"] = newHistoryArray;
|
||||||
newData["data"] = newDataData;
|
newData["data"] = newDataData;
|
||||||
|
newData["current_page"] = data["current_page"].toInt();
|
||||||
emit historyResult(newData);
|
emit historyResult(newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,8 +182,11 @@ void Ledger::historyFailure(QNetworkReply& reply) {
|
||||||
failResponse("history", reply);
|
failResponse("history", reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ledger::history(const QStringList& keys) {
|
void Ledger::history(const QStringList& keys, const int& pageNumber) {
|
||||||
keysQuery("history", "historySuccess", "historyFailure");
|
QJsonObject params;
|
||||||
|
params["per_page"] = 100;
|
||||||
|
params["page"] = pageNumber;
|
||||||
|
keysQuery("history", "historySuccess", "historyFailure", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The api/failResponse is called just for the side effect of logging.
|
// The api/failResponse is called just for the side effect of logging.
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
bool receiveAt(const QString& hfc_key, const QString& old_key);
|
bool receiveAt(const QString& hfc_key, const QString& old_key);
|
||||||
void balance(const QStringList& keys);
|
void balance(const QStringList& keys);
|
||||||
void inventory(const QStringList& keys);
|
void inventory(const QStringList& keys);
|
||||||
void history(const QStringList& keys);
|
void history(const QStringList& keys, const int& pageNumber);
|
||||||
void account();
|
void account();
|
||||||
void reset();
|
void reset();
|
||||||
void updateLocation(const QString& asset_id, const QString location, const bool controlledFailure = false);
|
void updateLocation(const QString& asset_id, const QString location, const bool controlledFailure = false);
|
||||||
|
@ -79,6 +79,7 @@ private:
|
||||||
QJsonObject apiResponse(const QString& label, QNetworkReply& reply);
|
QJsonObject apiResponse(const QString& label, QNetworkReply& reply);
|
||||||
QJsonObject failResponse(const QString& label, QNetworkReply& reply);
|
QJsonObject failResponse(const QString& label, QNetworkReply& reply);
|
||||||
void send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, QJsonObject request);
|
void send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, QJsonObject request);
|
||||||
|
void keysQuery(const QString& endpoint, const QString& success, const QString& fail, QJsonObject& extraRequestParams);
|
||||||
void keysQuery(const QString& endpoint, const QString& success, const QString& fail);
|
void keysQuery(const QString& endpoint, const QString& success, const QString& fail);
|
||||||
void signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure = false);
|
void signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure = false);
|
||||||
};
|
};
|
||||||
|
|
|
@ -96,12 +96,12 @@ void QmlCommerce::inventory() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlCommerce::history() {
|
void QmlCommerce::history(const int& pageNumber) {
|
||||||
auto ledger = DependencyManager::get<Ledger>();
|
auto ledger = DependencyManager::get<Ledger>();
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
QStringList cachedPublicKeys = wallet->listPublicKeys();
|
QStringList cachedPublicKeys = wallet->listPublicKeys();
|
||||||
if (!cachedPublicKeys.isEmpty()) {
|
if (!cachedPublicKeys.isEmpty()) {
|
||||||
ledger->history(cachedPublicKeys);
|
ledger->history(cachedPublicKeys, pageNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ protected:
|
||||||
Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false);
|
Q_INVOKABLE void buy(const QString& assetId, int cost, const bool controlledFailure = false);
|
||||||
Q_INVOKABLE void balance();
|
Q_INVOKABLE void balance();
|
||||||
Q_INVOKABLE void inventory();
|
Q_INVOKABLE void inventory();
|
||||||
Q_INVOKABLE void history();
|
Q_INVOKABLE void history(const int& pageNumber);
|
||||||
Q_INVOKABLE void generateKeyPair();
|
Q_INVOKABLE void generateKeyPair();
|
||||||
Q_INVOKABLE void reset();
|
Q_INVOKABLE void reset();
|
||||||
Q_INVOKABLE void resetLocalWalletOnly();
|
Q_INVOKABLE void resetLocalWalletOnly();
|
||||||
|
|
Loading…
Reference in a new issue