diff --git a/harbour-fernschreiber.pro b/harbour-fernschreiber.pro index 67d6326..3731efa 100644 --- a/harbour-fernschreiber.pro +++ b/harbour-fernschreiber.pro @@ -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 \ diff --git a/qml/pages/NewChatPage.qml b/qml/pages/NewChatPage.qml index 42b3933..0579f11 100644 --- a/qml/pages/NewChatPage.qml +++ b/qml/pages/NewChatPage.qml @@ -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; diff --git a/src/contactsmodel.cpp b/src/contactsmodel.cpp new file mode 100644 index 0000000..ebb0984 --- /dev/null +++ b/src/contactsmodel.cpp @@ -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 . +*/ + +#include "contactsmodel.h" +#include + +#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 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 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); +} diff --git a/src/contactsmodel.h b/src/contactsmodel.h new file mode 100644 index 0000000..e9c38b4 --- /dev/null +++ b/src/contactsmodel.h @@ -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 . +*/ + +#ifndef CONTACTSMODEL_H +#define CONTACTSMODEL_H + +#include +#include + +#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 contactIds; +}; + +#endif // CONTACTSMODEL_H diff --git a/src/harbour-fernschreiber.cpp b/src/harbour-fernschreiber.cpp index 1c54a3e..a75f8de 100644 --- a/src/harbour-fernschreiber.cpp +++ b/src/harbour-fernschreiber.cpp @@ -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(); diff --git a/src/tdlibwrapper.cpp b/src/tdlibwrapper.cpp index 84634fe..bf94d2b 100644 --- a/src/tdlibwrapper.cpp +++ b/src/tdlibwrapper.cpp @@ -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 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 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"); diff --git a/src/tdlibwrapper.h b/src/tdlibwrapper.h index d2d3268..8bc0f9b 100644 --- a/src/tdlibwrapper.h +++ b/src/tdlibwrapper.h @@ -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 contacts; QVariantMap unreadMessageInformation; QVariantMap unreadChatInformation; QHash basicGroups;