From ced6a8b3966a096354029b3e20d6b4a38d8c0f27 Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Wed, 2 Nov 2022 11:00:28 +0100 Subject: [PATCH] Change contacts list to take account of all contacts in database (multiple lists, bodyless, remote provision) --- CHANGELOG.md | 1 + linphone-app/CMakeLists.txt | 2 + .../src/components/contact/ContactModel.cpp | 4 + .../src/components/contact/ContactModel.hpp | 2 + .../components/contacts/ContactsListModel.cpp | 92 ++++++++++++------- .../components/contacts/ContactsListModel.hpp | 14 ++- .../src/components/core/CoreManager.cpp | 2 +- .../components/friend/FriendListListener.cpp | 51 ++++++++++ .../components/friend/FriendListListener.hpp | 50 ++++++++++ linphone-app/ui/views/App/Main/MainWindow.qml | 2 + 10 files changed, 187 insertions(+), 33 deletions(-) create mode 100644 linphone-app/src/components/friend/FriendListListener.cpp create mode 100644 linphone-app/src/components/friend/FriendListListener.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index a0925c545..30ff3da58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New call layouts. - Display a waiting room before going into a conference. - Log viewer. +- Read contacts from all friends lists. - Option to set the display name in "using an account" tab of assistant. - Long pressed buttons. - Phone dialpad on main window. diff --git a/linphone-app/CMakeLists.txt b/linphone-app/CMakeLists.txt index 656baf131..431756981 100644 --- a/linphone-app/CMakeLists.txt +++ b/linphone-app/CMakeLists.txt @@ -204,6 +204,7 @@ set(SOURCES src/components/core/event-count-notifier/AbstractEventCountNotifier.cpp src/components/file/FileDownloader.cpp src/components/file/FileExtractor.cpp + src/components/friend/FriendListListener.cpp src/components/history/HistoryModel.cpp src/components/history/HistoryProxyModel.cpp src/components/ldap/LdapModel.cpp @@ -338,6 +339,7 @@ set(HEADERS src/components/core/event-count-notifier/AbstractEventCountNotifier.hpp src/components/file/FileDownloader.hpp src/components/file/FileExtractor.hpp + src/components/friend/FriendListListener.hpp src/components/history/HistoryModel.hpp src/components/history/HistoryProxyModel.hpp src/components/ldap/LdapModel.hpp diff --git a/linphone-app/src/components/contact/ContactModel.cpp b/linphone-app/src/components/contact/ContactModel.cpp index ddfa6cc25..7d85c58d3 100644 --- a/linphone-app/src/components/contact/ContactModel.cpp +++ b/linphone-app/src/components/contact/ContactModel.cpp @@ -215,3 +215,7 @@ Presence::PresenceLevel ContactModel::getPresenceLevel () const { bool ContactModel::hasCapability(const LinphoneEnums::FriendCapability& capability){ return mLinphoneFriend->hasCapability(LinphoneEnums::toLinphone(capability)); } + +std::shared_ptr ContactModel::getFriend() const{ + return mLinphoneFriend; +} \ No newline at end of file diff --git a/linphone-app/src/components/contact/ContactModel.hpp b/linphone-app/src/components/contact/ContactModel.hpp index c59eb01dd..e482b8d88 100644 --- a/linphone-app/src/components/contact/ContactModel.hpp +++ b/linphone-app/src/components/contact/ContactModel.hpp @@ -57,6 +57,8 @@ public: Q_INVOKABLE VcardModel *cloneVcardModel () const; Presence::PresenceLevel getPresenceLevel () const; Q_INVOKABLE bool hasCapability(const LinphoneEnums::FriendCapability& capability); + + std::shared_ptr getFriend() const; signals: void contactUpdated (); diff --git a/linphone-app/src/components/contacts/ContactsListModel.cpp b/linphone-app/src/components/contacts/ContactsListModel.cpp index c2bf043b0..337ff8fad 100644 --- a/linphone-app/src/components/contacts/ContactsListModel.cpp +++ b/linphone-app/src/components/contacts/ContactsListModel.cpp @@ -24,40 +24,26 @@ #include "components/contact/ContactModel.hpp" #include "components/contact/VcardModel.hpp" #include "components/core/CoreManager.hpp" +#include "components/friend/FriendListListener.hpp" #include "ContactsListModel.hpp" +// ============================================================================= +void ContactsListModel::connectTo(FriendListListener * listener){ + connect(listener, &FriendListListener::contactCreated, this, &ContactsListModel::onContactCreated); + connect(listener, &FriendListListener::contactDeleted, this, &ContactsListModel::onContactDeleted); + connect(listener, &FriendListListener::contactUpdated, this, &ContactsListModel::onContactUpdated); + connect(listener, &FriendListListener::syncStatusChanged, this, &ContactsListModel::onSyncStatusChanged); + connect(listener, &FriendListListener::presenceReceived, this, &ContactsListModel::onPresenceReceived); +} // ============================================================================= using namespace std; ContactsListModel::ContactsListModel (QObject *parent) : ProxyListModel(parent) { - mLinphoneFriends = CoreManager::getInstance()->getCore()->getFriendsLists().front(); - // Clean friends. - { - list> toRemove; - for (const auto &linphoneFriend : mLinphoneFriends->getFriends()) { - if (!linphoneFriend->getVcard()) - toRemove.push_back(linphoneFriend); - } - - for (const auto &linphoneFriend : toRemove) { - qWarning() << QStringLiteral("Remove one friend without vcard."); - mLinphoneFriends->removeFriend(linphoneFriend); - } - } - - // Init contacts with linphone friends list. - QQmlEngine *engine = App::getInstance()->getEngine(); - for (const auto &linphoneFriend : mLinphoneFriends->getFriends()) { - auto contact = QSharedPointer::create(linphoneFriend); - - // See: http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#data-ownership - // The returned value must have a explicit parent or a QQmlEngine::CppOwnership. - engine->setObjectOwnership(contact.get(), QQmlEngine::CppOwnership); - - addContact(contact); - } + mFriendListListener = std::make_shared(); + connectTo(mFriendListListener.get()); + update(); } ContactsListModel::~ContactsListModel(){ @@ -65,7 +51,7 @@ ContactsListModel::~ContactsListModel(){ beginResetModel(); mOptimizedSearch.clear(); mList.clear(); - mLinphoneFriends = nullptr; + mLinphoneFriends.clear(); endResetModel(); } } @@ -84,7 +70,8 @@ bool ContactsListModel::removeRows (int row, int count, const QModelIndex &paren mOptimizedSearch.remove(address.toString()); } - mLinphoneFriends->removeFriend(contact->mLinphoneFriend); + for(auto l : mLinphoneFriends) + l->removeFriend(contact->mLinphoneFriend); emit contactRemoved(contact); } @@ -123,7 +110,7 @@ ContactModel *ContactsListModel::addContact (VcardModel *vcardModel) { contact = QSharedPointer::create(vcardModel); App::getInstance()->getEngine()->setObjectOwnership(contact.get(), QQmlEngine::CppOwnership); - if (mLinphoneFriends->addFriend(contact->mLinphoneFriend) != linphone::FriendList::Status::OK) { + if (mLinphoneFriends.front()->addFriend(contact->mLinphoneFriend) != linphone::FriendList::Status::OK) { qWarning() << QStringLiteral("Unable to add contact from vcard:") << vcardModel; return nullptr; } @@ -131,9 +118,8 @@ ContactModel *ContactsListModel::addContact (VcardModel *vcardModel) { qInfo() << QStringLiteral("Add contact from vcard:") << contact.get() << vcardModel; // Make sure new subscribe is issued. - mLinphoneFriends->updateSubscriptions(); + mLinphoneFriends.front()->updateSubscriptions(); - addContact(contact); emit layoutChanged(); emit contactAdded(contact); @@ -177,3 +163,47 @@ void ContactsListModel::addContact (QSharedPointer contact) { mOptimizedSearch[address.toString()] = contact; } } + +void ContactsListModel::update(){ + beginResetModel(); + for(auto l : mLinphoneFriends) + l->removeListener(mFriendListListener); + mLinphoneFriends.clear(); + mOptimizedSearch.clear(); + mList.clear(); + endResetModel(); + + mLinphoneFriends = CoreManager::getInstance()->getCore()->getFriendsLists(); + + for(auto l : mLinphoneFriends){ + l->addListener(mFriendListListener); + for (const auto &linphoneFriend : l->getFriends()) { + onContactCreated(linphoneFriend); + } + } +} + +//------------------------------------------------------------------------------------------------ + +void ContactsListModel::onContactCreated(const std::shared_ptr & linphoneFriend){ + QQmlEngine *engine = App::getInstance()->getEngine(); + auto haveContact = std::find_if(mList.begin(), mList.end(), [linphoneFriend] (const QSharedPointer& item){ + return item.objectCast()->getFriend() == linphoneFriend; + }); + if(haveContact == mList.end()) { + auto contact = QSharedPointer::create(linphoneFriend); + // See: http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#data-ownership + // The returned value must have a explicit parent or a QQmlEngine::CppOwnership. + engine->setObjectOwnership(contact.get(), QQmlEngine::CppOwnership); + addContact(contact); + } +} +void ContactsListModel::onContactDeleted(const std::shared_ptr & linphoneFriend){ +} +void ContactsListModel::onContactUpdated(const std::shared_ptr & newFriend, const std::shared_ptr & oldFriend){ +} +void ContactsListModel::onSyncStatusChanged(linphone::FriendList::SyncStatus status, const std::string & message){ +} +void ContactsListModel::onPresenceReceived(const std::list> & friends){ +} + diff --git a/linphone-app/src/components/contacts/ContactsListModel.hpp b/linphone-app/src/components/contacts/ContactsListModel.hpp index f6ea3b627..aa59869a3 100644 --- a/linphone-app/src/components/contacts/ContactsListModel.hpp +++ b/linphone-app/src/components/contacts/ContactsListModel.hpp @@ -33,6 +33,7 @@ namespace linphone { class ContactModel; class VcardModel; +class FriendListListener; class ContactsListModel : public ProxyListModel { friend class SipAddressesModel; @@ -52,6 +53,16 @@ public: Q_INVOKABLE void removeContact (ContactModel *contact); Q_INVOKABLE void cleanAvatars (); + Q_INVOKABLE void update (); + + void connectTo(FriendListListener * listener); + +public slots: + void onContactCreated(const std::shared_ptr & linphoneFriend); + void onContactDeleted(const std::shared_ptr & linphoneFriend); + void onContactUpdated(const std::shared_ptr & newFriend, const std::shared_ptr & oldFriend); + void onSyncStatusChanged(linphone::FriendList::SyncStatus status, const std::string & message); + void onPresenceReceived(const std::list> & friends); signals: void contactAdded (QSharedPointer); @@ -65,7 +76,8 @@ private: void addContact (QSharedPointer contact); QMap> mOptimizedSearch; - std::shared_ptr mLinphoneFriends; + std::list> mLinphoneFriends; + std::shared_ptr mFriendListListener; }; #endif // CONTACTS_LIST_MODEL_H_ diff --git a/linphone-app/src/components/core/CoreManager.cpp b/linphone-app/src/components/core/CoreManager.cpp index 07ba4f78f..c4c013123 100644 --- a/linphone-app/src/components/core/CoreManager.cpp +++ b/linphone-app/src/components/core/CoreManager.cpp @@ -260,6 +260,7 @@ void CoreManager::createLinphoneCore (const QString &configPath) { Paths::getFactoryConfigFilePath(), nullptr ); + setDatabasesPaths(); // Enable LIME on your core to use encryption. mCore->enableLimeX3Dh(mCore->limeX3DhAvailable()); // Now see the CoreService.CreateGroupChatRoom to see how to create a secure chat room @@ -279,7 +280,6 @@ void CoreManager::createLinphoneCore (const QString &configPath) { QString userAgent = Utils::computeUserAgent(config); mCore->setUserAgent(Utils::appStringToCoreString(userAgent), mCore->getVersion()); mCore->start(); - setDatabasesPaths(); setOtherPaths(); mCore->enableFriendListSubscription(true); mCore->enableRecordAware(true); diff --git a/linphone-app/src/components/friend/FriendListListener.cpp b/linphone-app/src/components/friend/FriendListListener.cpp new file mode 100644 index 000000000..12d976792 --- /dev/null +++ b/linphone-app/src/components/friend/FriendListListener.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program 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. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "FriendListListener.hpp" +#include "../../utils/Utils.hpp" + +#include + +// ============================================================================= + +FriendListListener::FriendListListener(QObject *parent) : QObject(parent) { +} + +//-------------------------------------------------------------------- +void FriendListListener::onContactCreated(const std::shared_ptr & friendList, const std::shared_ptr & linphoneFriend) { + qDebug() << "onContactCreated: " << Utils::coreStringToAppString(linphoneFriend->getName()); + emit contactCreated(linphoneFriend); +} +void FriendListListener::onContactDeleted(const std::shared_ptr & friendList, const std::shared_ptr & linphoneFriend) { + qDebug() << "onContactDeleted: " << Utils::coreStringToAppString(linphoneFriend->getName()); + emit contactDeleted(linphoneFriend); +} +void FriendListListener::onContactUpdated(const std::shared_ptr & friendList, const std::shared_ptr & newFriend, const std::shared_ptr & oldFriend) { + qDebug() << "onContactUpdated: " << Utils::coreStringToAppString(newFriend->getName()); + emit contactUpdated(newFriend, oldFriend); +} +void FriendListListener::onSyncStatusChanged(const std::shared_ptr & friendList, linphone::FriendList::SyncStatus status, const std::string & message) { + qDebug() << "onSyncStatusChanged: [" << (int)status<<"] " << Utils::coreStringToAppString(message); + emit syncStatusChanged(status, message); +} +void FriendListListener::onPresenceReceived(const std::shared_ptr & friendList, const std::list> & friends) { + qDebug() << "onPresenceReceived: " <. + */ + +#ifndef FRIEND_LIST_LISTENER_H_ +#define FRIEND_LIST_LISTENER_H_ + + +#include + +#include + +// ============================================================================= + +class FriendListListener : public QObject, public linphone::FriendListListener { + Q_OBJECT + +public: + FriendListListener (QObject *parent = nullptr); + virtual void onContactCreated(const std::shared_ptr & friendList, const std::shared_ptr & linphoneFriend) override; + virtual void onContactDeleted(const std::shared_ptr & friendList, const std::shared_ptr & linphoneFriend) override; + virtual void onContactUpdated(const std::shared_ptr & friendList, const std::shared_ptr & newFriend, const std::shared_ptr & oldFriend) override; + virtual void onSyncStatusChanged(const std::shared_ptr & friendList, linphone::FriendList::SyncStatus status, const std::string & message) override; + virtual void onPresenceReceived(const std::shared_ptr & friendList, const std::list> & friends) override; + +signals: + void contactCreated(const std::shared_ptr & linphoneFriend); + void contactDeleted(const std::shared_ptr & linphoneFriend); + void contactUpdated(const std::shared_ptr & newFriend, const std::shared_ptr & oldFriend); + void syncStatusChanged(linphone::FriendList::SyncStatus status, const std::string & message); + void presenceReceived(const std::list> & friends); +}; + +#endif diff --git a/linphone-app/ui/views/App/Main/MainWindow.qml b/linphone-app/ui/views/App/Main/MainWindow.qml index e84ded5f2..b60cc6661 100644 --- a/linphone-app/ui/views/App/Main/MainWindow.qml +++ b/linphone-app/ui/views/App/Main/MainWindow.qml @@ -307,10 +307,12 @@ ApplicationWindow { visible: SettingsModel.contactsEnabled onSelected: { + ContactsListModel.update() timeline.model.unselectAll() setView('Contacts') } onClicked:{ + ContactsListModel.update() setView('Contacts') } Icon{