mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-23 14:48:15 +00:00
feat(app): many changes:
- `ContactEdit` supports emails edition - Add a `SmartConnect` component
This commit is contained in:
parent
65dd1940c0
commit
42faa0a03b
12 changed files with 264 additions and 58 deletions
|
|
@ -142,6 +142,14 @@
|
|||
<source>avatarChooserTitle</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>companiesInput</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>companies</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Contacts</name>
|
||||
|
|
|
|||
|
|
@ -134,6 +134,14 @@
|
|||
<source>avatarChooserTitle</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>companiesInput</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>companies</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Contacts</name>
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@
|
|||
<file>ui/modules/Common/Popup/PopupShadow.qml</file>
|
||||
<file>ui/modules/Common/qmldir</file>
|
||||
<file>ui/modules/Common/SearchBox.qml</file>
|
||||
<file>ui/modules/Common/SmartConnect.qml</file>
|
||||
<file>ui/modules/Common/Styles/Animations/CaterpillarAnimationStyle.qml</file>
|
||||
<file>ui/modules/Common/Styles/CollapseStyle.qml</file>
|
||||
<file>ui/modules/Common/Styles/DialogStyle.qml</file>
|
||||
|
|
|
|||
|
|
@ -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<shared_ptr<belcard::BelCardPhoto> > photos =
|
||||
m_linphone_friend->getVcard()->getBelcard()->getPhotos();
|
||||
auto it = find_if(
|
||||
photos.begin(), photos.end(), [](const shared_ptr<belcard::BelCardPhoto> &photo) {
|
||||
photos.cbegin(), photos.cend(), [](const shared_ptr<belcard::BelCardPhoto> &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<linphone::Address> 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<shared_ptr<linphone::Address> > addresses = m_linphone_friend->getAddresses();
|
||||
string match = Utils::qStringToLinphoneString(sip_address);
|
||||
|
||||
auto it = find_if(
|
||||
addresses.cbegin(), addresses.cend(),
|
||||
[&match](const shared_ptr<linphone::Address> &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::BelCard> belCard = m_linphone_friend->getVcard()->getBelcard();
|
||||
shared_ptr<belcard::BelCardEmail> belCardEmail =
|
||||
belcard::BelCardGeneric::create<belcard::BelCardEmail>();
|
||||
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::BelCard> belCard = m_linphone_friend->getVcard()->getBelcard();
|
||||
list<shared_ptr<belcard::BelCardEmail> > emails = belCard->getEmails();
|
||||
string match = Utils::qStringToLinphoneString(email);
|
||||
|
||||
auto it = find_if(
|
||||
emails.cbegin(), emails.cend(),
|
||||
[&match](const shared_ptr<belcard::BelCardEmail> &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<QVariantMap> ContactModel::getAddresses () const {
|
||||
|
||||
}
|
||||
|
||||
void ContactModel::setAddresses (const QList<QVariantMap> &addresses) {
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
Presence::PresenceStatus ContactModel::getPresenceStatus () const {
|
||||
|
|
|
|||
|
|
@ -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<QVariantMap> addresses
|
||||
READ getAddresses
|
||||
WRITE setAddresses
|
||||
NOTIFY contactUpdated
|
||||
);
|
||||
|
||||
|
|
@ -84,6 +79,15 @@ class ContactModel : public QObject {
|
|||
public:
|
||||
ContactModel (std::shared_ptr<linphone::Friend> 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);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class ContactModel;
|
||||
class ContactsListModel;
|
||||
|
||||
// ===================================================================
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
tests/ui/modules/Common/SmartConnect.qml
Normal file
20
tests/ui/modules/Common/SmartConnect.qml
Normal file
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue