diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a6e7a44bf..4ff9ebcf7 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -46,6 +46,7 @@ foreach (package ${QT5_PACKAGES})
endforeach ()
list(APPEND LIBS "${CMAKE_SOURCE_DIR}/../OUTPUT/desktop/lib64/liblinphone++.so")
+list(APPEND LIBS "${CMAKE_SOURCE_DIR}/../OUTPUT/desktop/lib64/libbelcard.so")
set(SOURCES
src/app/App.cpp
diff --git a/tests/assets/images/contact_card_photo_hovered.svg b/tests/assets/images/contact_card_photo_hovered.svg
new file mode 100644
index 000000000..e7b9d282d
--- /dev/null
+++ b/tests/assets/images/contact_card_photo_hovered.svg
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/tests/assets/images/contact_card_photo_normal.svg b/tests/assets/images/contact_card_photo_normal.svg
new file mode 100644
index 000000000..b4e52a62f
--- /dev/null
+++ b/tests/assets/images/contact_card_photo_normal.svg
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/tests/assets/images/contact_card_photo_pressed.svg b/tests/assets/images/contact_card_photo_pressed.svg
new file mode 100644
index 000000000..cb5a9941a
--- /dev/null
+++ b/tests/assets/images/contact_card_photo_pressed.svg
@@ -0,0 +1,16 @@
+
+
diff --git a/tests/assets/languages/en.ts b/tests/assets/languages/en.ts
index 29797c752..e18fe2523 100644
--- a/tests/assets/languages/en.ts
+++ b/tests/assets/languages/en.ts
@@ -138,6 +138,10 @@
webSitesInput
URL
+
+ avatarChooserTitle
+
+
Contacts
diff --git a/tests/assets/languages/fr.ts b/tests/assets/languages/fr.ts
index 70069efa0..3291f13a3 100644
--- a/tests/assets/languages/fr.ts
+++ b/tests/assets/languages/fr.ts
@@ -130,6 +130,10 @@
webSitesInput
URL
+
+ avatarChooserTitle
+
+
Contacts
diff --git a/tests/resources.qrc b/tests/resources.qrc
index 34df0af51..906905702 100644
--- a/tests/resources.qrc
+++ b/tests/resources.qrc
@@ -36,6 +36,9 @@
assets/images/chevron_red.svg
assets/images/chevron_white.svg
assets/images/collapse.svg
+ assets/images/contact_card_photo_hovered.svg
+ assets/images/contact_card_photo_normal.svg
+ assets/images/contact_card_photo_pressed.svg
assets/images/contact_edit_hovered.svg
assets/images/contact_edit_normal.svg
assets/images/contact_edit_pressed.svg
diff --git a/tests/src/app/Database.cpp b/tests/src/app/Database.cpp
index cf1620738..b8cddd0c8 100644
--- a/tests/src/app/Database.cpp
+++ b/tests/src/app/Database.cpp
@@ -14,8 +14,9 @@
QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
#endif
-#define DATABASE_PATH_FRIENDS_LIST ".linphone-friends.db"
+#define DATABASE_PATH_AVATARS ".linphone/avatars/"
#define DATABASE_PATH_CALL_HISTORY_LIST ".linphone-call-history.db"
+#define DATABASE_PATH_FRIENDS_LIST ".linphone-friends.db"
#define DATABASE_PATH_MESSAGE_HISTORY_LIST ".linphone-history.db"
using namespace std;
@@ -33,6 +34,16 @@ inline bool ensureDatabaseFilePathExists (const QString &path) {
return file.exists() || file.open(QIODevice::ReadWrite);
}
+string Database::getAvatarsPath () {
+ QString path(DATABASES_PATH + "/" DATABASE_PATH_AVATARS);
+ QDir dir(path);
+
+ if (!dir.exists() && !dir.mkpath(path))
+ return "";
+
+ return Utils::qStringToLinphoneString(QDir::toNativeSeparators(path));
+}
+
inline string getDatabaseFilePath (const QString &filename) {
QString path(DATABASES_PATH + "/");
path += filename;
@@ -41,14 +52,14 @@ inline string getDatabaseFilePath (const QString &filename) {
: "";
}
-string Database::getFriendsListPath () {
- return getDatabaseFilePath(DATABASE_PATH_FRIENDS_LIST);
-}
-
string Database::getCallHistoryPath () {
return getDatabaseFilePath(DATABASE_PATH_CALL_HISTORY_LIST);
}
+string Database::getFriendsListPath () {
+ return getDatabaseFilePath(DATABASE_PATH_FRIENDS_LIST);
+}
+
string Database::getMessageHistoryPath () {
return getDatabaseFilePath(DATABASE_PATH_MESSAGE_HISTORY_LIST);
}
diff --git a/tests/src/app/Database.hpp b/tests/src/app/Database.hpp
index d1346b787..9369f5365 100644
--- a/tests/src/app/Database.hpp
+++ b/tests/src/app/Database.hpp
@@ -9,8 +9,10 @@ namespace Database {
// Returns the databases paths.
// If files cannot be created or are unavailable, a empty string is returned.
// Use the directories separator of used OS.
- std::string getFriendsListPath ();
+ std::string getAvatarsPath ();
+
std::string getCallHistoryPath ();
+ std::string getFriendsListPath ();
std::string getMessageHistoryPath ();
};
diff --git a/tests/src/components/contacts/ContactModel.cpp b/tests/src/components/contacts/ContactModel.cpp
index 44a5409b0..e821caf4e 100644
--- a/tests/src/components/contacts/ContactModel.cpp
+++ b/tests/src/components/contacts/ContactModel.cpp
@@ -1,9 +1,28 @@
+#include
+#include
+#include
+#include
+
+#include
+
+#include "../../app/Database.hpp"
#include "../../utils.hpp"
#include "ContactModel.hpp"
+using namespace std;
+
// ===================================================================
+inline shared_ptr getBelCard (
+ const shared_ptr &linphone_friend
+) {
+ shared_ptr vcard = linphone_friend->getVcard();
+ return *reinterpret_cast *>(vcard.get());
+}
+
+// -------------------------------------------------------------------
+
Presence::PresenceStatus ContactModel::getPresenceStatus () const {
return m_presence_status;
}
@@ -18,6 +37,43 @@ QString ContactModel::getUsername () const {
);
}
+bool ContactModel::setAvatar (const QString &path) {
+ // Try to copy photo in avatars folder.
+ QFile file(path);
+
+ if (!file.exists() || QImageReader::imageFormat(path).size() == 0)
+ return false;
+
+ QFileInfo info(file);
+ QString file_id = QUuid::createUuid().toString() + "." + info.suffix();
+ QString dest = Utils::linphoneStringToQString(Database::getAvatarsPath()) +
+ file_id;
+
+ if (!file.copy(dest))
+ return false;
+
+ qInfo() << QStringLiteral("Update avatar of `%1`. (path=%2)")
+ .arg(getUsername()).arg(dest);
+
+ // Remove oldest photos.
+ shared_ptr belCard = getBelCard(m_linphone_friend);
+
+ for (const auto &photo : belCard->getPhotos()) {
+ qDebug() << Utils::linphoneStringToQString(photo->getValue());
+ belCard->removePhoto(photo);
+ }
+
+ // Update.
+ shared_ptr photo =
+ belcard::BelCardGeneric::create();
+ photo->setValue(Utils::qStringToLinphoneString(file_id));
+ belCard->addPhoto(photo);
+
+
+ emit contactUpdated();
+ return true;
+}
+
QString ContactModel::getSipAddress () const {
return Utils::linphoneStringToQString(
m_linphone_friend->getAddress()->asString()
diff --git a/tests/src/components/contacts/ContactModel.hpp b/tests/src/components/contacts/ContactModel.hpp
index 21eb561bb..588ac2823 100644
--- a/tests/src/components/contacts/ContactModel.hpp
+++ b/tests/src/components/contacts/ContactModel.hpp
@@ -23,19 +23,20 @@ class ContactModel : public QObject {
Q_PROPERTY(
QString avatar
READ getAvatar
+ WRITE setAvatar
NOTIFY contactUpdated
);
Q_PROPERTY(
Presence::PresenceStatus presenceStatus
READ getPresenceStatus
- CONSTANT
+ NOTIFY contactUpdated
);
Q_PROPERTY(
Presence::PresenceLevel presenceLevel
READ getPresenceLevel
- CONSTANT
+ NOTIFY contactUpdated
);
Q_PROPERTY(
@@ -60,6 +61,8 @@ private:
return "";
}
+ bool setAvatar (const QString &path);
+
Presence::PresenceStatus getPresenceStatus () const;
Presence::PresenceLevel getPresenceLevel () const;
diff --git a/tests/ui/modules/Common/Styles/ForceScrollBarStyle.qml b/tests/ui/modules/Common/Styles/ForceScrollBarStyle.qml
index f9d3d32d1..e765eefa2 100644
--- a/tests/ui/modules/Common/Styles/ForceScrollBarStyle.qml
+++ b/tests/ui/modules/Common/Styles/ForceScrollBarStyle.qml
@@ -9,7 +9,7 @@ QtObject {
property color backgroundColor: Colors.g20
property QtObject contentItem: QtObject {
- property int implicitHeight: 100
+ property int implicitHeight: 8
property int implicitWidth: 8
property int radius: 10
}
diff --git a/tests/ui/modules/Linphone/Contact/Avatar.qml b/tests/ui/modules/Linphone/Contact/Avatar.qml
index edc42701c..3b286af1c 100644
--- a/tests/ui/modules/Linphone/Contact/Avatar.qml
+++ b/tests/ui/modules/Linphone/Contact/Avatar.qml
@@ -20,6 +20,10 @@ Item {
// -----------------------------------------------------------------
+ function isLoaded () {
+ return roundedImage.status === Image.Ready
+ }
+
function _computeInitials () {
var result = username.match(_initialsRegex)
diff --git a/tests/ui/scripts/Utils/utils.js b/tests/ui/scripts/Utils/utils.js
index ae311bad1..b8e35f26a 100644
--- a/tests/ui/scripts/Utils/utils.js
+++ b/tests/ui/scripts/Utils/utils.js
@@ -388,6 +388,12 @@ function isInteger (integer) {
// -------------------------------------------------------------------
+function isObject (object) {
+ return object !== null && typeof object === 'object'
+}
+
+// -------------------------------------------------------------------
+
function isString (string) {
return typeof string === 'string' || string instanceof String
}
diff --git a/tests/ui/views/App/MainWindow/ContactEdit.qml b/tests/ui/views/App/MainWindow/ContactEdit.qml
index c512a1614..3ebdb9d2b 100644
--- a/tests/ui/views/App/MainWindow/ContactEdit.qml
+++ b/tests/ui/views/App/MainWindow/ContactEdit.qml
@@ -1,5 +1,6 @@
import QtQuick 2.7
import QtQuick.Controls 2.0
+import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.3
import Common 1.0
@@ -20,10 +21,12 @@ ColumnLayout {
sipAddress
) || sipAddress
+ property var _info: {}
+
// -----------------------------------------------------------------
function _removeContact () {
- Utils.openConfirmDialog(this, {
+ Utils.openConfirmDialog(window, {
descriptionText: qsTr('removeContactDescription'),
exitHandler: function (status) {
if (status) {
@@ -35,10 +38,31 @@ ColumnLayout {
})
}
+ function _setAvatar (path) {
+ if (!path) {
+ return
+ }
+
+ if (Utils.isObject(_contact)) {
+ _contact.avatar = path.match(/^(?:file:\/\/)?(.*)$/)[1]
+ }
+
+ // TODO: Not registered contact.
+ }
+
// -----------------------------------------------------------------
spacing: 0
+ FileDialog {
+ id: avatarChooser
+
+ folder: shortcuts.home
+ title: qsTr('avatarChooserTitle')
+
+ onAccepted: _setAvatar(fileUrls[0])
+ }
+
// -----------------------------------------------------------------
// Info bar.
// -----------------------------------------------------------------
@@ -64,6 +88,22 @@ ColumnLayout {
width: ContactEditStyle.infoBar.avatarSize
username: LinphoneUtils.getContactUsername(_contact)
+ visible: isLoaded()
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: avatarChooser.open()
+ }
+ }
+
+ ActionButton {
+ Layout.preferredHeight: ContactEditStyle.infoBar.avatarSize
+ Layout.preferredWidth: ContactEditStyle.infoBar.avatarSize
+
+ icon: 'contact_card_photo'
+ visible: !avatar.isLoaded()
+
+ onClicked: avatarChooser.open()
}
Text {
@@ -83,6 +123,7 @@ ColumnLayout {
Layout.alignment: Qt.AlignRight
iconSize: ContactEditStyle.infoBar.buttons.size
spacing: ContactEditStyle.infoBar.buttons.spacing
+ visible: Utils.isObject(_contact)
ActionButton {
icon: 'history'
@@ -107,16 +148,17 @@ ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
ScrollBar.vertical: ForceScrollBar {}
+
boundsBehavior: Flickable.StopAtBounds
clip: true
- contentHeight: content.height
+ contentHeight: infoList.height
flickableDirection: Flickable.VerticalFlick
ColumnLayout {
anchors.left: parent.left
- anchors.margins: 20
+ anchors.margins: 40
anchors.right: parent.right
- id: content
+ id: infoList
ListForm {
title: qsTr('sipAccounts')