diff --git a/tests/assets/languages/en.ts b/tests/assets/languages/en.ts
index c3ee54151..15241168c 100644
--- a/tests/assets/languages/en.ts
+++ b/tests/assets/languages/en.ts
@@ -142,6 +142,14 @@
avatarChooserTitle
+
+ companiesInput
+
+
+
+ companies
+
+
Contacts
diff --git a/tests/assets/languages/fr.ts b/tests/assets/languages/fr.ts
index c89e84a9f..b43aa3256 100644
--- a/tests/assets/languages/fr.ts
+++ b/tests/assets/languages/fr.ts
@@ -134,6 +134,14 @@
avatarChooserTitle
+
+ companiesInput
+
+
+
+ companies
+
+
Contacts
diff --git a/tests/resources.qrc b/tests/resources.qrc
index 7f5c34851..6fb7514eb 100644
--- a/tests/resources.qrc
+++ b/tests/resources.qrc
@@ -157,6 +157,7 @@
ui/modules/Common/Popup/PopupShadow.qml
ui/modules/Common/qmldir
ui/modules/Common/SearchBox.qml
+ ui/modules/Common/SmartConnect.qml
ui/modules/Common/Styles/Animations/CaterpillarAnimationStyle.qml
ui/modules/Common/Styles/CollapseStyle.qml
ui/modules/Common/Styles/DialogStyle.qml
diff --git a/tests/src/components/contacts/ContactModel.cpp b/tests/src/components/contacts/ContactModel.cpp
index aba2ba51b..50a73adea 100644
--- a/tests/src/components/contacts/ContactModel.cpp
+++ b/tests/src/components/contacts/ContactModel.cpp
@@ -8,6 +8,7 @@
#include "../../app/AvatarProvider.hpp"
#include "../../app/Database.hpp"
#include "../../utils.hpp"
+#include "../core/CoreManager.hpp"
#include "ContactModel.hpp"
@@ -34,8 +35,12 @@ void ContactModel::setUsername (const QString &username) {
if (username.length() == 0 || username == getUsername())
return;
+ m_linphone_friend->edit();
+
if (!m_linphone_friend->setName(Utils::qStringToLinphoneString(username)))
emit contactUpdated();
+
+ m_linphone_friend->done();
}
// -------------------------------------------------------------------
@@ -45,15 +50,16 @@ QString ContactModel::getAvatar () const {
list > photos =
m_linphone_friend->getVcard()->getBelcard()->getPhotos();
auto it = find_if(
- photos.begin(), photos.end(), [](const shared_ptr &photo) {
+ photos.cbegin(), photos.cend(), [](const shared_ptr &photo) {
return !photo->getValue().compare(0, sizeof(VCARD_SCHEME) - 1, VCARD_SCHEME);
}
);
- // Returns right path.
- if (it == photos.end())
+ // No path found.
+ if (it == photos.cend())
return "";
+ // Returns right path.
return QStringLiteral("image://%1/%2")
.arg(AvatarProvider::PROVIDER_ID)
.arg(Utils::linphoneStringToQString(
@@ -129,8 +135,65 @@ QVariantList ContactModel::getSipAddresses () const {
return list;
}
-void ContactModel::setSipAddresses (const QVariantList &sip_addresses) {
- // TODO.
+void ContactModel::addSipAddress (const QString &sip_address) {
+ shared_ptr address =
+ CoreManager::getInstance()->getCore()->createAddress(
+ Utils::qStringToLinphoneString(sip_address)
+ );
+
+ if (!address) {
+ qWarning() << QStringLiteral("Unable to add invalid sip address: `%1`.").arg(sip_address);
+ return;
+ }
+
+ qInfo() << QStringLiteral("Add new sip address: `%1`.").arg(sip_address);
+
+ m_linphone_friend->edit();
+ m_linphone_friend->addAddress(address);
+ m_linphone_friend->done();
+
+ emit contactUpdated();
+}
+
+bool ContactModel::removeSipAddress (const QString &sip_address) {
+ list > addresses = m_linphone_friend->getAddresses();
+ string match = Utils::qStringToLinphoneString(sip_address);
+
+ auto it = find_if(
+ addresses.cbegin(), addresses.cend(),
+ [&match](const shared_ptr &address) {
+ return match == address->asString();
+ }
+ );
+
+ if (it == addresses.cend()) {
+ qWarning() << QStringLiteral("Unable to found sip address: `%1`.")
+ .arg(sip_address);
+ return false;
+ }
+
+ if (addresses.size() == 1) {
+ qWarning() << QStringLiteral("Unable to remove the only existing sip address: `%1`.")
+ .arg(sip_address);
+ return false;
+ }
+
+ qInfo() << QStringLiteral("Remove sip address: `%1`.").arg(sip_address);
+
+ m_linphone_friend->edit();
+ m_linphone_friend->removeAddress(*it);
+ m_linphone_friend->done();
+
+ emit contactUpdated();
+
+ return true;
+}
+
+void ContactModel::updateSipAddress (const QString &old_sip_address, const QString &sip_address) {
+ if (old_sip_address == sip_address || !removeSipAddress(old_sip_address))
+ return;
+
+ addSipAddress(sip_address);
}
// -------------------------------------------------------------------
@@ -144,10 +207,6 @@ QVariantList ContactModel::getCompanies () const {
return list;
}
-void ContactModel::setCompanies (const QVariantList &companies) {
- // TODO.
-}
-
// -------------------------------------------------------------------
QVariantList ContactModel::getEmails () const {
@@ -159,8 +218,55 @@ QVariantList ContactModel::getEmails () const {
return list;
}
-void ContactModel::setEmails (const QVariantList &emails) {
- // TODO.
+void ContactModel::addEmail (const QString &email) {
+ shared_ptr belCard = m_linphone_friend->getVcard()->getBelcard();
+ shared_ptr belCardEmail =
+ belcard::BelCardGeneric::create();
+ belCardEmail->setValue(Utils::qStringToLinphoneString(email));
+
+ qInfo() << QStringLiteral("Add new email: `%1`.").arg(email);
+
+ m_linphone_friend->edit();
+ belCard->addEmail(belCardEmail);
+ m_linphone_friend->done();
+
+ emit contactUpdated();
+}
+
+bool ContactModel::removeEmail (const QString &email) {
+ shared_ptr belCard = m_linphone_friend->getVcard()->getBelcard();
+ list > emails = belCard->getEmails();
+ string match = Utils::qStringToLinphoneString(email);
+
+ auto it = find_if(
+ emails.cbegin(), emails.cend(),
+ [&match](const shared_ptr &email) {
+ return match == email->getValue();
+ }
+ );
+
+ if (it == emails.cend()) {
+ qWarning() << QStringLiteral("Unable to remove email: `%1`.")
+ .arg(email);
+ return false;
+ }
+
+ qInfo() << QStringLiteral("Remove email: `%1`.").arg(email);
+
+ m_linphone_friend->edit();
+ belCard->removeEmail(*it);
+ m_linphone_friend->done();
+
+ emit contactUpdated();
+
+ return true;
+}
+
+void ContactModel::updateEmail (const QString &old_email, const QString &email) {
+ if (old_email == email || !removeEmail(old_email))
+ return;
+
+ addEmail(email);
}
// -------------------------------------------------------------------
@@ -174,20 +280,12 @@ QVariantList ContactModel::getUrls () const {
return list;
}
-void ContactModel::setUrls (const QVariantList &urls) {
- // TODO.
-}
-
// -------------------------------------------------------------------
QList ContactModel::getAddresses () const {
}
-void ContactModel::setAddresses (const QList &addresses) {
-
-}
-
// -------------------------------------------------------------------
Presence::PresenceStatus ContactModel::getPresenceStatus () const {
diff --git a/tests/src/components/contacts/ContactModel.hpp b/tests/src/components/contacts/ContactModel.hpp
index 112c013f4..8a466bf73 100644
--- a/tests/src/components/contacts/ContactModel.hpp
+++ b/tests/src/components/contacts/ContactModel.hpp
@@ -31,35 +31,30 @@ class ContactModel : public QObject {
Q_PROPERTY(
QVariantList sipAddresses
READ getSipAddresses
- WRITE setSipAddresses
NOTIFY contactUpdated
);
Q_PROPERTY(
QVariantList companies
READ getCompanies
- WRITE setCompanies
NOTIFY contactUpdated
);
Q_PROPERTY(
QVariantList emails
READ getEmails
- WRITE setEmails
NOTIFY contactUpdated
);
Q_PROPERTY(
QVariantList urls
READ getUrls
- WRITE setUrls
NOTIFY contactUpdated
);
Q_PROPERTY(
QList addresses
READ getAddresses
- WRITE setAddresses
NOTIFY contactUpdated
);
@@ -84,6 +79,15 @@ class ContactModel : public QObject {
public:
ContactModel (std::shared_ptr linphone_friend);
+public slots:
+ void addSipAddress (const QString &sip_address);
+ bool removeSipAddress (const QString &sip_address);
+ void updateSipAddress (const QString &old_sip_address, const QString &sip_address);
+
+ void addEmail (const QString &email);
+ bool removeEmail (const QString &email);
+ void updateEmail (const QString &old_email, const QString &email);
+
signals:
void contactUpdated ();
@@ -95,13 +99,11 @@ private:
void setAvatar (const QString &path);
QVariantList getSipAddresses () const;
- void setSipAddresses (const QVariantList &sip_addresses);
QVariantList getCompanies () const;
void setCompanies (const QVariantList &companies);
QVariantList getEmails () const;
- void setEmails (const QVariantList &emails);
QVariantList getUrls () const;
void setUrls (const QVariantList &urls);
diff --git a/tests/src/components/contacts/ContactsListProxyModel.hpp b/tests/src/components/contacts/ContactsListProxyModel.hpp
index 77bf673e8..7832359f6 100644
--- a/tests/src/components/contacts/ContactsListProxyModel.hpp
+++ b/tests/src/components/contacts/ContactsListProxyModel.hpp
@@ -3,6 +3,7 @@
#include
+class ContactModel;
class ContactsListModel;
// ===================================================================
diff --git a/tests/ui/modules/Common/Form/ListForm.qml b/tests/ui/modules/Common/Form/ListForm.qml
index d0e9e2524..07f0248d8 100644
--- a/tests/ui/modules/Common/Form/ListForm.qml
+++ b/tests/ui/modules/Common/Form/ListForm.qml
@@ -14,8 +14,20 @@ RowLayout {
property alias title: text.text
property var defaultData: []
+ signal changed (int id, string default_value, string new_value)
+ signal removed (int id, string value)
+
// -----------------------------------------------------------------
+ function setData (data) {
+ var model = values.model
+
+ model.clear()
+ data.forEach(function (data) {
+ model.append({ $value: data })
+ })
+ }
+
function _addValue (value) {
values.model.append({ $value: value })
@@ -26,9 +38,15 @@ RowLayout {
function _handleEditionFinished (index, text) {
if (text.length === 0) {
+ var default_value = values.model.get(index).$value
values.model.remove(index)
+
+ if (default_value.length !== 0) {
+ listForm.removed(index, default_value)
+ }
} else {
- values.model.set(index, { $value: text })
+ var default_value = values.model.get(index).$value
+ listForm.changed(index, default_value, text)
}
addButton.enabled = true
@@ -148,9 +166,7 @@ RowLayout {
return
}
- defaultData.forEach(function (data) {
- model.append({ $value: data })
- })
+ setData(defaultData)
}
}
}
diff --git a/tests/ui/modules/Common/Form/TransparentTextInput.qml b/tests/ui/modules/Common/Form/TransparentTextInput.qml
index b207af6bc..c6aa53be3 100644
--- a/tests/ui/modules/Common/Form/TransparentTextInput.qml
+++ b/tests/ui/modules/Common/Form/TransparentTextInput.qml
@@ -4,7 +4,7 @@ import Common 1.0
import Common.Styles 1.0
// ===================================================================
-// A editable text that become the content of a box on focus.
+// A editable text that has a background color on focus.
// ===================================================================
Item {
@@ -35,6 +35,13 @@ Item {
var width = textInput.contentWidth + parent.padding * 2
return width < parent.width ? width : parent.width
}
+
+ InvertedMouseArea {
+ anchors.fill: parent
+ enabled: textInput.activeFocus
+
+ onPressed: textInput.focus = false
+ }
}
TextInput {
@@ -58,11 +65,5 @@ Item {
cursorPosition = 0
parent.editingFinished()
}
-
- InvertedMouseArea {
- anchors.fill: parent
- enabled: textInput.activeFocus
- onPressed: textInput.focus = false
- }
}
}
diff --git a/tests/ui/modules/Common/SmartConnect.qml b/tests/ui/modules/Common/SmartConnect.qml
new file mode 100644
index 000000000..bd9fa3a4e
--- /dev/null
+++ b/tests/ui/modules/Common/SmartConnect.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.7
+
+import Utils 1.0
+
+// ===================================================================
+
+Item {
+ property bool _connected: false
+
+ function connect (emitter, signalName, handler) {
+ Utils.assert(!_connected, 'Smart connect is already connected!')
+
+ emitter[signalName].connect(handler)
+ _connected = true
+
+ Component.onDestruction.connect(function () {
+ emitter[signalName].disconnect(handler)
+ })
+ }
+}
diff --git a/tests/ui/modules/Common/qmldir b/tests/ui/modules/Common/qmldir
index 3d6a22440..440a38cf3 100644
--- a/tests/ui/modules/Common/qmldir
+++ b/tests/ui/modules/Common/qmldir
@@ -68,6 +68,9 @@ PopupShadow 1.0 Popup/PopupShadow.qml
# SearchBox
SearchBox 1.0 SearchBox.qml
+# SmartConnect
+SmartConnect 1.0 SmartConnect.qml
+
# Tooltip
TooltipArea 1.0 Tooltip/TooltipArea.qml
diff --git a/tests/ui/views/App/MainWindow/ContactEdit.qml b/tests/ui/views/App/MainWindow/ContactEdit.qml
index 2a56c0e37..f762f25e2 100644
--- a/tests/ui/views/App/MainWindow/ContactEdit.qml
+++ b/tests/ui/views/App/MainWindow/ContactEdit.qml
@@ -17,9 +17,7 @@ ColumnLayout {
property string sipAddress: ''
- property var _contact: ContactsListModel.mapSipAddressToContact(
- sipAddress
- ) || sipAddress
+ property var _contact
// -----------------------------------------------------------------
@@ -37,21 +35,43 @@ ColumnLayout {
}
function _setAvatar (path) {
- if (!path) {
- return
- }
-
- if (Utils.isObject(_contact)) {
+ if (Utils.isObject(_contact) && path) {
_contact.avatar = path.match(/^(?:file:\/\/)?(.*)$/)[1]
}
+ }
- // TODO: Not registered contact.
+ function _setUsername (username) {
+ if (Utils.isObject(_contact)) {
+ _contact.username = username
+
+ // Update current text with new username.
+ usernameInput.text = _contact.username
+ }
}
// -----------------------------------------------------------------
spacing: 0
+ Component.onCompleted: {
+ var contact = ContactsListModel.mapSipAddressToContact(sipAddress)
+
+ if (contact) {
+ infoUpdater.connect(contact, 'onContactUpdated', function () {
+ addresses.setData(contact.sipAddresses)
+ companies.setData(contact.companies)
+ emails.setData(contact.emails)
+ urls.setData(contact.urls)
+ })
+
+ _contact = contact
+ } else {
+ _contact = sipAddress
+ }
+ }
+
+ // -----------------------------------------------------------------
+
FileDialog {
id: avatarChooser
@@ -89,15 +109,14 @@ ColumnLayout {
id: avatar
anchors.fill: parent
-
image: _contact.avatar
- username: LinphoneUtils.getContactUsername(_contact)
+ username: LinphoneUtils.getContactUsername(_contact) || 'John Doe'
visible: isLoaded() && !parent.hovered
}
}
TransparentTextInput {
- id: editUsername
+ id: usernameInput
Layout.fillWidth: true
Layout.preferredHeight: ContactEditStyle.infoBar.buttons.size
@@ -111,12 +130,7 @@ ColumnLayout {
text: avatar.username
- onEditingFinished: {
- _contact.username = text
-
- // Update current text with new username.
- text = _contact.username
- }
+ onEditingFinished: _setUsername(text)
}
ActionBar {
@@ -157,28 +171,56 @@ ColumnLayout {
contentWidth: width - ScrollBar.vertical.width - leftMargin - rightMargin
flickableDirection: Flickable.VerticalFlick
- leftMargin: 40
- rightMargin: 20
- topMargin: 40
+ leftMargin: ContactEditStyle.values.leftMargin
+ rightMargin: ContactEditStyle.values.rightMargin
+ topMargin: ContactEditStyle.values.topMargin
ColumnLayout {
id: infoList
width: flick.contentWidth
+ SmartConnect {
+ id: infoUpdater
+ }
+
ListForm {
+ id: addresses
+
defaultData: _contact.sipAddresses
placeholder: qsTr('sipAccountsInput')
title: qsTr('sipAccounts')
+
+ onChanged: default_value.length === 0
+ ? _contact.addSipAddress(new_value)
+ : _contact.updateSipAddress(default_value, new_value)
+ onRemoved: _contact.removeSipAddress(value)
}
ListForm {
+ id: companies
+
+ defaultData: _contact.companies
+ placeholder: qsTr('companiesInput')
+ title: qsTr('companies')
+ }
+
+ ListForm {
+ id: emails
+
defaultData: _contact.emails
placeholder: qsTr('emailsInput')
title: qsTr('emails')
+
+ onChanged: default_value.length === 0
+ ? _contact.addEmail(new_value)
+ : _contact.updateEmail(default_value, new_value)
+ onRemoved: _contact.removeEmail(value)
}
ListForm {
+ id: urls
+
defaultData: _contact.urls
placeholder: qsTr('webSitesInput')
title: qsTr('webSites')
diff --git a/tests/ui/views/App/Styles/MainWindow/ContactEditStyle.qml b/tests/ui/views/App/Styles/MainWindow/ContactEditStyle.qml
index 3c80d9eea..1f2ce88cc 100644
--- a/tests/ui/views/App/Styles/MainWindow/ContactEditStyle.qml
+++ b/tests/ui/views/App/Styles/MainWindow/ContactEditStyle.qml
@@ -24,4 +24,10 @@ QtObject {
property int fontSize: 13
}
}
+
+ property QtObject values: QtObject {
+ property int leftMargin: 40
+ property int rightMargin: 20
+ property int topMargin: 40
+ }
}