From 8e03fab8da3858c2f51063755d6ec038028497ad Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 3 Apr 2017 21:51:03 +0200 Subject: [PATCH] Improve QML app Contacts view performances Simplified sorting getting rid of complicated DelegateModel Offload sorting work to another thread via WorkerScript Get rid of polling and use token system instead --- retroshare-qml-app/src/qml.qrc | 1 + retroshare-qml-app/src/qml/ContactSort.js | 95 ++++++++ retroshare-qml-app/src/qml/Contacts.qml | 219 ++++++------------ .../src/qml/GxsIdentityDelegate.qml | 5 +- 4 files changed, 166 insertions(+), 154 deletions(-) create mode 100644 retroshare-qml-app/src/qml/ContactSort.js diff --git a/retroshare-qml-app/src/qml.qrc b/retroshare-qml-app/src/qml.qrc index e225c4e39..861577e60 100644 --- a/retroshare-qml-app/src/qml.qrc +++ b/retroshare-qml-app/src/qml.qrc @@ -18,5 +18,6 @@ qml/icons/edit-image-face-detect.png qml/icons/document-share.png qml/icons/application-menu.png + qml/ContactSort.js diff --git a/retroshare-qml-app/src/qml/ContactSort.js b/retroshare-qml-app/src/qml/ContactSort.js new file mode 100644 index 000000000..24b7fec5e --- /dev/null +++ b/retroshare-qml-app/src/qml/ContactSort.js @@ -0,0 +1,95 @@ +/* + * RetroShare Android QML App + * Copyright (C) 2017 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +function strcmp(left, right) +{ return ( left < right ? -1 : ( left > right ? 1:0 ) ) } + +var unreadMessages = {} +var contactsData = {} + +function cntcmp(left, right, searchText) +{ + if(typeof searchText !== 'undefined' && searchText.length > 0) + { + var mtc = searchText.toLowerCase() + var lfn = left.name.toLowerCase() + var rgn = right.name.toLowerCase() + var lfml = lfn.indexOf(mtc) + var rgml = rgn.indexOf(mtc) + if ( lfml !== rgml ) + { + lfml = lfml >= 0 ? lfml : Number.MAX_VALUE + rgml = rgml >= 0 ? rgml : Number.MAX_VALUE + return lfml - rgml + } + } + + var lfun = left.hasOwnProperty("unread_count") ? left.unread_count : 0 + var rgun = right.hasOwnProperty("unread_count") ? right.unread_count : 0 + if( lfun !== rgun ) return rgun - lfun + if(left.name !== right.name) return strcmp(left.name, right.name) + return strcmp(left.gxs_id, right.gxs_id) +} + +function mergeContactsUnread() +{ + var jsonData = contactsData.data + var dataLen = jsonData.length + for ( var i=0; i 0) { - gxsIdsModel.json = par.response - if(contactsView.own_gxs_id == "") refreshOwn() + contactsView.own_gxs_id = json.data[0].gxs_id + contactsView.own_nick = json.data[0].name } - rsApi.request("/identity/*/", "", refreshCallback) + else createIdentityDialog.visible = true } function refreshOwn() { - rsApi.request("/identity/own", "", function(par) - { - var json = JSON.parse(par.response) - if(json.data.length > 0) - { - contactsView.own_gxs_id = json.data[0].gxs_id - contactsView.own_nick = json.data[0].name - } - else createIdentityDialog.visible = true - }) + console.log("contactsView.refreshOwn()", visible) + rsApi.request("/identity/own", "", refreshOwnCallback) } + + function refreshUnreadCallback(par) + { + console.log("contactsView.refreshUnreadCB()", visible) + var json = JSON.parse(par.response) + mainWindow.registerToken(json.statetoken, refreshUnread) + contactsSortWorker.sendMessage( + {'action': 'refreshUnread', 'response': par.response}) + } + function refreshUnread() + { + console.log("contactsView.refreshUnread()", visible) + if(!visible) return + rsApi.request("/chat/unread_msgs", "", refreshUnreadCallback) + } + function startChatCallback(par) { var chId = JSON.parse(par.response).data.chat_id stackView.push("qrc:/qml/ChatView.qml", {'chatId': chId}) } - function refreshUnread() - { - rsApi.request("/chat/unread_msgs", "", function(par) - { - var jsonData = JSON.parse(par.response).data - var dataLen = jsonData.length - if(JSON.stringify(unreadMessages) != JSON.stringify(jsonData)) - { - unreadMessages = {} - for ( var i=0; i rgun - if(left.name !== right.name) return left.name < right.name - return left.gxs_id < right.gxs_id - }, - function(left, right) - { - if(searchText.length > 0) - { - var mtc = searchText.text.toLowerCase() - var lfn = left.name.toLowerCase() - var rgn = right.name.toLowerCase() - var lfml = lfn.indexOf(mtc) - var rgml = rgn.indexOf(mtc) - if ( lfml !== rgml ) - { - lfml = lfml >= 0 ? lfml : Number.MAX_VALUE - rgml = rgml >= 0 ? rgml : Number.MAX_VALUE - return lfml < rgml - } - } - return lessThan[0](left, right) - } - ] - - property int sortOrder: contactsView.searching ? 1 : 0 - onSortOrderChanged: resetSorting() - - property bool isSorting: false - - function insertPosition(lessThan, item) - { - var lower = 0 - var upper = items.count - while (lower < upper) - { - var middle = Math.floor(lower + (upper - lower) / 2) - var result = lessThan(item.model, items.get(middle).model); - if (result) upper = middle - else lower = middle + 1 - } - return lower - } - - function resetSorting() { items.setGroups(0, items.count, "unsorted") } - - function sort() - { - while (unsortedItems.count > 0) - { - var item = unsortedItems.get(0) - var index = insertPosition(lessThan[visualModel.sortOrder], - item) - item.groups = ["items"] - items.move(item.itemsIndex, index) - } - } - - items.includeByDefault: false - - groups: - [ - DelegateModelGroup - { - id: unsortedItems - name: "unsorted" - - includeByDefault: true - onChanged: visualModel.sort() - } - ] - - delegate: GxsIdentityDelegate {} - } - ListView { id: locationsListView width: parent.width height: contactsView.searching ? parent.height - searchBox.height : parent.height - model: visualModel + model: contactsListModel.model anchors.top: contactsView.searching ? searchBox.bottom : parent.top + delegate: GxsIdentityDelegate {} } Rectangle @@ -224,7 +154,9 @@ Item id: searchText anchors.left: searchIcon.right anchors.verticalCenter: parent.verticalCenter - onTextChanged: visualModel.resetSorting() + onTextChanged: + contactsSortWorker.sendMessage( + {'action': 'searchContact', 'sexp': text}) } } @@ -238,21 +170,6 @@ Item text: "Open Chat as: " + contactsView.own_nick + " " + contactsView.own_gxs_id } - Timer - { - id: refreshTimer - interval: 5000 - repeat: true - triggeredOnStart: true - onTriggered: - if(contactsView.visible) - { - contactsView.refreshUnread() - contactsView.refreshData() - } - Component.onCompleted: start() - } - Dialog { id: createIdentityDialog diff --git a/retroshare-qml-app/src/qml/GxsIdentityDelegate.qml b/retroshare-qml-app/src/qml/GxsIdentityDelegate.qml index 68e244982..3b14abcae 100644 --- a/retroshare-qml-app/src/qml/GxsIdentityDelegate.qml +++ b/retroshare-qml-app/src/qml/GxsIdentityDelegate.qml @@ -113,7 +113,7 @@ Item } Rectangle { - visible: contactsView.unreadMessages.hasOwnProperty(model.gxs_id) + visible: model.unread_count > 0 anchors.right: parent.right anchors.rightMargin: 10 @@ -130,8 +130,7 @@ Item { color: "white" font.bold: true - text: contactsView.unreadMessages.hasOwnProperty(model.gxs_id) ? - contactsView.unreadMessages[model.gxs_id] : '' + text: model.unread_count > 0 ? model.unread_count : '' anchors.centerIn: parent } }