Commit 08fbc20c authored by Ronan's avatar Ronan
Browse files

feat(app): many changes:

- use vcard of Contact in qml
- remove `sipAddress` attribute of Contact
- refactoring...
parent eec251ea
belcard @ eaeab2d6
Subproject commit 633e151d8a1775e8b4f717158d12bc0c0957c4ed
Subproject commit eaeab2d665423e1fdbf2f59c2ae8da6c3c89c8fa
linphone @ e816a335
Subproject commit 7b70508d9591c794ec42a80438a11f067f665994
Subproject commit e816a335cd1693cdbbde27a69143e1570058ed5f
......@@ -65,12 +65,12 @@ QString VcardModel::getAvatar () const {
);
}
void VcardModel::setAvatar (const QString &path) {
bool VcardModel::setAvatar (const QString &path) {
// 1. Try to copy photo in avatars folder.
QFile file(path);
if (!file.exists() || QImageReader::imageFormat(path).size() == 0)
return;
return false;
QFileInfo info(file);
QString uuid = QUuid::createUuid().toString();
......@@ -81,7 +81,7 @@ void VcardModel::setAvatar (const QString &path) {
QString dest = ::Utils::linphoneStringToQString(Database::getAvatarsPath()) + file_id;
if (!file.copy(dest))
return;
return false;
qInfo() << QStringLiteral("Update avatar of `%1`. (path=%2)").arg(getUsername()).arg(dest);
......@@ -112,9 +112,12 @@ void VcardModel::setAvatar (const QString &path) {
shared_ptr<belcard::BelCardPhoto> photo =
belcard::BelCardGeneric::create<belcard::BelCardPhoto>();
photo->setValue(VCARD_SCHEME + ::Utils::qStringToLinphoneString(file_id));
belcard->addPhoto(photo);
if (!belcard->addPhoto(photo))
return false;
emit vcardUpdated();
return true;
}
// -----------------------------------------------------------------------------
......@@ -135,7 +138,7 @@ QVariantMap VcardModel::getAddress () const {
return map;
}
void VcardModel::setAddress (const QVariantMap &address) {
bool VcardModel::setAddress (const QVariantMap &address) {
shared_ptr<belcard::BelCard> belcard = m_vcard->getBelcard();
list<shared_ptr<belcard::BelCardAddress> > addresses = belcard->getAddresses();
......@@ -150,9 +153,11 @@ void VcardModel::setAddress (const QVariantMap &address) {
belcard_address->setPostalCode(::Utils::qStringToLinphoneString(address["postalCode"].toString()));
belcard_address->setCountry(::Utils::qStringToLinphoneString(address["country"].toString()));
belcard->addAddress(belcard_address);
if (!belcard->addAddress(belcard_address))
return false;
emit vcardUpdated();
return true;
}
QVariantList VcardModel::getSipAddresses () const {
......@@ -165,11 +170,19 @@ QVariantList VcardModel::getSipAddresses () const {
}
bool VcardModel::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 false;
}
qInfo() << QStringLiteral("Add new sip address: `%1`.").arg(sip_address);
m_vcard->addSipAddress(::Utils::qStringToLinphoneString(sip_address));
m_vcard->addSipAddress(address->asStringUriOnly());
emit vcardUpdated();
return true;
}
......@@ -227,10 +240,11 @@ bool VcardModel::addCompany (const QString &company) {
value->setValue(::Utils::qStringToLinphoneString(company));
qInfo() << QStringLiteral("Add new company: `%1`.").arg(company);
belcard->addRole(value);
emit vcardUpdated();
if (!belcard->addRole(value))
return false;
emit vcardUpdated();
return true;
}
......@@ -276,10 +290,11 @@ bool VcardModel::addEmail (const QString &email) {
value->setValue(::Utils::qStringToLinphoneString(email));
qInfo() << QStringLiteral("Add new email: `%1`.").arg(email);
belcard->addEmail(value);
emit vcardUpdated();
if (!belcard->addEmail(value))
return false;
emit vcardUpdated();
return true;
}
......@@ -324,10 +339,11 @@ bool VcardModel::addUrl (const QString &url) {
value->setValue(::Utils::qStringToLinphoneString(url));
qInfo() << QStringLiteral("Add new url: `%1`.").arg(url);
belcard->addURL(value);
emit vcardUpdated();
if (!belcard->addURL(value))
return false;
emit vcardUpdated();
return true;
}
......
......@@ -49,10 +49,10 @@ private:
void setUsername (const QString &username);
QString getAvatar () const;
void setAvatar (const QString &path);
bool setAvatar (const QString &path);
QVariantMap getAddress () const;
void setAddress (const QVariantMap &address);
bool setAddress (const QVariantMap &address);
QVariantList getSipAddresses () const;
QVariantList getCompanies () const;
......
import QtQuick 2.7
// ===================================================================
// =============================================================================
Item {
id: item
......@@ -58,6 +58,6 @@ Item {
samplerName: 'mask'
}
radius: parent.width / 2
radius: width / 2
}
}
......@@ -5,7 +5,7 @@ import Linphone 1.0
import Linphone.Styles 1.0
import Utils 1.0
// ===================================================================
// =============================================================================
Item {
id: avatar
......@@ -17,7 +17,7 @@ Item {
property var _initialsRegex: /^\s*([^\s\.]+)(?:[\s\.]+([^\s\.]+))?/
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
function isLoaded () {
return roundedImage.status === Image.Ready
......@@ -28,7 +28,7 @@ Item {
Utils.assert(
result != null,
'Unable to get initials of: \'' + username + '\''
'Unable to get initials of: `' + username + '`.'
)
return result[1].charAt(0).toUpperCase() + (
......@@ -38,7 +38,7 @@ Item {
)
}
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
RoundedImage {
id: roundedImage
......
......@@ -5,9 +5,8 @@ import Common 1.0
import Linphone 1.0
import LinphoneUtils 1.0
import Linphone.Styles 1.0
import Utils 1.0
// ===================================================================
// =============================================================================
Rectangle {
id: item
......@@ -15,12 +14,8 @@ Rectangle {
property alias actions: actionBar.data
property alias sipAddressColor: description.sipAddressColor
property alias usernameColor: description.usernameColor
// Can be a contact object or just a sip address.
property var contact
// Override contact.sipAddress if used.
property var sipAddress
property string sipAddress
property var _contact: ContactsListModel.mapSipAddressToContact(sipAddress)
color: 'transparent' // No color by default.
height: ContactStyle.height
......@@ -38,9 +33,9 @@ Rectangle {
Layout.preferredHeight: ContactStyle.contentHeight
Layout.preferredWidth: ContactStyle.contentHeight
image: contact.avatar
presenceLevel: contact.presenceLevel || Presence.White
username: LinphoneUtils.getContactUsername(contact)
image: _contact && _contact.vcard.avatar
presenceLevel: _contact ? contact.presenceLevel : Presence.White
username: LinphoneUtils.getContactUsername(_contact || sipAddress)
}
ContactDescription {
......@@ -48,9 +43,7 @@ Rectangle {
Layout.fillHeight: true
Layout.fillWidth: true
sipAddress: Utils.isString(contact)
? contact
: item.sipAddress || contact.sipAddress
sipAddress: item.sipAddress
username: avatar.username
}
......
......@@ -2,7 +2,7 @@ import QtQuick 2.7
import Linphone.Styles 1.0
// ===================================================================
// =============================================================================
Column {
property alias sipAddress: sipAddress.text
......@@ -11,7 +11,6 @@ Column {
property color usernameColor: ContactDescriptionStyle.username.color
property int horizontalTextAlignment
// Username.
Text {
id: username
......@@ -25,7 +24,6 @@ Column {
width: parent.width
}
// Sip address.
Text {
id: sipAddress
......
......@@ -7,7 +7,7 @@ SearchBox {
id: searchBox
delegate: Contact {
contact: $contact
// contact: $contact
width: parent.width
actions: [
......
......@@ -87,7 +87,6 @@ ColumnLayout {
? TimelineStyle.contact.backgroundColor.a
: TimelineStyle.contact.backgroundColor.b
)
contact: parent.contact
sipAddress: $timelineEntry.sipAddresses
sipAddressColor: view.currentIndex === index
? TimelineStyle.contact.sipAddress.color.selected
......@@ -100,7 +99,8 @@ ColumnLayout {
anchors.fill: parent
sourceComponent: TooltipArea {
text: $timelineEntry.timestamp.toLocaleString(
Qt.locale(App.locale()), Locale.ShortFormat
Qt.locale(App.locale()),
Locale.ShortFormat
)
}
}
......
......@@ -10,5 +10,5 @@
function getContactUsername (contact) {
return Utils.isString(contact)
? contact.substring(4, contact.indexOf('@')) // 4 = length("sip:")
: contact.username
: contact.vcard.username
}
// ===================================================================
// =============================================================================
// Library to deal with URI.
// ===================================================================
// =============================================================================
.pragma library
......@@ -10,7 +10,7 @@
// Not standard but helpful.
var SUPPORTS_URL = true
// Level 0. ----------------------------------------------------------
// Level 0. --------------------------------------------------------------------
var URI_PCT_ENCODED = '%[A-Fa-f\\d]{2}'
var URI_PORT = '\\d*'
......@@ -18,7 +18,7 @@ var URI_SCHEME = '[a-zA-Z][\\w+\-\.]*'
var URI_SUB_DELIMS = '[!$&\'()*+,;=]'
var URI_UNRESERVED = '[\\w\-\._~]'
// Level 1. ----------------------------------------------------------
// Level 1. --------------------------------------------------------------------
var URI_HOST = '(' +
'(' +
......@@ -42,7 +42,7 @@ var URI_USERINFO = '(?:' +
'|' + ':' +
')*'
// Level 2. ----------------------------------------------------------
// Level 2. --------------------------------------------------------------------
var URI_AUTHORITY = '(?:' + URI_USERINFO + '@' + ')?' +
URI_HOST +
......@@ -61,7 +61,7 @@ var URI_QUERY = '(?:' +
var URI_SEGMENT = URI_PCHAR + '*'
var URI_SEGMENT_NZ = URI_PCHAR + '+'
// Level 3. ----------------------------------------------------------
// Level 3. --------------------------------------------------------------------
var URI_PATH_ABEMPTY = '(?:' + '/' + URI_SEGMENT + ')*'
......@@ -71,7 +71,7 @@ var URI_PATH_ABSOLUTE = '/' +
var URI_PATH_ROOTLESS =
URI_SEGMENT_NZ + '(?:' + '/' + URI_SEGMENT + ')*'
// Level 4. ----------------------------------------------------------
// Level 4. --------------------------------------------------------------------
// `path-empty` not used.
var URI_HIER_PART = '(?:' +
......@@ -80,7 +80,7 @@ var URI_HIER_PART = '(?:' +
'|' + URI_PATH_ROOTLESS +
')'
// Level 5. ----------------------------------------------------------
// Level 5. --------------------------------------------------------------------
// Regex to match URI. It respects the RFC 3986.
// But many features are not supported like IP format.
......@@ -92,7 +92,7 @@ var URI = (SUPPORTS_URL
var URI_REGEX = new RegExp(URI, 'g')
// ===================================================================
// =============================================================================
/* TODO: Supports:
......
......@@ -110,7 +110,7 @@ Rectangle {
}
backgroundColor: StartingCallStyle.avatar.backgroundColor
image: _contact.avatar
image: _contact.vcard.avatar
username: contactDescription.username
height: _computeAvatarSize()
......
......@@ -7,7 +7,7 @@ import Utils 1.0
import App.Styles 1.0
// ===================================================================
// =============================================================================
ColumnLayout {
function _removeContact (contact) {
......@@ -24,9 +24,9 @@ ColumnLayout {
spacing: 0
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
// Search Bar & actions.
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
Rectangle {
Layout.fillWidth: true
......@@ -66,9 +66,9 @@ ColumnLayout {
}
}
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
// Contacts list.
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
Rectangle {
Layout.fillWidth: true
......@@ -89,7 +89,7 @@ ColumnLayout {
height: ContactsStyle.contact.height
width: parent.width
// -----------------------------------------------------------
// ---------------------------------------------------------------------
Rectangle {
id: contact
......@@ -97,7 +97,7 @@ ColumnLayout {
anchors.fill: parent
color: ContactsStyle.contact.backgroundColor.normal
// ---------------------------------------------------------
// -------------------------------------------------------------------
Component {
id: container1
......@@ -142,7 +142,7 @@ ColumnLayout {
ActionButton {
icon: 'chat'
onClicked: window.setView('Conversation', {
sipAddress: $contact.sipAddress
sipAddress: $contact.vcard.sipAddresses[0] // FIXME: Display menu if many addresses.
})
}
}
......@@ -160,7 +160,7 @@ ColumnLayout {
}
}
// ---------------------------------------------------------
// -------------------------------------------------------------------
Rectangle {
id: indicator
......@@ -185,15 +185,13 @@ ColumnLayout {
}
spacing: ContactsStyle.contact.spacing
// Avatar.
Avatar {
Layout.preferredHeight: ContactsStyle.contact.avatarSize
Layout.preferredWidth: ContactsStyle.contact.avatarSize
image: $contact.avatar
username: $contact.username
image: $contact.vcard.avatar
username: $contact.vcard.username
}
// Username.
Text {
Layout.preferredWidth: ContactsStyle.contact.username.width
color: ContactsStyle.contact.username.color
......@@ -204,7 +202,7 @@ ColumnLayout {
pointSize: ContactsStyle.contact.username.fontSize
}
text: $contact.username
text: $contact.vcard.username
MouseArea {
anchors.fill: parent
......@@ -214,7 +212,7 @@ ColumnLayout {
hoverEnabled: true
onClicked: window.setView('ContactEdit', {
sipAddress: $contact.sipAddress
sipAddress: $contact.vcard.sipAddresses[0] // FIXME: Display menu if many addresses.
})
}
}
......@@ -230,7 +228,7 @@ ColumnLayout {
}
}
// ---------------------------------------------------------
// -------------------------------------------------------------------
states: State {
when: mouseArea.containsMouse
......
......@@ -4,7 +4,7 @@ import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
// ===================================================================
// =============================================================================
ColumnLayout {
spacing: 0
......
......@@ -8,7 +8,7 @@ import Utils 1.0
import App.Styles 1.0
// ===================================================================
// =============================================================================
ApplicationWindow {
id: window
......@@ -17,9 +17,9 @@ ApplicationWindow {
contentLoader.setSource(view + '.qml', props || {})
}
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
// Window properties.
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
maximumHeight: MainWindowStyle.toolBar.height
minimumHeight: MainWindowStyle.toolBar.height
......@@ -30,9 +30,9 @@ ApplicationWindow {
onActiveFocusItemChanged: activeFocusItem == null &&
smartSearchBar.hideMenu()
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
// Toolbar properties.
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
header: ToolBar {
background: MainWindowStyle.toolBar.background
......@@ -94,9 +94,9 @@ ApplicationWindow {
}
}
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
// Content.
// -----------------------------------------------------------------
// ---------------------------------------------------------------------------
RowLayout {
anchors.fill: parent
......
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