Move contacts to an own model

This commit is contained in:
Sebastian Wolf 2020-11-24 16:13:16 +01:00
parent 7da8957423
commit 86599b2859
7 changed files with 192 additions and 76 deletions

View file

@ -24,6 +24,7 @@ SOURCES += src/harbour-fernschreiber.cpp \
src/appsettings.cpp \
src/chatlistmodel.cpp \
src/chatmodel.cpp \
src/contactsmodel.cpp \
src/dbusadaptor.cpp \
src/dbusinterface.cpp \
src/emojisearchworker.cpp \
@ -146,6 +147,7 @@ HEADERS += \
src/appsettings.h \
src/chatlistmodel.h \
src/chatmodel.h \
src/contactsmodel.h \
src/dbusadaptor.h \
src/dbusinterface.h \
src/debuglog.h \

View file

@ -26,12 +26,12 @@ Page {
id: newChatPage
allowedOrientations: Orientation.All
property var contacts;
property bool isLoading: true;
onStatusChanged: {
if (status === PageStatus.Active) {
newChatPage.contacts = tdLibWrapper.getContactsFullInfo();
contactsModel.hydrateContacts();
contactsListView.model = contactsModel;
newChatPage.isLoading = false;
}
}
@ -59,7 +59,6 @@ Page {
SilicaListView {
id: contactsListView
model: newChatPage.contacts
clip: true
width: parent.width
height: parent.height
@ -87,15 +86,15 @@ Page {
Behavior on opacity { FadeAnimation {} }
pictureThumbnail {
photoData: (typeof modelData.profile_photo !== "undefined") ? modelData.profile_photo.small : {}
photoData: (typeof display.profile_photo !== "undefined") ? display.profile_photo.small : {}
}
width: parent.width
primaryText.text: Emoji.emojify(Functions.getUserName(modelData), primaryText.font.pixelSize, "../js/emoji/")
prologSecondaryText.text: "@" + ( modelData.username !== "" ? modelData.username : modelData.id )
primaryText.text: Emoji.emojify(Functions.getUserName(display), primaryText.font.pixelSize, "../js/emoji/")
prologSecondaryText.text: "@" + ( display.username !== "" ? display.username : display.id )
tertiaryText {
maximumLineCount: 1
text: Functions.getChatPartnerStatusText(modelData.status["@type"], modelData.status.was_online);
text: Functions.getChatPartnerStatusText(display.status["@type"], display.status.was_online);
}
onClicked: {
@ -159,7 +158,7 @@ Page {
icon.source: "image://theme/icon-m-chat"
anchors.verticalCenter: parent.verticalCenter
onClicked: {
tdLibWrapper.createPrivateChat(modelData.id);
tdLibWrapper.createPrivateChat(display.id);
}
}
@ -196,7 +195,7 @@ Page {
MouseArea {
anchors.fill: parent
onClicked: {
tdLibWrapper.createPrivateChat(modelData.id);
tdLibWrapper.createPrivateChat(display.id);
}
onPressed: {
privateChatHighlightBackground.visible = true;

118
src/contactsmodel.cpp Normal file
View file

@ -0,0 +1,118 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
#include "contactsmodel.h"
#include <QListIterator>
#define DEBUG_MODULE ContactsModel
#include "debuglog.h"
namespace {
const QString STATUS("status");
const QString ID("id");
const QString TYPE("type");
const QString LAST_NAME("last_name");
const QString FIRST_NAME("first_name");
const QString USERNAME("username");
const QString _TYPE("@type");
const QString _EXTRA("@extra");
}
ContactsModel::ContactsModel(TDLibWrapper *tdLibWrapper, QObject *parent)
: QAbstractListModel(parent)
{
this->tdLibWrapper = tdLibWrapper;
connect(this->tdLibWrapper, SIGNAL(usersReceived(QString, QVariantList, int)), this, SLOT(handleUsersReceived(QString, QVariantList, int)));
}
int ContactsModel::rowCount(const QModelIndex &) const
{
return this->contacts.size();
}
QVariant ContactsModel::data(const QModelIndex &index, int role) const
{
if (index.isValid() && role == Qt::DisplayRole) {
return QVariant(contacts.value(index.row()));
}
return QVariant();
}
void ContactsModel::handleUsersReceived(const QString &extra, const QVariantList &userIds, int totalUsers)
{
if (extra == "contactsRequested") {
LOG("Received contacts list..." << totalUsers);
this->contactIds.clear();
QListIterator<QVariant> userIdIterator(userIds);
while (userIdIterator.hasNext()) {
QString nextUserId = userIdIterator.next().toString();
if (!this->tdLibWrapper->hasUserInformation(nextUserId)) {
this->tdLibWrapper->getUserFullInfo(nextUserId);
}
this->contactIds.append(nextUserId);
}
}
}
static bool compareUsers(const QVariant &user1, const QVariant &user2)
{
const QVariantMap userMap1 = user1.toMap();
const QVariantMap userMap2 = user2.toMap();
const QString lastName1 = userMap1.value(LAST_NAME).toString();
const QString lastName2 = userMap2.value(LAST_NAME).toString();
if (!lastName1.isEmpty()) {
if (lastName1 < lastName2) {
return true;
} else if (lastName1 > lastName2) {
return false;
}
}
const QString firstName1 = userMap1.value(FIRST_NAME).toString();
const QString firstName2 = userMap2.value(FIRST_NAME).toString();
if (firstName1 < firstName2) {
return true;
} else if (firstName1 > firstName2) {
return false;
}
const QString userName1 = userMap1.value(USERNAME).toString();
const QString userName2 = userMap2.value(USERNAME).toString();
if (userName1 < userName2) {
return true;
} else if (userName1 > userName2) {
return false;
}
return userMap1.value(ID).toLongLong() < userMap2.value(ID).toLongLong();
}
void ContactsModel::hydrateContacts()
{
LOG("Hydrating contacts...");
this->contacts.clear();
QListIterator<QString> userIdIterator(contactIds);
while (userIdIterator.hasNext()) {
QString nextUserId = userIdIterator.next();
LOG("Hydrating contact:" << nextUserId);
this->contacts.append(this->tdLibWrapper->getUserInformation(nextUserId));
}
LOG("Hydrated contacts:" << this->contacts.size());
std::sort(this->contacts.begin(), this->contacts.end(), compareUsers);
}

48
src/contactsmodel.h Normal file
View file

@ -0,0 +1,48 @@
/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONTACTSMODEL_H
#define CONTACTSMODEL_H
#include <QAbstractListModel>
#include <QVariantList>
#include "tdlibwrapper.h"
class ContactsModel : public QAbstractListModel
{
Q_OBJECT
public:
ContactsModel(TDLibWrapper *tdLibWrapper, QObject *parent = nullptr);
virtual int rowCount(const QModelIndex &) const;
virtual QVariant data(const QModelIndex &index, int role) const;
Q_INVOKABLE void hydrateContacts();
public slots:
void handleUsersReceived(const QString &extra, const QVariantList &userIds, int totalUsers);
private:
TDLibWrapper *tdLibWrapper;
QVariantList contacts;
QList<QString> contactIds;
};
#endif // CONTACTSMODEL_H

View file

@ -42,6 +42,7 @@
#include "stickermanager.h"
#include "tgsplugin.h"
#include "fernschreiberutils.h"
#include "contactsmodel.h"
// The default filter can be overridden by QT_LOGGING_RULES envinronment variable, e.g.
// QT_LOGGING_RULES="fernschreiber.*=true" harbour-fernschreiber
@ -96,6 +97,9 @@ int main(int argc, char *argv[])
StickerManager stickerManager(tdLibWrapper);
context->setContextProperty("stickerManager", &stickerManager);
ContactsModel contactsModel(tdLibWrapper, view.data());
context->setContextProperty("contactsModel", &contactsModel);
view->setSource(SailfishApp::pathTo("qml/harbour-fernschreiber.qml"));
view->show();
return app->exec();

View file

@ -111,7 +111,7 @@ TDLibWrapper::TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface,
connect(this->tdLibReceiver, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)), this, SIGNAL(chatPhotoUpdated(qlonglong, QVariantMap)));
connect(this->tdLibReceiver, SIGNAL(chatTitleUpdated(QString, QString)), this, SIGNAL(chatTitleUpdated(QString, QString)));
connect(this->tdLibReceiver, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)), this, SIGNAL(chatPinnedMessageUpdated(qlonglong, qlonglong)));
connect(this->tdLibReceiver, SIGNAL(usersReceived(QString, QVariantList, int)), this, SLOT(handleUsersReceived(QString, QVariantList, int)));
connect(this->tdLibReceiver, SIGNAL(usersReceived(QString, QVariantList, int)), this, SIGNAL(usersReceived(QString, QVariantList, int)));
connect(this->tdLibReceiver, SIGNAL(errorReceived(int, QString)), this, SIGNAL(errorReceived(int, QString)));
connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList)));
@ -621,6 +621,16 @@ void TDLibWrapper::createPrivateChat(const QString &userId)
this->sendRequest(requestObject);
}
void TDLibWrapper::createNewSecretChat(const QString &userId)
{
LOG("Creating new secret chat");
QVariantMap requestObject;
requestObject.insert(_TYPE, "createNewSecretChat");
requestObject.insert("user_id", userId);
requestObject.insert(_EXTRA, "openDirectly"); //gets matched in qml
this->sendRequest(requestObject);
}
void TDLibWrapper::createSupergroupChat(const QString &supergroupId)
{
LOG("Creating Supergroup Chat");
@ -927,52 +937,6 @@ void TDLibWrapper::registerJoinChat()
this->joinChatRequested = false;
}
static bool compareUsers(const QVariant &user1, const QVariant &user2)
{
const QVariantMap userMap1 = user1.toMap();
const QVariantMap userMap2 = user2.toMap();
const QString lastName1 = userMap1.value(LAST_NAME).toString();
const QString lastName2 = userMap2.value(LAST_NAME).toString();
if (!lastName1.isEmpty()) {
if (lastName1 < lastName2) {
return true;
} else if (lastName1 > lastName2) {
return false;
}
}
const QString firstName1 = userMap1.value(FIRST_NAME).toString();
const QString firstName2 = userMap2.value(FIRST_NAME).toString();
if (firstName1 < firstName2) {
return true;
} else if (firstName1 > firstName2) {
return false;
}
const QString userName1 = userMap1.value(USERNAME).toString();
const QString userName2 = userMap2.value(USERNAME).toString();
if (userName1 < userName2) {
return true;
} else if (userName1 > userName2) {
return false;
}
return userMap1.value(ID).toLongLong() < userMap2.value(ID).toLongLong();
}
QVariantList TDLibWrapper::getContactsFullInfo()
{
QVariantList preparedContacts;
QListIterator<QString> userIdIterator(contacts);
while (userIdIterator.hasNext()) {
QString nextUserId = userIdIterator.next();
if (allUsers.contains(nextUserId)) {
preparedContacts.append(allUsers.value(nextUserId));
}
}
std::sort(preparedContacts.begin(), preparedContacts.end(), compareUsers);
return preparedContacts;
}
DBusAdaptor *TDLibWrapper::getDBusAdaptor()
{
return this->dbusInterface->getDBusAdaptor();
@ -1185,23 +1149,6 @@ void TDLibWrapper::handleOpenWithChanged()
}
}
void TDLibWrapper::handleUsersReceived(const QString &extra, const QVariantList &userIds, int totalUsers)
{
if (extra == "contactsRequested") {
LOG("Received contacts list...");
contacts.clear();
QListIterator<QVariant> userIdIterator(userIds);
while (userIdIterator.hasNext()) {
QString nextUserId = userIdIterator.next().toString();
if (!this->hasUserInformation(nextUserId)) {
this->getUserFullInfo(nextUserId);
}
contacts.append(nextUserId);
}
}
emit usersReceived(extra, userIds, totalUsers);
}
void TDLibWrapper::setInitialParameters()
{
LOG("Sending initial parameters to TD Lib");

View file

@ -107,7 +107,6 @@ public:
Q_INVOKABLE void controlScreenSaver(bool enabled);
Q_INVOKABLE bool getJoinChatRequested();
Q_INVOKABLE void registerJoinChat();
Q_INVOKABLE QVariantList getContactsFullInfo();
DBusAdaptor *getDBusAdaptor();
@ -147,6 +146,7 @@ public:
Q_INVOKABLE void getGroupFullInfo(const QString &groupId, bool isSuperGroup);
Q_INVOKABLE void getUserFullInfo(const QString &userId);
Q_INVOKABLE void createPrivateChat(const QString &userId);
Q_INVOKABLE void createNewSecretChat(const QString &userId);
Q_INVOKABLE void createSupergroupChat(const QString &supergroupId);
Q_INVOKABLE void createBasicGroupChat(const QString &basicGroupId);
Q_INVOKABLE void getGroupsInCommon(const QString &userId, int limit, int offset);
@ -245,7 +245,6 @@ public slots:
void handleStickerSets(const QVariantList &stickerSets);
void handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList);
void handleOpenWithChanged();
void handleUsersReceived(const QString &extra, const QVariantList &userIds, int totalUsers);
private:
void setInitialParameters();
@ -268,7 +267,6 @@ private:
QVariantMap allUsers;
QVariantMap allUserNames;
QVariantMap chats;
QList<QString> contacts;
QVariantMap unreadMessageInformation;
QVariantMap unreadChatInformation;
QHash<qlonglong,Group*> basicGroups;