Commit 78958055 authored by Ronan Abhamon's avatar Ronan Abhamon

feat(src/components/contacts/ContactsListModel): on contact creation, try to...

feat(src/components/contacts/ContactsListModel): on contact creation, try to merge with existing contact
parent abe5bbdd
...@@ -138,6 +138,50 @@ next: ...@@ -138,6 +138,50 @@ next:
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void ContactModel::mergeVcardModel (VcardModel *vcardModel) {
Q_ASSERT(vcardModel != nullptr);
qInfo() << QStringLiteral("Merge vcard into contact:") << this << vcardModel;
// 1. Merge avatar.
if (vcardModel->getAvatar().isEmpty())
vcardModel->setAvatar(mVcardModel->getAvatar());
// 2. Merge sip addresses, companies, emails and urls.
for (const auto &sipAddress : mVcardModel->getSipAddresses())
vcardModel->addSipAddress(sipAddress.toString());
for (const auto &company : mVcardModel->getCompanies())
vcardModel->addCompany(company.toString());
for (const auto &email : mVcardModel->getEmails())
vcardModel->addEmail(email.toString());
for (const auto &url : mVcardModel->getUrls())
vcardModel->addUrl(url.toString());
// 3. Merge address.
{
const QVariantMap &oldAddress = vcardModel->getAddress();
QVariantMap newAddress = vcardModel->getAddress();
static const char *attributes[4] = { "street", "locality", "postalCode", "country" };
bool needMerge = true;
for (const auto &attribute : attributes)
if (!newAddress[attribute].toString().isEmpty()) {
needMerge = false;
break;
}
if (needMerge) {
for (const auto &attribute : attributes)
newAddress[attribute] = oldAddress[attribute];
}
}
setVcardModel(vcardModel);
}
// -----------------------------------------------------------------------------
VcardModel *ContactModel::cloneVcardModel () const { VcardModel *ContactModel::cloneVcardModel () const {
shared_ptr<linphone::Vcard> vcard = mVcardModel->mVcard->clone(); shared_ptr<linphone::Vcard> vcard = mVcardModel->mVcard->clone();
Q_ASSERT(vcard != nullptr); Q_ASSERT(vcard != nullptr);
......
...@@ -50,6 +50,8 @@ public: ...@@ -50,6 +50,8 @@ public:
VcardModel *getVcardModel () const; VcardModel *getVcardModel () const;
void setVcardModel (VcardModel *vcardModel); void setVcardModel (VcardModel *vcardModel);
void mergeVcardModel (VcardModel *vcardModel);
Q_INVOKABLE VcardModel *cloneVcardModel () const; Q_INVOKABLE VcardModel *cloneVcardModel () const;
signals: signals:
......
...@@ -43,18 +43,21 @@ using namespace std; ...@@ -43,18 +43,21 @@ using namespace std;
// ============================================================================= // =============================================================================
template<class T> template<class T>
inline shared_ptr<T> findBelCardValue (const list<shared_ptr<T> > &list, const QString &value) { inline shared_ptr<T> findBelCardValue (const list<shared_ptr<T> > &list, const string &value) {
string match = ::Utils::qStringToLinphoneString(value);
auto it = find_if( auto it = find_if(
list.cbegin(), list.cend(), [&match](const shared_ptr<T> &entry) { list.cbegin(), list.cend(), [&value](const shared_ptr<T> &entry) {
return match == entry->getValue(); return value == entry->getValue();
} }
); );
return it != list.cend() ? *it : nullptr; return it != list.cend() ? *it : nullptr;
} }
template<class T>
inline shared_ptr<T> findBelCardValue (const list<shared_ptr<T> > &list, const QString &value) {
return findBelCardValue(list, ::Utils::qStringToLinphoneString(value));
}
inline bool isLinphoneDesktopPhoto (const shared_ptr<belcard::BelCardPhoto> &photo) { inline bool isLinphoneDesktopPhoto (const shared_ptr<belcard::BelCardPhoto> &photo) {
return !photo->getValue().compare(0, sizeof(VCARD_SCHEME) - 1, VCARD_SCHEME); return !photo->getValue().compare(0, sizeof(VCARD_SCHEME) - 1, VCARD_SCHEME);
} }
...@@ -141,6 +144,11 @@ QString VcardModel::getAvatar () const { ...@@ -141,6 +144,11 @@ QString VcardModel::getAvatar () const {
); );
} }
inline QString getFileIdFromAppPath (const QString &path) {
const static QString appPrefix = QStringLiteral("image://%1/").arg(AvatarProvider::PROVIDER_ID);
return path.mid(appPrefix.length());
}
bool VcardModel::setAvatar (const QString &path) { bool VcardModel::setAvatar (const QString &path) {
CHECK_VCARD_IS_WRITABLE(this); CHECK_VCARD_IS_WRITABLE(this);
...@@ -148,25 +156,30 @@ bool VcardModel::setAvatar (const QString &path) { ...@@ -148,25 +156,30 @@ bool VcardModel::setAvatar (const QString &path) {
QString fileId; QString fileId;
QFile file; QFile file;
// 1. Try to copy photo in avatars folder. // 1. Try to copy photo in avatars folder if it's a right path file and
// not a application path like `image:`.
if (!path.isEmpty()) { if (!path.isEmpty()) {
file.setFileName(path); if (path.startsWith("image:"))
fileId = getFileIdFromAppPath(path);
else {
file.setFileName(path);
if (!file.exists() || QImageReader::imageFormat(path).size() == 0) if (!file.exists() || QImageReader::imageFormat(path).size() == 0)
return false; return false;
QFileInfo info(file); QFileInfo info(file);
QString uuid = QUuid::createUuid().toString(); QString uuid = QUuid::createUuid().toString();
fileId = QStringLiteral("%1.%2") fileId = QStringLiteral("%1.%2")
.arg(uuid.mid(1, uuid.length() - 2)) // Remove `{}`. .arg(uuid.mid(1, uuid.length() - 2)) // Remove `{}`.
.arg(info.suffix()); .arg(info.suffix());
QString dest = ::Utils::linphoneStringToQString(Paths::getAvatarsDirPath()) + fileId; QString dest = ::Utils::linphoneStringToQString(Paths::getAvatarsDirPath()) + fileId;
if (!file.copy(dest)) if (!file.copy(dest))
return false; return false;
qInfo() << QStringLiteral("Update avatar of `%1`. (path=%2)").arg(getUsername()).arg(dest); qInfo() << QStringLiteral("Update avatar of `%1`. (path=%2)").arg(getUsername()).arg(dest);
}
} }
// 2. Remove oldest photo. // 2. Remove oldest photo.
...@@ -298,6 +311,9 @@ bool VcardModel::addSipAddress (const QString &sipAddress) { ...@@ -298,6 +311,9 @@ bool VcardModel::addSipAddress (const QString &sipAddress) {
// Add sip address in belcard. // Add sip address in belcard.
shared_ptr<belcard::BelCard> belcard = mVcard->getVcard(); shared_ptr<belcard::BelCard> belcard = mVcard->getVcard();
if (findBelCardValue(belcard->getImpp(), interpretedSipAddress))
return false;
shared_ptr<belcard::BelCardImpp> value = belcard::BelCardGeneric::create<belcard::BelCardImpp>(); shared_ptr<belcard::BelCardImpp> value = belcard::BelCardGeneric::create<belcard::BelCardImpp>();
value->setValue(interpretedSipAddress); value->setValue(interpretedSipAddress);
...@@ -359,6 +375,9 @@ bool VcardModel::addCompany (const QString &company) { ...@@ -359,6 +375,9 @@ bool VcardModel::addCompany (const QString &company) {
CHECK_VCARD_IS_WRITABLE(this); CHECK_VCARD_IS_WRITABLE(this);
shared_ptr<belcard::BelCard> belcard = mVcard->getVcard(); shared_ptr<belcard::BelCard> belcard = mVcard->getVcard();
if (findBelCardValue(belcard->getRoles(), company))
return false;
shared_ptr<belcard::BelCardRole> value = belcard::BelCardGeneric::create<belcard::BelCardRole>(); shared_ptr<belcard::BelCardRole> value = belcard::BelCardGeneric::create<belcard::BelCardRole>();
value->setValue(::Utils::qStringToLinphoneString(company)); value->setValue(::Utils::qStringToLinphoneString(company));
...@@ -410,6 +429,9 @@ bool VcardModel::addEmail (const QString &email) { ...@@ -410,6 +429,9 @@ bool VcardModel::addEmail (const QString &email) {
CHECK_VCARD_IS_WRITABLE(this); CHECK_VCARD_IS_WRITABLE(this);
shared_ptr<belcard::BelCard> belcard = mVcard->getVcard(); shared_ptr<belcard::BelCard> belcard = mVcard->getVcard();
if (findBelCardValue(belcard->getEmails(), email))
return false;
shared_ptr<belcard::BelCardEmail> value = belcard::BelCardGeneric::create<belcard::BelCardEmail>(); shared_ptr<belcard::BelCardEmail> value = belcard::BelCardGeneric::create<belcard::BelCardEmail>();
value->setValue(::Utils::qStringToLinphoneString(email)); value->setValue(::Utils::qStringToLinphoneString(email));
...@@ -421,6 +443,7 @@ bool VcardModel::addEmail (const QString &email) { ...@@ -421,6 +443,7 @@ bool VcardModel::addEmail (const QString &email) {
qInfo() << QStringLiteral("Add new email on vcard: `%1`.").arg(email); qInfo() << QStringLiteral("Add new email on vcard: `%1`.").arg(email);
emit vcardUpdated(); emit vcardUpdated();
return true; return true;
} }
...@@ -461,6 +484,9 @@ bool VcardModel::addUrl (const QString &url) { ...@@ -461,6 +484,9 @@ bool VcardModel::addUrl (const QString &url) {
CHECK_VCARD_IS_WRITABLE(this); CHECK_VCARD_IS_WRITABLE(this);
shared_ptr<belcard::BelCard> belcard = mVcard->getVcard(); shared_ptr<belcard::BelCard> belcard = mVcard->getVcard();
if (findBelCardValue(belcard->getURLs(), url))
return false;
shared_ptr<belcard::BelCardURL> value = belcard::BelCardGeneric::create<belcard::BelCardURL>(); shared_ptr<belcard::BelCardURL> value = belcard::BelCardGeneric::create<belcard::BelCardURL>();
value->setValue(::Utils::qStringToLinphoneString(url)); value->setValue(::Utils::qStringToLinphoneString(url));
...@@ -472,6 +498,7 @@ bool VcardModel::addUrl (const QString &url) { ...@@ -472,6 +498,7 @@ bool VcardModel::addUrl (const QString &url) {
qInfo() << QStringLiteral("Add new url on vcard: `%1`.").arg(url); qInfo() << QStringLiteral("Add new url on vcard: `%1`.").arg(url);
emit vcardUpdated(); emit vcardUpdated();
return true; return true;
} }
......
...@@ -113,29 +113,44 @@ bool ContactsListModel::removeRows (int row, int count, const QModelIndex &paren ...@@ -113,29 +113,44 @@ bool ContactsListModel::removeRows (int row, int count, const QModelIndex &paren
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
ContactModel *ContactsListModel::findContactModelFromSipAddress (const QString &sipAddress) const { ContactModel *ContactsListModel::findContactModelFromSipAddress (const QString &sipAddress) const {
auto it = find_if(mList.begin(), mList.end(), [sipAddress](ContactModel *contactModel) { auto it = find_if(mList.begin(), mList.end(), [&sipAddress](ContactModel *contactModel) {
return contactModel->getVcardModel()->getSipAddresses().contains(sipAddress); return contactModel->getVcardModel()->getSipAddresses().contains(sipAddress);
}); });
return it != mList.end() ? *it : nullptr; return it != mList.end() ? *it : nullptr;
} }
ContactModel *ContactsListModel::findContactModelFromUsername (const QString &username) const {
auto it = find_if(mList.begin(), mList.end(), [&username](ContactModel *contactModel) {
return contactModel->getVcardModel()->getUsername() == username;
});
return it != mList.end() ? *it : nullptr;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
ContactModel *ContactsListModel::addContact (VcardModel *vcard) { ContactModel *ContactsListModel::addContact (VcardModel *vcardModel) {
ContactModel *contact = new ContactModel(this, vcard); // Try to merge vcardModel to an existing contact.
ContactModel *contact = findContactModelFromUsername(vcardModel->getUsername());
if (contact) {
contact->mergeVcardModel(vcardModel);
return contact;
}
contact = new ContactModel(this, vcardModel);
App::getInstance()->getEngine()->setObjectOwnership(contact, QQmlEngine::CppOwnership); App::getInstance()->getEngine()->setObjectOwnership(contact, QQmlEngine::CppOwnership);
if ( if (
mLinphoneFriends->addFriend(contact->mLinphoneFriend) != mLinphoneFriends->addFriend(contact->mLinphoneFriend) !=
linphone::FriendListStatus::FriendListStatusOK linphone::FriendListStatus::FriendListStatusOK
) { ) {
qWarning() << QStringLiteral("Unable to add contact from vcard:") << vcard; qWarning() << QStringLiteral("Unable to add contact from vcard:") << vcardModel;
delete contact; delete contact;
return nullptr; return nullptr;
} }
qInfo() << QStringLiteral("Add contact from vcard:") << contact << vcard; qInfo() << QStringLiteral("Add contact from vcard:") << contact << vcardModel;
int row = mList.count(); int row = mList.count();
......
...@@ -48,8 +48,9 @@ public: ...@@ -48,8 +48,9 @@ public:
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override; bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
ContactModel *findContactModelFromSipAddress (const QString &sipAddress) const; ContactModel *findContactModelFromSipAddress (const QString &sipAddress) const;
ContactModel *findContactModelFromUsername (const QString &username) const;
Q_INVOKABLE ContactModel *addContact (VcardModel *vcard); Q_INVOKABLE ContactModel *addContact (VcardModel *vcardModel);
Q_INVOKABLE void removeContact (ContactModel *contact); Q_INVOKABLE void removeContact (ContactModel *contact);
Q_INVOKABLE void cleanAvatars (); Q_INVOKABLE void cleanAvatars ();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment