From 0a47672d646cc233ab4b2d2ce10477cc3d2950f3 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 18 Jul 2018 13:00:03 -0700 Subject: [PATCH] machinery for fetching next page of inifinite scroll before it really needed, and use in our infinite scrolls --- interface/resources/qml/hifi/Feed.qml | 3 +- interface/resources/qml/hifi/Pal.qml | 10 +----- .../commerce/common/sendAsset/SendAsset.qml | 3 +- .../qml/hifi/commerce/purchases/Purchases.qml | 11 ++----- .../qml/hifi/commerce/wallet/WalletHome.qml | 7 +--- .../qml/hifi/models/PSFListModel.qml | 33 +++++++++++++++++-- 6 files changed, 37 insertions(+), 30 deletions(-) diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml index 5f2dfea8c7..785b586dd2 100644 --- a/interface/resources/qml/hifi/Feed.qml +++ b/interface/resources/qml/hifi/Feed.qml @@ -53,7 +53,7 @@ Column { 'protocol=' + encodeURIComponent(Window.protocolSignature()) ]; endpoint: '/api/v1/user_stories?' + options.join('&'); - itemsPerPage: 3; + itemsPerPage: 4; processPage: function (data) { return data.user_stories.map(makeModelData); }; @@ -106,7 +106,6 @@ Column { highlightMoveDuration: -1; highlightMoveVelocity: -1; currentIndex: -1; - onAtXEndChanged: { if (scroll.atXEnd && !scroll.atXBeginning) { suggestions.getNextPage(); } } spacing: 12; width: parent.width; diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index c66ed1fe18..6884d2e1f6 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -61,7 +61,7 @@ Rectangle { 'username'; } sortAscending: connectionsTable.sortIndicatorOrder === Qt.AscendingOrder; - itemsPerPage: 9; + itemsPerPage: 10; listView: connectionsTable; processPage: function (data) { return data.users.map(function (user) { @@ -786,14 +786,6 @@ Rectangle { } model: connectionsUserModel; - Connections { - target: connectionsTable.flickableItem; - onAtYEndChanged: { - if (connectionsTable.flickableItem.atYEnd && !connectionsTable.flickableItem.atYBeginning) { - connectionsUserModel.getNextPage(); - } - } - } // This Rectangle refers to each Row in the connectionsTable. rowDelegate: Rectangle { diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml index 3e4bae4780..a515c8031f 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml @@ -398,7 +398,7 @@ Item { http: root.http; listModelName: root.listModelName; endpoint: "/api/v1/users?filter=connections"; - itemsPerPage: 8; + itemsPerPage: 9; listView: connectionsList; processPage: function (data) { return data.users; @@ -520,7 +520,6 @@ Item { visible: !connectionsLoading.visible; clip: true; model: connectionsModel; - onAtYEndChanged: if (connectionsList.atYEnd && !connectionsList.atYBeginning) { connectionsModel.getNextPage(); } snapMode: ListView.SnapToItem; // Anchors anchors.fill: parent; diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 91993d0fa3..3569ce6767 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -551,8 +551,9 @@ Rectangle { HifiModels.PSFListModel { id: purchasesModel; - itemsPerPage: 6; + itemsPerPage: 7; listModelName: 'purchases'; + listView: purchasesContentsList; getPage: function () { console.debug('getPage', purchasesModel.listModelName, root.isShowingMyItems, filterBar.primaryFilter_filterName, purchasesModel.currentPageToRetrieve, purchasesModel.itemsPerPage); Commerce.inventory( @@ -781,14 +782,6 @@ Rectangle { } } } - - - onAtYEndChanged: { - if (purchasesContentsList.atYEnd && !purchasesContentsList.atYBeginning) { - console.log("User scrolled to the bottom of 'Purchases'."); - purchasesModel.getNextPage(); - } - } } Rectangle { diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 3e0a56b4c5..a0c6057b3b 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -212,6 +212,7 @@ Item { HifiModels.PSFListModel { id: transactionHistoryModel; listModelName: "transaction history"; // For debugging. Alternatively, we could specify endpoint for that purpose, even though it's not used directly. + listView: transactionHistory; itemsPerPage: 6; getPage: function () { console.debug('getPage', transactionHistoryModel.listModelName, transactionHistoryModel.currentPageToRetrieve); @@ -346,12 +347,6 @@ Item { } } } - onAtYEndChanged: { - if (transactionHistory.atYEnd && !transactionHistory.atYBeginning) { - console.log("User scrolled to the bottom of 'Recent Activity'."); - transactionHistoryModel.getNextPage(); - } - } } Item { diff --git a/interface/resources/qml/hifi/models/PSFListModel.qml b/interface/resources/qml/hifi/models/PSFListModel.qml index 19f1a3e173..988502dd91 100644 --- a/interface/resources/qml/hifi/models/PSFListModel.qml +++ b/interface/resources/qml/hifi/models/PSFListModel.qml @@ -33,7 +33,6 @@ ListModel { // QML fires the following changed handlers even when first instantiating the Item. So we need a guard against firing them too early. property bool initialized: false; - Component.onCompleted: initialized = true; onEndpointChanged: if (initialized) { getFirstPage('delayClear'); } onSortKeyChanged: if (initialized) { getFirstPage('delayClear'); } onSearchFilterChanged: if (initialized) { getFirstPage('delayClear'); } @@ -60,7 +59,37 @@ ListModel { // Override to return one property of data, and/or to transform the elements. Must return an array of model elements. property var processPage: function (data) { return data; } - property var listView; // Optional. For debugging. + property var listView; // Optional. For debugging, or for having the scroll handler automatically call getNextPage. + property var flickable: listView && (listView.flickableItem || listView); + // 2: get two pages before you need it (i.e. one full page before you reach the end). + // 1: equivalent to paging when reaching end (and not before). + // 0: don't getNextPage on scroll at all here. The application code will do it. + property real pageAhead: 2.0; + function needsEarlyYFetch() { + return flickable + && !flickable.atYBeginning + && (flickable.contentY - flickable.originY) >= (flickable.contentHeight - (pageAhead * flickable.height)); + } + function needsEarlyXFetch() { + return flickable + && !flickable.atXBeginning + && (flickable.contentX - flickable.originX) >= (flickable.contentWidth - (pageAhead * flickable.width)); + } + function getNextPageIfHorizontalScroll() { + if (needsEarlyXFetch()) { getNextPage(); } + } + function getNextPageIfVerticalScroll() { + if (needsEarlyYFetch()) { getNextPage(); } + } + Component.onCompleted: { + initialized = true; + if (flickable && pageAhead > 0.0) { + // Pun: Scrollers are usually one direction or another, such that only one of the following will actually fire. + flickable.contentXChanged.connect(getNextPageIfHorizontalScroll); + flickable.contentYChanged.connect(getNextPageIfVerticalScroll); + } + } + property int totalPages: 0; property int totalEntries: 0; // Check consistency and call processPage.