Commit 2e7c10d4 authored by Ronan Abhamon's avatar Ronan Abhamon

feat(app): supports correctly presence for addresses and reworking

parent 4b7f6526
......@@ -90,7 +90,6 @@ set(SOURCES
src/components/calls/CallsListModel.cpp
src/components/chat/ChatModel.cpp
src/components/chat/ChatProxyModel.cpp
src/components/contact/ContactObserver.cpp
src/components/contact/ContactModel.cpp
src/components/contact/VcardModel.cpp
src/components/contacts/ContactsListModel.cpp
......@@ -98,11 +97,12 @@ set(SOURCES
src/components/core/CoreHandlers.cpp
src/components/core/CoreManager.cpp
src/components/notifier/Notifier.cpp
src/components/presence/OwnPresenceModel.cpp
src/components/presence/Presence.cpp
src/components/presence/PresenceStatusModel.cpp
src/components/settings/AccountSettingsModel.cpp
src/components/settings/SettingsModel.cpp
src/components/sip-addresses/SipAddressesModel.cpp
src/components/sip-addresses/SipAddressObserver.cpp
src/components/smart-search-bar/SmartSearchBarModel.cpp
src/components/timeline/TimelineModel.cpp
src/externals/single-application/SingleApplication.cpp
......@@ -124,7 +124,6 @@ set(HEADERS
src/components/calls/CallsListModel.hpp
src/components/chat/ChatModel.hpp
src/components/chat/ChatProxyModel.hpp
src/components/contact/ContactObserver.hpp
src/components/contact/ContactModel.hpp
src/components/contact/VcardModel.hpp
src/components/contacts/ContactsListModel.hpp
......@@ -132,11 +131,12 @@ set(HEADERS
src/components/core/CoreHandlers.hpp
src/components/core/CoreManager.hpp
src/components/notifier/Notifier.hpp
src/components/presence/OwnPresenceModel.hpp
src/components/presence/Presence.hpp
src/components/presence/PresenceStatusModel.hpp
src/components/settings/AccountSettingsModel.hpp
src/components/settings/SettingsModel.hpp
src/components/sip-addresses/SipAddressesModel.hpp
src/components/sip-addresses/SipAddressObserver.hpp
src/components/smart-search-bar/SmartSearchBarModel.hpp
src/components/timeline/TimelineModel.hpp
src/externals/single-application/SingleApplication.hpp
......
......@@ -25,7 +25,7 @@
#include "../components/chat/ChatProxyModel.hpp"
#include "../components/contacts/ContactsListProxyModel.hpp"
#include "../components/core/CoreManager.hpp"
#include "../components/presence/PresenceStatusModel.hpp"
#include "../components/presence/OwnPresenceModel.hpp"
#include "../components/settings/AccountSettingsModel.hpp"
#include "../components/smart-search-bar/SmartSearchBarModel.hpp"
#include "../components/timeline/TimelineModel.hpp"
......@@ -279,16 +279,16 @@ void App::registerTypes () {
qmlRegisterUncreatableType<ContactModel>(
"Linphone", 1, 0, "ContactModel", "ContactModel is uncreatable."
);
qmlRegisterUncreatableType<ContactObserver>(
"Linphone", 1, 0, "ContactObserver", "ContactObserver is uncreatable."
qmlRegisterUncreatableType<SipAddressObserver>(
"Linphone", 1, 0, "SipAddressObserver", "SipAddressObserver is uncreatable."
);
qmlRegisterUncreatableType<VcardModel>(
"Linphone", 1, 0, "VcardModel", "VcardModel is uncreatable."
);
registerSingletonType<AccountSettingsModel>("AccountSettingsModel");
registerSingletonType<OwnPresenceModel>("OwnPresenceModel");
registerSingletonType<Presence>("Presence");
registerSingletonType<PresenceStatusModel>("PresenceStatusModel");
registerSingletonType<TimelineModel>("TimelineModel");
registerSharedSingletonType(App, "App", App::getInstance);
......
......@@ -23,6 +23,7 @@
#include <QtDebug>
#include "../../app/App.hpp"
#include "../../utils.hpp"
#include "CoreManager.hpp"
#include "CoreHandlers.hpp"
......@@ -70,8 +71,15 @@ void CoreHandlers::onMessageReceived (
void CoreHandlers::onNotifyPresenceReceivedForUriOrTel (
const shared_ptr<linphone::Core> &,
const shared_ptr<linphone::Friend> &linphone_friend,
const string &,
const shared_ptr<const linphone::PresenceModel> &
const string &uri_or_tel,
const shared_ptr<const linphone::PresenceModel> &presence_model
) {
emit presenceReceived(::Utils::linphoneStringToQString(uri_or_tel), presence_model);
}
void CoreHandlers::onNotifyPresenceReceived (
const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphone_friend
) {
linphone_friend->getData<ContactModel>("contact-model").refreshPresence();
}
......
......@@ -36,6 +36,7 @@ class CoreHandlers :
signals:
void callStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::CallState state);
void messageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
void presenceReceived (const QString &sip_address, const std::shared_ptr<const linphone::PresenceModel> &presence_model);
private:
void onAuthenticationRequested (
......@@ -64,6 +65,11 @@ private:
const std::shared_ptr<const linphone::PresenceModel> &presence_model
) override;
void onNotifyPresenceReceived (
const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphone_friend
) override;
void onRegistrationStateChanged (
const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ProxyConfig> &config,
......
/*
* PresenceStatusModel.cpp
* OwnPresenceModel.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
......@@ -25,19 +25,19 @@
#include "../../utils.hpp"
#include "../core/CoreManager.hpp"
#include "PresenceStatusModel.hpp"
#include "OwnPresenceModel.hpp"
// =============================================================================
Presence::PresenceLevel PresenceStatusModel::getPresenceLevel () const {
Presence::PresenceLevel OwnPresenceModel::getPresenceLevel () const {
return Presence::getPresenceLevel(getPresenceStatus());
}
Presence::PresenceStatus PresenceStatusModel::getPresenceStatus () const {
Presence::PresenceStatus OwnPresenceModel::getPresenceStatus () const {
return static_cast<Presence::PresenceStatus>(CoreManager::getInstance()->getCore()->getConsolidatedPresence());
}
void PresenceStatusModel::setPresenceStatus (Presence::PresenceStatus status) {
void OwnPresenceModel::setPresenceStatus (Presence::PresenceStatus status) {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
core->setConsolidatedPresence(static_cast<linphone::ConsolidatedPresence>(status));
emit presenceStatusChanged(status);
......@@ -46,36 +46,25 @@ void PresenceStatusModel::setPresenceStatus (Presence::PresenceStatus status) {
// -----------------------------------------------------------------------------
QVariantList PresenceStatusModel::getStatuses () const {
QVariantList statuses;
inline void addBuildStatus (QVariantList &list, Presence::PresenceStatus status) {
Presence::PresenceLevel level = Presence::getPresenceLevel(status);
QVariantMap online_status;
online_status["presenceLevel"] = Presence::Green;
online_status["presenceStatus"] = Presence::Online;
online_status["presenceIcon"] = Presence::getPresenceLevelIconName(Presence::Green);
online_status["presenceLabel"] = Presence::getPresenceStatusAsString(Presence::Online);
statuses << online_status;
QVariantMap map;
map["presenceLevel"] = level;
map["presenceStatus"] = status;
map["presenceIcon"] = Presence::getPresenceLevelIconName(level);
map["presenceLabel"] = Presence::getPresenceStatusAsString(status);
QVariantMap busy_status;
busy_status["presenceLevel"] = Presence::Orange;
busy_status["presenceStatus"] = Presence::Busy;
busy_status["presenceIcon"] = Presence::getPresenceLevelIconName(Presence::Orange);
busy_status["presenceLabel"] = Presence::getPresenceStatusAsString(Presence::Busy);
statuses << busy_status;
list << map;
}
QVariantMap do_not_disturb_status;
do_not_disturb_status["presenceLevel"] = Presence::Red;
do_not_disturb_status["presenceStatus"] = Presence::DoNotDisturb;
do_not_disturb_status["presenceIcon"] = Presence::getPresenceLevelIconName(Presence::Red);
do_not_disturb_status["presenceLabel"] = Presence::getPresenceStatusAsString(Presence::DoNotDisturb);
statuses << do_not_disturb_status;
QVariantList OwnPresenceModel::getStatuses () const {
QVariantList statuses;
QVariantMap offline_status;
offline_status["presenceLevel"] = Presence::White;
offline_status["presenceStatus"] = Presence::Offline;
offline_status["presenceIcon"] = Presence::getPresenceLevelIconName(Presence::White);
offline_status["presenceLabel"] = Presence::getPresenceStatusAsString(Presence::Offline);
statuses << offline_status;
addBuildStatus(statuses, Presence::Online);
addBuildStatus(statuses, Presence::Busy);
addBuildStatus(statuses, Presence::DoNotDisturb);
addBuildStatus(statuses, Presence::Offline);
return statuses;
}
/*
* PresenceStatusModel.hpp
* OwnPresenceModel.hpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
......@@ -20,16 +20,19 @@
* Author: Ghislain MARY
*/
#ifndef PRESENCE_STATUS_MODEL_H_
#define PRESENCE_STATUS_MODEL_H_
#ifndef OWN_PRESENCE_MODEL_H_
#define OWN_PRESENCE_MODEL_H_
#include "../presence/Presence.hpp"
#include <QObject>
// =============================================================================
// Gives the statuses list informations (icons, label, level, status).
// Can set/get the presence status of the linphone user app.
// =============================================================================
class PresenceStatusModel : public QObject {
class OwnPresenceModel : public QObject {
Q_OBJECT;
Q_PROPERTY(QVariantList statuses READ getStatuses CONSTANT);
......@@ -38,11 +41,11 @@ class PresenceStatusModel : public QObject {
Q_PROPERTY(Presence::PresenceStatus presenceStatus READ getPresenceStatus WRITE setPresenceStatus NOTIFY presenceStatusChanged);
public:
PresenceStatusModel (QObject *parent = Q_NULLPTR) : QObject(parent) {}
OwnPresenceModel (QObject *parent = Q_NULLPTR) : QObject(parent) {}
signals:
void presenceLevelChanged(Presence::PresenceLevel level);
void presenceStatusChanged(Presence::PresenceStatus status);
void presenceLevelChanged (Presence::PresenceLevel level);
void presenceStatusChanged (Presence::PresenceStatus status);
private:
Presence::PresenceLevel getPresenceLevel () const;
......@@ -52,4 +55,4 @@ private:
QVariantList getStatuses () const;
};
#endif // PRESENCE_STATUS_MODEL_H_
#endif // OWN_PRESENCE_MODEL_H_
......@@ -26,6 +26,9 @@
#include <linphone++/linphone.hh>
#include <QObject>
// =============================================================================
// A helper to get the presence level of a presence status and to get a
// presence status as string.
// =============================================================================
class Presence : public QObject {
......@@ -54,7 +57,8 @@ public:
~Presence () = default;
static PresenceLevel getPresenceLevel (const PresenceStatus &status);
Q_INVOKABLE static PresenceLevel getPresenceLevel (const PresenceStatus &status);
Q_INVOKABLE static QString getPresenceStatusAsString (const PresenceStatus &status);
Q_INVOKABLE static QString getPresenceLevelIconName (const PresenceLevel &level);
};
......
/*
* ContactObserver.cpp
* SipAddressObserver.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
......@@ -16,21 +16,30 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: February 2, 2017
* Created on: March 28, 2017
* Author: Ronan Abhamon
*/
#include "../contact/ContactModel.hpp"
#include "ContactObserver.hpp"
#include "SipAddressObserver.hpp"
// =============================================================================
ContactObserver::ContactObserver (const QString &sip_address) {
SipAddressObserver::SipAddressObserver (const QString &sip_address) {
m_sip_address = sip_address;
}
void ContactObserver::setContact (ContactModel *contact) {
void SipAddressObserver::setContact (ContactModel *contact) {
if (contact == m_contact)
return;
m_contact = contact;
emit contactChanged(contact);
}
void SipAddressObserver::setPresenceStatus (const Presence::PresenceStatus &presence_status) {
if (presence_status == m_presence_status)
return;
m_presence_status = presence_status;
emit presenceStatusChanged(presence_status);
}
/*
* ContactObserver.hpp
* SipAddressObserver.hpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* This program is free software; you can redistribute it and/or
......@@ -16,49 +16,58 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: February 2, 2017
* Created on: March 28, 2017
* Author: Ronan Abhamon
*/
#ifndef CONTACT_OBSERVER_H_
#define CONTACT_OBSERVER_H_
#ifndef SIP_ADDRESS_OBSERVER_H_
#define SIP_ADDRESS_OBSERVER_H_
#include <QObject>
#include "../contact/ContactModel.hpp"
// =============================================================================
class ContactModel;
class ContactObserver : public QObject {
class SipAddressObserver : public QObject {
friend class SipAddressesModel;
Q_OBJECT;
Q_PROPERTY(QString sipAddress READ getSipAddress CONSTANT);
Q_PROPERTY(ContactModel * contact READ getContact NOTIFY contactChanged);
Q_PROPERTY(Presence::PresenceStatus presenceStatus READ getPresenceStatus NOTIFY presenceStatusChanged);
public:
ContactObserver (const QString &sip_address);
~ContactObserver () = default;
ContactModel *getContact () const {
return m_contact;
}
SipAddressObserver (const QString &sip_address);
~SipAddressObserver () = default;
signals:
void contactChanged (ContactModel *contact);
void presenceStatusChanged (const Presence::PresenceStatus &presenceStatus);
private:
QString getSipAddress () const {
return m_sip_address;
}
ContactModel *getContact () const {
return m_contact;
}
void setContact (ContactModel *contact);
Presence::PresenceStatus getPresenceStatus () const {
return m_presence_status;
}
void setPresenceStatus (const Presence::PresenceStatus &presence_status);
QString m_sip_address;
ContactModel *m_contact = nullptr;
Presence::PresenceStatus m_presence_status = Presence::PresenceStatus::Offline;
};
Q_DECLARE_METATYPE(ContactObserver *);
Q_DECLARE_METATYPE(SipAddressObserver *);
#endif // CONTACT_OBSERVER_H_
#endif // SIP_ADDRESS_OBSERVER_H_
......@@ -37,58 +37,19 @@ using namespace std;
SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(parent) {
initSipAddresses();
m_core_handlers = CoreManager::getInstance()->getHandlers();
ContactsListModel *contacts = CoreManager::getInstance()->getContactsListModel();
QObject::connect(contacts, &ContactsListModel::contactAdded, this, &SipAddressesModel::handleContactAdded);
QObject::connect(contacts, &ContactsListModel::contactRemoved, this, &SipAddressesModel::handleContactRemoved);
m_core_handlers = CoreManager::getInstance()->getHandlers();
QObject::connect(
&(*m_core_handlers), &CoreHandlers::messageReceived,
this, [this](const shared_ptr<linphone::ChatMessage> &message) {
const QString &sip_address = ::Utils::linphoneStringToQString(message->getFromAddress()->asStringUriOnly());
addOrUpdateSipAddress(sip_address, message);
}
);
QObject::connect(contacts, &ContactsListModel::sipAddressAdded, this, &SipAddressesModel::handleSipAddressAdded);
QObject::connect(contacts, &ContactsListModel::sipAddressRemoved, this, &SipAddressesModel::handleSipAddressRemoved);
QObject::connect(
contacts, &ContactsListModel::sipAddressAdded, this, [this](ContactModel *contact, const QString &sip_address) {
// TODO: Avoid the limitation of one contact by sip address.
ContactModel *mapped_contact = mapSipAddressToContact(sip_address);
if (mapped_contact) {
qWarning() << "Unable to map sip address" << sip_address << "to" << contact << "- already used by" << mapped_contact;
return;
}
addOrUpdateSipAddress(sip_address, contact);
}
);
QObject::connect(
contacts, &ContactsListModel::sipAddressRemoved, this, [this](ContactModel *contact, const QString &sip_address) {
ContactModel *mapped_contact = mapSipAddressToContact(sip_address);
if (contact != mapped_contact) {
qWarning() << "Unable to remove sip address" << sip_address << "of" << contact << "- already used by" << mapped_contact;
return;
}
removeContactOfSipAddress(sip_address);
}
);
QObject::connect(
&(*m_core_handlers), &CoreHandlers::callStateChanged,
this, [this](const std::shared_ptr<linphone::Call> &call, linphone::CallState state) {
// Ignore aborted calls.
if (call->getCallLog()->getStatus() == linphone::CallStatus::CallStatusAborted)
return;
if (state == linphone::CallStateEnd || state == linphone::CallStateError)
addOrUpdateSipAddress(
::Utils::linphoneStringToQString(call->getRemoteAddress()->asStringUriOnly()), call
);
}
);
QObject::connect(&(*m_core_handlers), &CoreHandlers::messageReceived, this, &SipAddressesModel::handleMessageReceived);
QObject::connect(&(*m_core_handlers), &CoreHandlers::callStateChanged, this, &SipAddressesModel::handleCallStateChanged);
QObject::connect(&(*m_core_handlers), &CoreHandlers::presenceReceived, this, &SipAddressesModel::handlePresenceReceived);
}
// -----------------------------------------------------------------------------
......@@ -180,13 +141,22 @@ ContactModel *SipAddressesModel::mapSipAddressToContact (const QString &sip_addr
// -----------------------------------------------------------------------------
ContactObserver *SipAddressesModel::getContactObserver (const QString &sip_address) {
ContactObserver *model = new ContactObserver(sip_address);
model->setContact(mapSipAddressToContact(sip_address));
SipAddressObserver *SipAddressesModel::getSipAddressObserver (const QString &sip_address) {
SipAddressObserver *model = new SipAddressObserver(sip_address);
{
auto it = m_sip_addresses.find(sip_address);
if (it != m_sip_addresses.end()) {
model->setContact(it->value("contact").value<ContactModel *>());
model->setPresenceStatus(
it->value("presenceStatus", Presence::PresenceStatus::Offline).value<Presence::PresenceStatus>()
);
}
}
m_observers.insert(sip_address, model);
QObject::connect(
model, &ContactObserver::destroyed, this, [this, model]() {
model, &SipAddressObserver::destroyed, this, [this, model]() {
const QString &sip_address = model->getSipAddress();
if (m_observers.remove(sip_address, model) == 0)
qWarning() << QStringLiteral("Unable to remove sip address `%1` from observers.").arg(sip_address);
......@@ -198,7 +168,7 @@ ContactObserver *SipAddressesModel::getContactObserver (const QString &sip_addre
// -----------------------------------------------------------------------------
QString SipAddressesModel::interpretUrl (const QString &sip_address) {
QString SipAddressesModel::interpretUrl (const QString &sip_address) const {
shared_ptr<linphone::Address> l_address = CoreManager::getInstance()->getCore()->interpretUrl(
::Utils::qStringToLinphoneString(sip_address)
);
......@@ -233,6 +203,8 @@ bool SipAddressesModel::removeRows (int row, int count, const QModelIndex &paren
return true;
}
// -----------------------------------------------------------------------------
void SipAddressesModel::handleContactAdded (ContactModel *contact) {
for (const auto &sip_address : contact->getVcardModel()->getSipAddresses())
addOrUpdateSipAddress(sip_address.toString(), contact);
......@@ -243,6 +215,79 @@ void SipAddressesModel::handleContactRemoved (const ContactModel *contact) {
removeContactOfSipAddress(sip_address.toString());
}
void SipAddressesModel::handleSipAddressAdded (ContactModel *contact, const QString &sip_address) {
ContactModel *mapped_contact = mapSipAddressToContact(sip_address);
if (mapped_contact) {
qWarning() << "Unable to map sip address" << sip_address << "to" << contact << "- already used by" << mapped_contact;
return;
}
addOrUpdateSipAddress(sip_address, contact);
}
void SipAddressesModel::handleSipAddressRemoved (ContactModel *contact, const QString &sip_address) {
ContactModel *mapped_contact = mapSipAddressToContact(sip_address);
if (contact != mapped_contact) {
qWarning() << "Unable to remove sip address" << sip_address << "of" << contact << "- already used by" << mapped_contact;
return;
}
removeContactOfSipAddress(sip_address);
}
void SipAddressesModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &message) {
const QString &sip_address = ::Utils::linphoneStringToQString(message->getFromAddress()->asStringUriOnly());
addOrUpdateSipAddress(sip_address, message);
}
void SipAddressesModel::handleCallStateChanged (
const shared_ptr<linphone::Call> &call,
linphone::CallState state
) {
// Ignore aborted calls.
if (call->getCallLog()->getStatus() == linphone::CallStatus::CallStatusAborted)
return;
if (state == linphone::CallStateEnd || state == linphone::CallStateError)
addOrUpdateSipAddress(
::Utils::linphoneStringToQString(call->getRemoteAddress()->asStringUriOnly()), call
);
}
void SipAddressesModel::handlePresenceReceived (
const QString &sip_address,
const shared_ptr<const linphone::PresenceModel> &presence_model
) {
Presence::PresenceStatus status;
switch (presence_model->getConsolidatedPresence()) {
case linphone::ConsolidatedPresenceOnline:
status = Presence::PresenceStatus::Online;
break;
case linphone::ConsolidatedPresenceBusy:
status = Presence::PresenceStatus::Busy;
break;
case linphone::ConsolidatedPresenceDoNotDisturb:
status = Presence::PresenceStatus::DoNotDisturb;
break;
case linphone::ConsolidatedPresenceOffline:
status = Presence::PresenceStatus::Offline;
break;
}
auto it = m_sip_addresses.find(sip_address);
if (it != m_sip_addresses.end()) {
qInfo() << QStringLiteral("Update presence of `%1`: %2.").arg(sip_address).arg(status);
(*it)["presenceStatus"] = status;
int row = m_refs.indexOf(&(*it));
Q_ASSERT(row != -1);
emit dataChanged(index(row, 0), index(row, 0));
}
updateObservers(sip_address, status);
}
// -----------------------------------------------------------------------------
void SipAddressesModel::addOrUpdateSipAddress (QVariantMap &map, ContactModel *contact) {
......@@ -374,8 +419,11 @@ void SipAddressesModel::initSipAddresses () {
}
void SipAddressesModel::updateObservers (const QString &sip_address, ContactModel *contact) {
for (auto &observer : m_observers.values(sip_address)) {
if (contact != observer->getContact())
observer->setContact(contact);
}
for (auto &observer : m_observers.values(sip_address))
observer->setContact(contact);
}
void SipAddressesModel::updateObservers (const QString &sip_address, const Presence::PresenceStatus &presence_status) {
for (auto &observer : m_observers.values(sip_address))
observer->setPresenceStatus(presence_status);
}
......@@ -25,7 +25,7 @@
#include "../chat/ChatModel.hpp"
#include "../contact/ContactModel.hpp"
#include "../contact/ContactObserver.hpp"
#include "SipAddressObserver.hpp"
#include <QAbstractListModel>
......@@ -48,17 +48,26 @@ public:
void connectToChatModel (ChatModel *chat_model);
Q_INVOKABLE ContactModel *mapSipAddressToContact (const QString &sip_address) const;
Q_INVOKABLE ContactObserver *getContactObserver (const QString &sip_address);
Q_INVOKABLE SipAddressObserver *getSipAddressObserver (const QString &sip_address);
Q_INVOKABLE QString interpretUrl (const QString &sip_address);
Q_INVOKABLE QString interpretUrl (const QString &sip_address) const;
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
// ---------------------------------------------------------------------------
void handleContactAdded (ContactModel *contact);
void handleContactRemoved (const ContactModel *contact);
void handleSipAddressAdded (ContactModel *contact, const QString &sip_address);
void handleSipAddressRemoved (ContactModel *contact, const QString &sip_address);
void handleMessageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
void handleCallStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::CallState state);
void handlePresenceReceived (const QString &sip_address, const shared_ptr<const linphone::PresenceModel> &presence_model);
// ---------------------------------------------------------------------------
// A sip address exists in this list if a contact is linked to it, or a call, or a message.
......@@ -77,11 +86,12 @@ private:
void initSipAddresses ();
void updateObservers (const QString &sip_address, ContactModel *contact);
void updateObservers (const QString &sip_address, const Presence::PresenceStatus &presence_status);
QHash<QString, QVariantMap> m_sip_addresses;
QList<const QVariantMap *> m_refs;
QMultiHash<QString, ContactObserver *> m_observers;
QMultiHash<QString, SipAddressObserver *> m_observers;
std::shared_ptr<CoreHandlers> m_core_handlers;
};
......
......@@ -11,8 +11,7 @@ Item {
// ---------------------------------------------------------------------------
property var account
property var presence
readonly property var _account: AccountSettingsModel
signal clicked
......@@ -31,7 +30,7 @@ Item {
Layout.bottomMargin: AccountStatusStyle.presenceLevel.bottomMargin
Layout.preferredHeight: AccountStatusStyle.presenceLevel.size
Layout.preferredWidth: AccountStatusStyle.presenceLevel.size
level: presence.presenceLevel
level: OwnPresenceModel.presenceLevel
}
Text {
......@@ -41,7 +40,7 @@ Item {
elide: Text.ElideRight
font.bold: true
font.pointSize: AccountStatusStyle.username.fontSize
text: account.username
text: accountStatus._account.username
verticalAlignment: Text.AlignBottom
}
}
......@@ -51,7 +50,7 @@ Item {
elide: Text.ElideRight
font.pointSize: AccountStatusStyle.sipAddress.fontSize
height: parent.height / 2
text: account.sipAddress
text: accountStatus._account.sipAddress
verticalAlignment: Text.AlignTop
width: parent.width
}
......
......@@ -21,7 +21,7 @@ Rectangle {
// ---------------------------------------------------------------------------
property var _contactObserver: SipAddressesModel.getContactObserver(sipAddress)
property var _sipAddressObserver: SipAddressesModel.getSipAddressObserver(sipAddress)
// ---------------------------------------------------------------------------
......@@ -57,7 +57,7 @@ Rectangle {
displayUnreadMessagesCount: true
entry: ({
contact: _contactObserver.contact,
contact: _sipAddressObserver.contact,
sipAddress: callControls.sipAddress
})
}
......
......@@ -32,7 +32,7 @@ Rectangle {
property bool bindToEnd: false
property bool tryToLoadMoreEntries: true
property var contactObserver: SipAddressesModel.getContactObserver(proxyModel.sipAddress)
property var sipAddressObserver: SipAddressesModel.getSipAddressObserver(proxyModel.sipAddress)
// -----------------------------------------------------------------------
......
......@@ -27,8 +27,8 @@ Row {
height: ChatStyle.entry.message.incoming.avatarSize
width: ChatStyle.entry.message.incoming.avatarSize
image: chat.contactObserver.contact ? chat.contactObserver.contact.avatar : ''
username: LinphoneUtils.getContactUsername(chat.contactObserver.contact || proxyModel.sipAddress)
image: chat.sipAddressObserver.contact ? chat.sipAddressObserver.contact.avatar : ''
username: LinphoneUtils.getContactUsername(chat.sipAddressObserver.contact || proxyModel.sipAddress)
}
}
......
......@@ -20,8 +20,8 @@ RowLayout {
Avatar {
anchors.centerIn: parent
height: ChatStyle.entry.message.incoming.avatarSize
image: chat.contactObserver.contact ? chat.contactObserver.contact.avatar : ''
username: LinphoneUtils.getContactUsername(chat.contactObserver.contact || proxyModel.sipAddress)
image: chat.sipAddressObserver.contact ? chat.sipAddressObserver.contact.avatar : ''
username: LinphoneUtils.getContactUsername(chat.sipAddressObserver.contact || proxyModel.sipAddress)
width: ChatStyle.entry.message.incoming.avatarSize
// The avatar is only visible for the first message of a incoming messages sequence.
......
......@@ -17,9 +17,10 @@ Rectangle {
property bool displayUnreadMessagesCount: false
// A entry from `SipAddressesModel`.
property var entry
property var _contact: entry.contact
readonly property var _contact: entry.contact
// ---------------------------------------------------------------------------
......@@ -39,8 +40,13 @@ Rectangle {
Layout.preferredHeight: ContactStyle.contentHeight
Layout.preferredWidth: ContactStyle.contentHeight
image: _contact && _contact.vcard.avatar
presenceLevel: _contact ? _contact.presenceLevel : -1
presenceLevel: entry.presenceStatus != null
? Presence.getPresenceLevel(entry.presenceStatus)
: -1
username: LinphoneUtils.getContactUsername(_contact || entry.sipAddress)
}
......@@ -58,7 +64,7 @@ Rectangle {
MessagesCounter {
Layout.alignment: Qt.AlignTop
count: entry.unreadMessagesCount || 0
count: Number(entry.unreadMessagesCount)
visible: displayUnreadMessagesCount && entry.unreadMessagesCount > 0
}
}
......
......@@ -13,8 +13,8 @@ Notification {
// ---------------------------------------------------------------------------
property var _call: notificationData && notificationData.call
property var _contact: _contactObserver.contact
property var _contactObserver: SipAddressesModel.getContactObserver(_call ? _call.sipAddress : '')
property var _contact: _sipAddressObserver.contact
property var _sipAddressObserver: SipAddressesModel.getSipAddressObserver(_call ? _call.sipAddress : '')
// ---------------------------------------------------------------------------
......@@ -51,7 +51,7 @@ Notification {
entry: ({
contact: notification._contact,
sipAddress: notification._contactObserver.sipAddress
sipAddress: notification._sipAddressObserver.sipAddress
})
}
......
......@@ -13,8 +13,8 @@ Notification {
// ---------------------------------------------------------------------------
property string _sipAddress: notificationData && notificationData.sipAddress || ''
property var _contact: _contactObserver.contact
property var _contactObserver: SipAddressesModel.getContactObserver(_sipAddress)
property var _contact: _sipAddressObserver.contact
property var _sipAddressObserver: SipAddressesModel.getSipAddressObserver(_sipAddress)
// ---------------------------------------------------------------------------
......
......@@ -7,12 +7,14 @@ import Linphone 1.0
// Wrapper to use `icon` property.
Item {
property int level: -1
property var level: null
Icon {
anchors.centerIn: parent
icon: Presence.getPresenceLevelIconName(level)
icon: (level !== -1 && level != null)
? Presence.getPresenceLevelIconName(level)
: ''
iconSize: parent.height > parent.width
? parent.width
: parent.height
......
......@@ -13,7 +13,7 @@ Rectangle {
property var call
default property alias _actionArea: actionArea.data
property var _contactObserver: SipAddressesModel.getContactObserver(sipAddress)
property var _sipAddressObserver: SipAddressesModel.getSipAddressObserver(sipAddress)
// ---------------------------------------------------------------------------
......@@ -41,7 +41,7 @@ Rectangle {
height: CallStyle.header.contactDescription.height
horizontalTextAlignment: Text.AlignHCenter
sipAddress: call.sipAddress
username: LinphoneUtils.getContactUsername(_contactObserver.contact || call.sipAddress)
username: LinphoneUtils.getContactUsername(_sipAddressObserver.contact || call.sipAddress)
width: parent.width
}
......@@ -81,7 +81,7 @@ Rectangle {
anchors.centerIn: parent
backgroundColor: CallStyle.container.avatar.backgroundColor
image: _contactObserver.contact && _contactObserver.contact.vcard.avatar
image: _sipAddressObserver.contact && _sipAddressObserver.contact.vcard.avatar
username: contactDescription.username
height: _computeAvatarSize()
......
......@@ -25,7 +25,7 @@ Rectangle {
property var call
property var _contactObserver: SipAddressesModel.getContactObserver(sipAddress)
property var _sipAddressObserver: SipAddressesModel.getSipAddressObserver(sipAddress)
property var _fullscreen: null
// ---------------------------------------------------------------------------
......@@ -85,8 +85,8 @@ Rectangle {
anchors.centerIn: parent
horizontalTextAlignment: Text.AlignHCenter
sipAddress: _contactObserver.sipAddress
username: LinphoneUtils.getContactUsername(_contactObserver.contact || sipAddress)
sipAddress: _sipAddressObserver.sipAddress
username: LinphoneUtils.getContactUsername(_sipAddressObserver.contact || sipAddress)
height: parent.height
width: parent.width - cameraActions.width - callQuality.width - CallStyle.header.contactDescription.width
......@@ -167,7 +167,7 @@ Rectangle {
foregroundColor: call.status === CallModel.CallStatusPaused
? CallStyle.container.pause.color
: 'transparent'
image: _contactObserver.contact && _contactObserver.contact.vcard.avatar
image: _sipAddressObserver.contact && _sipAddressObserver.contact.vcard.avatar
username: contactDescription.username
height: Logic.computeAvatarSize(CallStyle.container.avatar.maxSize)
......
......@@ -73,6 +73,7 @@ ColumnLayout {
anchors.fill: parent
image: _vcard.avatar
username: _vcard.username
presenceLevel: _contact ? _contact.presenceLevel : -1
visible: (isLoaded() && !parent.hovered) || !_edition
}
}
......
......@@ -2,6 +2,7 @@
// `Conversation.qml` Logic.
// =============================================================================
.import 'qrc:/ui/scripts/LinphoneUtils/linphone-utils.js' as LinphoneUtils
.import 'qrc:/ui/scripts/Utils/utils.js' as Utils
// =============================================================================
......@@ -15,3 +16,29 @@ function removeAllEntries () {
}
})
}
function getAvatar () {
var contact = conversation._sipAddressObserver.contact
return contact ? contact.vcard.avatar : ''
}
function getEditIcon () {
return conversation._sipAddressObserver.contact ? 'contact_edit' : 'contact_add'
}
function getUsername () {
return LinphoneUtils.getContactUsername(
conversation._sipAddressObserver.contact ||
conversation.sipAddress
)
}
function updateChatFilter (button) {
if (button === 0) {
chatProxyModel.setEntryTypeFilter(ChatModel.GenericEntry)
} else if (button === 1) {
chatProxyModel.setEntryTypeFilter(ChatModel.CallEntry)
} else {
chatProxyModel.setEntryTypeFilter(ChatModel.MessageEntry)
}
}
......@@ -3,7 +3,6 @@ import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import LinphoneUtils 1.0
import App.Styles 1.0
......@@ -16,7 +15,7 @@ ColumnLayout {
property string sipAddress
property var _contact: SipAddressesModel.mapSipAddressToContact(sipAddress)
readonly property var _sipAddressObserver: SipAddressesModel.getSipAddressObserver(sipAddress)
// ---------------------------------------------------------------------------
......@@ -29,6 +28,7 @@ ColumnLayout {
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: ConversationStyle.bar.height
color: ConversationStyle.bar.backgroundColor
RowLayout {
......@@ -44,14 +44,20 @@ ColumnLayout {
Layout.preferredHeight: ConversationStyle.bar.avatarSize
Layout.preferredWidth: ConversationStyle.bar.avatarSize
image: _contact ? _contact.vcard.avatar : ''
presenceLevel: _contact ? _contact.presenceLevel : -1
username: LinphoneUtils.getContactUsername(_contact || conversation.sipAddress)
image: Logic.getAvatar()
presenceLevel: Presence.getPresenceLevel(
conversation._sipAddressObserver.presenceStatus
)
username: Logic.getUsername()
}
ContactDescription {
Layout.fillHeight: true
Layout.fillWidth: true
sipAddress: conversation.sipAddress
sipAddressColor: ConversationStyle.bar.description.sipAddressColor
username: avatar.username
......@@ -60,6 +66,7 @@ ColumnLayout {
Row {
Layout.fillHeight: true
spacing: ConversationStyle.bar.actions.spacing
ActionBar {
......@@ -81,8 +88,8 @@ ColumnLayout {
anchors.verticalCenter: parent.verticalCenter
ActionButton {
icon: !_contact ? 'contact_add' : 'contact_edit'
iconSize: ConversationStyle.bar.actions.del.iconSize
icon: Logic.getEditIcon()
iconSize: ConversationStyle.bar.actions.edit.iconSize
onClicked: window.setView('ContactEdit', {
sipAddress: conversation.sipAddress
......@@ -107,6 +114,7 @@ ColumnLayout {
Borders {
Layout.fillWidth: true
Layout.preferredHeight: ConversationStyle.filters.height
borderColor: ConversationStyle.filters.border.color
bottomWidth: ConversationStyle.filters.border.bottomWidth
color: ConversationStyle.filters.backgroundColor
......@@ -118,21 +126,14 @@ ColumnLayout {
leftMargin: ConversationStyle.filters.leftMargin
verticalCenter: parent.verticalCenter
}
texts: [
qsTr('displayCallsAndMessages'),
qsTr('displayCalls'),
qsTr('displayMessages')
]
onClicked: {
if (button === 0) {
chatProxyModel.setEntryTypeFilter(ChatModel.GenericEntry)
} else if (button === 1) {
chatProxyModel.setEntryTypeFilter(ChatModel.CallEntry)
} else {
chatProxyModel.setEntryTypeFilter(ChatModel.MessageEntry)
}
}
onClicked: Logic.updateChatFilter(button)
}
}
......@@ -143,6 +144,7 @@ ColumnLayout {
Chat {
Layout.fillHeight: true
Layout.fillWidth: true
proxyModel: ChatProxyModel {
id: chatProxyModel
......
......@@ -119,9 +119,6 @@ ApplicationWindow {
Layout.fillHeight: parent.height
Layout.preferredWidth: MainWindowStyle.accountStatus.width
account: AccountSettingsModel
presence: PresenceStatusModel
TooltipArea {
text: AccountSettingsModel.sipAddress
}
......
......@@ -39,15 +39,15 @@ DialogPlus {
label: qsTr('selectPresenceLabel')
ComboBox {
currentIndex: Utils.findIndex(PresenceStatusModel.statuses, function (status) {
return status.presenceStatus == PresenceStatusModel.presenceStatus
currentIndex: Utils.findIndex(OwnPresenceModel.statuses, function (status) {
return status.presenceStatus == OwnPresenceModel.presenceStatus
})
model: PresenceStatusModel.statuses
model: OwnPresenceModel.statuses
iconRole: 'presenceIcon'
textRole: 'presenceLabel'
onActivated: PresenceStatusModel.presenceStatus = model[index].presenceStatus
onActivated: OwnPresenceModel.presenceStatus = model[index].presenceStatus
}
}
}
......
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