Commit edee0e0e authored by Simon Redman's avatar Simon Redman

[SMS App] Handle addresses for multitarget messages

## Summary

Upgrade the SMS App to handle multitarget addresses in the "addresses" field of a message and drop usage of the "address" field

Also note that this has all the commits from kde/kdeconnect-kde!97, but I will rebase those away once that patch is landed

Bonus: Image composition for multitarget conversations

## Test Plan
- Apply Android-side patch kde/kdeconnect-android!80
- Launch SMS App
- Notice that you can see all the recipients of multitarget messages. (Replying still not supported, but might get implemented as part of fixing replying to single-target messages)
parent ee9547ed
Pipeline #5518 passed with stage
in 10 minutes and 39 seconds
......@@ -20,29 +20,36 @@
#include "conversationmessage.h"
#include <QLoggingCategory>
#include <QVariantMap>
Q_LOGGING_CATEGORY(CONVERSATION_MESSAGE_LOGGING_CATEGORY, "kdeconnect.interfaces.conversationmessage")
ConversationMessage::ConversationMessage(const QVariantMap& args)
: m_eventField(args[QStringLiteral("event")].toInt()),
m_body(args[QStringLiteral("body")].toString()),
m_address(args[QStringLiteral("address")].toString()),
m_date(args[QStringLiteral("date")].toLongLong()),
m_type(args[QStringLiteral("type")].toInt()),
m_read(args[QStringLiteral("read")].toInt()),
m_threadID(args[QStringLiteral("thread_id")].toLongLong()),
m_uID(args[QStringLiteral("_id")].toInt())
{
QString test = QLatin1String(args[QStringLiteral("addresses")].typeName());
QVariantList jsonAddresses = args[QStringLiteral("addresses")].toList();
for (const QVariant& addressField : jsonAddresses) {
const auto& rawAddress = addressField.toMap();
m_addresses.append(ConversationAddress(rawAddress[QStringLiteral("address")].value<QString>()));
}
}
ConversationMessage::ConversationMessage (const qint32& eventField, const QString& body,
const QString& address, const qint64& date,
const QList<ConversationAddress>& addresses, const qint64& date,
const qint32& type, const qint32& read,
const qint64& threadID,
const qint32& uID)
: m_eventField(eventField)
, m_body(body)
, m_address(address)
, m_addresses(addresses)
, m_date(date)
, m_type(type)
, m_read(read)
......@@ -54,7 +61,7 @@ ConversationMessage::ConversationMessage (const qint32& eventField, const QStrin
ConversationMessage::ConversationMessage(const ConversationMessage& other)
: m_eventField(other.m_eventField)
, m_body(other.m_body)
, m_address(other.m_address)
, m_addresses(other.m_addresses)
, m_date(other.m_date)
, m_type(other.m_type)
, m_read(other.m_read)
......@@ -69,7 +76,7 @@ ConversationMessage& ConversationMessage::operator=(const ConversationMessage& o
{
this->m_eventField = other.m_eventField;
this->m_body = other.m_body;
this->m_address = other.m_address;
this->m_addresses = other.m_addresses;
this->m_date = other.m_date;
this->m_type = other.m_type;
this->m_read = other.m_read;
......@@ -78,12 +85,25 @@ ConversationMessage& ConversationMessage::operator=(const ConversationMessage& o
return *this;
}
ConversationMessage ConversationMessage::fromDBus(const QDBusVariant& var)
{
QDBusArgument data = var.variant().value<QDBusArgument>();
ConversationMessage message;
data >> message;
return message;
}
QVariantMap ConversationMessage::toVariant() const
{
QVariantList addresses;
for (const ConversationAddress& address : m_addresses) {
addresses.push_back(address.toVariant());
}
return {
{QStringLiteral("event"), m_eventField},
{QStringLiteral("body"), m_body},
{QStringLiteral("address"), m_address},
{QStringLiteral("addresses"), addresses},
{QStringLiteral("date"), m_date},
{QStringLiteral("type"), m_type},
{QStringLiteral("read"), m_read},
......@@ -92,50 +112,34 @@ QVariantMap ConversationMessage::toVariant() const
};
}
QDBusArgument &operator<<(QDBusArgument &argument, const ConversationMessage &message)
ConversationAddress::ConversationAddress(QString address)
: m_address(address)
{}
ConversationAddress::ConversationAddress(const ConversationAddress& other)
: m_address(other.address())
{}
ConversationAddress::~ConversationAddress()
{}
ConversationAddress& ConversationAddress::operator=(const ConversationAddress& other)
{
argument.beginStructure();
argument << message.eventField()
<< message.body()
<< message.address()
<< message.date()
<< message.type()
<< message.read()
<< message.threadID()
<< message.uID();
argument.endStructure();
return argument;
this->m_address = other.m_address;
return *this;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, ConversationMessage &message)
QVariantMap ConversationAddress::toVariant() const
{
qint32 event;
QString body;
QString address;
qint64 date;
qint32 type;
qint32 read;
qint64 threadID;
qint32 uID;
argument.beginStructure();
argument >> event;
argument >> body;
argument >> address;
argument >> date;
argument >> type;
argument >> read;
argument >> threadID;
argument >> uID;
argument.endStructure();
message = ConversationMessage(event, body, address, date, type, read, threadID, uID);
return argument;
return {
{QStringLiteral("address"), address()},
};
}
void ConversationMessage::registerDbusType()
{
qDBusRegisterMetaType<ConversationMessage>();
qRegisterMetaType<ConversationMessage>();
qDBusRegisterMetaType<ConversationAddress>();
qRegisterMetaType<ConversationAddress>();
}
......@@ -22,9 +22,14 @@
#define PLUGINS_TELEPHONY_CONVERSATIONMESSAGE_H_
#include <QDBusMetaType>
#include <QLoggingCategory>
#include "kdeconnectinterfaces_export.h"
Q_DECLARE_LOGGING_CATEGORY(CONVERSATION_MESSAGE_LOGGING_CATEGORY)
class ConversationAddress;
class KDECONNECTINTERFACES_EXPORT ConversationMessage
{
......@@ -57,18 +62,19 @@ public:
*/
ConversationMessage(const QVariantMap& args = QVariantMap());
ConversationMessage(const qint32& eventField, const QString& body, const QString& address,
ConversationMessage(const qint32& eventField, const QString& body, const QList<ConversationAddress>& addresses,
const qint64& date, const qint32& type, const qint32& read,
const qint64& threadID, const qint32& uID);
ConversationMessage(const ConversationMessage& other);
~ConversationMessage();
ConversationMessage& operator=(const ConversationMessage& other);
static ConversationMessage fromDBus(const QDBusVariant&);
static void registerDbusType();
qint32 eventField() const { return m_eventField; }
QString body() const { return m_body; }
QString address() const { return m_address; }
QList<ConversationAddress> addresses() const { return m_addresses; }
qint64 date() const { return m_date; }
qint32 type() const { return m_type; }
qint32 read() const { return m_read; }
......@@ -80,6 +86,15 @@ public:
bool containsTextBody() const { return (eventField() & ConversationMessage::EventTextMessage); }
bool isMultitarget() const { return (eventField() & ConversationMessage::EventMultiTarget); }
bool isIncoming() const { return type() == MessageTypeInbox; }
bool isOutgoing() const { return type() == MessageTypeSent; }
/**
* Return the address of the other party of a single-target conversation
* Calling this method with a multi-target conversation is ill-defined
*/
QString getOtherPartyAddress() const;
protected:
/**
* Bitwise OR of event flags
......@@ -93,9 +108,10 @@ protected:
QString m_body;
/**
* Remote-side address of the message. Most likely a phone number, but may be an email address
* List of all addresses involved in this conversation
* An address is most likely a phone number, but may be something else like an email address
*/
QString m_address;
QList<ConversationAddress> m_addresses;
/**
* Date stamp (Unix epoch millis) associated with the message
......@@ -123,6 +139,85 @@ protected:
qint32 m_uID;
};
class KDECONNECTINTERFACES_EXPORT ConversationAddress
{
public:
ConversationAddress(QString address = QStringLiteral());
ConversationAddress(const ConversationAddress& other);
~ConversationAddress();
ConversationAddress& operator=(const ConversationAddress& other);
QString address() const { return m_address; }
QVariantMap toVariant() const;
private:
QString m_address;
};
inline QDBusArgument &operator<<(QDBusArgument &argument, const ConversationMessage &message)
{
argument.beginStructure();
argument << message.eventField()
<< message.body()
<< message.addresses()
<< message.date()
<< message.type()
<< message.read()
<< message.threadID()
<< message.uID();
argument.endStructure();
return argument;
}
inline const QDBusArgument &operator>>(const QDBusArgument &argument, ConversationMessage &message)
{
qint32 event;
QString body;
QList<ConversationAddress> addresses;
qint64 date;
qint32 type;
qint32 read;
qint64 threadID;
qint32 uID;
argument.beginStructure();
argument >> event;
argument >> body;
argument >> addresses;
argument >> date;
argument >> type;
argument >> read;
argument >> threadID;
argument >> uID;
argument.endStructure();
message = ConversationMessage(event, body, addresses, date, type, read, threadID, uID);
return argument;
}
inline QDBusArgument& operator<<(QDBusArgument& argument, const ConversationAddress& address)
{
argument.beginStructure();
argument << address.address();
argument.endStructure();
return argument;
}
inline const QDBusArgument& operator>>(const QDBusArgument& argument, ConversationAddress& address)
{
QString addressField;
argument.beginStructure();
argument >> addressField;
argument.endStructure();
address = ConversationAddress(addressField);
return argument;
}
Q_DECLARE_METATYPE(ConversationMessage);
Q_DECLARE_METATYPE(ConversationAddress);
#endif /* PLUGINS_TELEPHONY_CONVERSATIONMESSAGE_H_ */
......@@ -82,7 +82,7 @@ QVariantList ConversationsDbusInterface::activeConversations()
<< "Conversation with ID" << it.key() << "is unexpectedly empty";
break;
}
const QVariantMap& message = (*conversation.crbegin()).toVariant();
const QVariant& message = QVariant::fromValue<ConversationMessage>(*conversation.crbegin());
toReturn.append(message);
}
......@@ -137,9 +137,9 @@ void ConversationsDbusInterface::addMessages(const QList<ConversationMessage> &m
// Tell the world about what just happened
if (newConversation) {
Q_EMIT conversationCreated(message.toVariant());
Q_EMIT conversationCreated(QDBusVariant(QVariant::fromValue(message)));
} else if (latestMessage) {
Q_EMIT conversationUpdated(message.toVariant());
Q_EMIT conversationUpdated(QDBusVariant(QVariant::fromValue(message)));
}
}
......@@ -187,12 +187,19 @@ void ConversationsDbusInterface::replyToConversation(const qint64& conversationI
qCWarning(KDECONNECT_CONVERSATIONS) << "Got a conversationID for a conversation with no messages!";
return;
}
// Caution:
// This method assumes that the address of any message (in this case, whichever one pops out
// with .first()) will be the same. This works fine for single-target SMS but might break down
// for group MMS, etc.
const QString& address = messagesList.first().address();
m_smsInterface.sendSms(address, message);
if (messagesList.first().isMultitarget()) {
qWarning(KDECONNECT_CONVERSATIONS) << "Tried to reply to a group MMS which is not supported in this version of KDE Connect";
return;
}
const QList<ConversationAddress>& addresses = messagesList.first().addresses();
if (addresses.size() > 1) {
// TODO: Upgrade for multitarget replies
qCWarning(KDECONNECT_CONVERSATIONS) << "Sending replies to multiple recipients is not supported";
return;
}
m_smsInterface.sendSms(addresses[0].address(), message);
}
void ConversationsDbusInterface::requestAllConversationThreads()
......
......@@ -97,7 +97,7 @@ Q_SIGNALS:
* Emitted whenever a conversation with no cached messages is added, either because the cache
* is being populated or because a new conversation has been created
*/
Q_SCRIPTABLE void conversationCreated(const QVariantMap& msg);
Q_SCRIPTABLE void conversationCreated(const QDBusVariant& msg);
/**
* Emitted whenever a conversation is being deleted
......@@ -108,7 +108,7 @@ Q_SIGNALS:
* Emitted whenever a message is added to a conversation and it is the newest message in the
* conversation
*/
Q_SCRIPTABLE void conversationUpdated(const QVariantMap& msg);
Q_SCRIPTABLE void conversationUpdated(const QDBusVariant& msg);
private /*methods*/:
QString newId(); //Generates successive identifitiers to use as public ids
......
......@@ -80,7 +80,7 @@ size_t RequestConversationWorker::replyForConversation(const QList<ConversationM
if (i >= howMany) {
break;
}
Q_EMIT conversationMessageRead(it->toVariant());
Q_EMIT conversationMessageRead(QDBusVariant(QVariant::fromValue(*it)));
i++;
}
......
......@@ -52,7 +52,7 @@ public Q_SLOTS:
void work();
Q_SIGNALS:
void conversationMessageRead(const QVariantMap& msg);
void conversationMessageRead(const QDBusVariant& msg);
void finished();
private:
......
......@@ -93,7 +93,7 @@ void SmsPlugin::forwardToTelepathy(const ConversationMessage& message)
connect(&m_telepathyInterface, SIGNAL(messageReceived(QString,QString)), SLOT(sendSms(QString,QString)), Qt::UniqueConnection);
const QString messageBody = message.body();
const QString contactName; // TODO: When telepathy support is improved, look up the contact with KPeople
const QString phoneNumber = message.address();
const QString phoneNumber = message.addresses()[0].address();
m_telepathyInterface.call(QDBus::NoBlock, QStringLiteral("sendMessage"), phoneNumber, contactName, messageBody);
}
......
......@@ -15,8 +15,11 @@ generate_export_header(kdeconnectsmshelper EXPORT_FILE_NAME ${CMAKE_CURRENT_BINA
target_include_directories(kdeconnectsmshelper PUBLIC ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(kdeconnectsmshelper
LINK_PUBLIC
PUBLIC
Qt5::Core
Qt5::DBus
KF5::People
kdeconnectinterfaces
)
# If ever this library is actually used by someone else, we should export these headers
......
......@@ -23,6 +23,7 @@
#include <QString>
#include <QLoggingCategory>
#include <QPainter>
#include <KLocalizedString>
......@@ -42,11 +43,11 @@ ConversationListModel::ConversationListModel(QObject* parent)
//qCDebug(KDECONNECT_SMS_CONVERSATIONS_LIST_MODEL) << "Constructing" << this;
auto roles = roleNames();
roles.insert(FromMeRole, "fromMe");
roles.insert(AddressRole, "address");
roles.insert(PersonUriRole, "personUri");
roles.insert(SenderRole, "sender");
roles.insert(DateRole, "date");
roles.insert(AddressesRole, "addresses");
roles.insert(ConversationIdRole, "conversationId");
roles.insert(MultitargetRole, "isMultitarget");
roles.insert(DateRole, "date");
setItemRoleNames(roles);
ConversationMessage::registerDbusType();
......@@ -69,8 +70,8 @@ void ConversationListModel::setDeviceId(const QString& deviceId)
qCDebug(KDECONNECT_SMS_CONVERSATIONS_LIST_MODEL) << "setDeviceId" << deviceId << "of" << this;
if (m_conversationsInterface) {
disconnect(m_conversationsInterface, SIGNAL(conversationCreated(QVariantMap)), this, SLOT(handleCreatedConversation(QVariantMap)));
disconnect(m_conversationsInterface, SIGNAL(conversationUpdated(QVariantMap)), this, SLOT(handleConversationUpdated(QVariantMap)));
disconnect(m_conversationsInterface, SIGNAL(conversationCreated(QDBusVariant)), this, SLOT(handleCreatedConversation(QDBusVariant)));
disconnect(m_conversationsInterface, SIGNAL(conversationUpdated(QDBusVariant)), this, SLOT(handleConversationUpdated(QDBusVariant)));
delete m_conversationsInterface;
m_conversationsInterface = nullptr;
}
......@@ -86,8 +87,8 @@ void ConversationListModel::setDeviceId(const QString& deviceId)
Q_EMIT deviceIdChanged();
m_conversationsInterface = new DeviceConversationsDbusInterface(deviceId, this);
connect(m_conversationsInterface, SIGNAL(conversationCreated(QVariantMap)), this, SLOT(handleCreatedConversation(QVariantMap)));
connect(m_conversationsInterface, SIGNAL(conversationUpdated(QVariantMap)), this, SLOT(handleConversationUpdated(QVariantMap)));
connect(m_conversationsInterface, SIGNAL(conversationCreated(QDBusVariant)), this, SLOT(handleCreatedConversation(QDBusVariant)));
connect(m_conversationsInterface, SIGNAL(conversationUpdated(QDBusVariant)), this, SLOT(handleConversationUpdated(QDBusVariant)));
prepareConversationsList();
m_conversationsInterface->requestAllConversationThreads();
......@@ -105,21 +106,23 @@ void ConversationListModel::prepareConversationsList()
clear(); // If we clear before we receive the reply, there might be a (several second) visual gap!
for (const QVariant& headMessage : convs) {
QDBusArgument data = headMessage.value<QDBusArgument>();
QVariantMap message;
ConversationMessage message;
data >> message;
handleCreatedConversation(message);
createRowFromMessage(message);
}
}, this);
}
void ConversationListModel::handleCreatedConversation(const QVariantMap& msg)
void ConversationListModel::handleCreatedConversation(const QDBusVariant& msg)
{
createRowFromMessage(msg);
ConversationMessage message = ConversationMessage::fromDBus(msg);
createRowFromMessage(message);
}
void ConversationListModel::handleConversationUpdated(const QVariantMap& msg)
void ConversationListModel::handleConversationUpdated(const QDBusVariant& msg)
{
createRowFromMessage(msg);
ConversationMessage message = ConversationMessage::fromDBus(msg);
createRowFromMessage(message);
}
void ConversationListModel::printDBusError(const QDBusError& error)
......@@ -137,9 +140,8 @@ QStandardItem * ConversationListModel::conversationForThreadId(qint32 threadId)
return nullptr;
}
void ConversationListModel::createRowFromMessage(const QVariantMap& msg)
void ConversationListModel::createRowFromMessage(const ConversationMessage& message)
{
const ConversationMessage message(msg);
if (message.type() == -1) {
// The Android side currently hacks in -1 if something weird comes up
// TODO: Remove this hack when MMS support is implemented
......@@ -151,26 +153,34 @@ void ConversationListModel::createRowFromMessage(const QVariantMap& msg)
if (!item) {
toadd = true;
item = new QStandardItem();
QScopedPointer<KPeople::PersonData> personData(lookupPersonByAddress(message.address()));
if (personData) {
item->setText(personData->name());
item->setIcon(QIcon(personData->photo()));
item->setData(personData->personUri(), PersonUriRole);
} else {
item->setData(QString(), PersonUriRole);
item->setText(message.address());
}
/** The address of everyone involved in this conversation, which we should not display (check if they are known contacts first) */
QList<ConversationAddress> rawAddresses = message.addresses();
QString displayNames = SmsHelper::getTitleForAddresses(rawAddresses);
QIcon displayIcon = SmsHelper::getIconForAddresses(rawAddresses);
item->setText(displayNames);
item->setIcon(displayIcon);
item->setData(message.threadID(), ConversationIdRole);
item->setData(rawAddresses[0].address(), SenderRole);
}
// TODO: Upgrade to support other kinds of media
// Get the body that we should display
QString displayBody = message.containsTextBody() ? message.body() : i18n("(Unsupported Message Type)");
// TODO: Upgrade with multitarget support
if (message.isMultitarget()) {
item->setText(i18n("(Multitarget Message)"));
// Prepend the sender's name
if (message.isOutgoing()) {
displayBody = i18n("You: %1", displayBody);
} else {
// If the message is incoming, the sender is the first Address
QString senderAddress = item->data(SenderRole).toString();
QScopedPointer<KPeople::PersonData> sender(SmsHelper::lookupPersonByAddress(senderAddress));
QString senderName = sender == nullptr? senderAddress : SmsHelper::lookupPersonByAddress(senderAddress)->name();
displayBody = i18n("%1: %2", senderName, displayBody);
}
// Update the message if the data is newer
// This will be true if a conversation receives a new message, but false when the user
// does something to trigger past conversation history loading
......@@ -178,8 +188,8 @@ void ConversationListModel::createRowFromMessage(const QVariantMap& msg)
qint64 oldDate = item->data(DateRole).toLongLong(&oldDateExists);
if (!oldDateExists || message.date() >= oldDate) {
// If there was no old data or incoming data is newer, update the record
item->setData(message.address(), AddressRole);
item->setData(message.type() == ConversationMessage::MessageTypeSent, FromMeRole);
item->setData(QVariant::fromValue(message.addresses()), AddressesRole);
item->setData(message.isOutgoing(), FromMeRole);
item->setData(displayBody, Qt::ToolTipRole);
item->setData(message.date(), DateRole);
item->setData(message.isMultitarget(), MultitargetRole);
......@@ -188,37 +198,3 @@ void ConversationListModel::createRowFromMessage(const QVariantMap& msg)
if (toadd)
appendRow(item);
}
KPeople::PersonData* ConversationListModel::lookupPersonByAddress(const QString& address)
{
const QString& canonicalAddress = SmsHelper::canonicalizePhoneNumber(address);
int rowIndex = 0;
for (rowIndex = 0; rowIndex < m_people.rowCount(); rowIndex++) {
const QString& uri = m_people.get(rowIndex, KPeople::PersonsModel::PersonUriRole).toString();
KPeople::PersonData* person = new KPeople::PersonData(uri);
const QStringList& allEmails = person->allEmails();
for (const QString& email : allEmails) {
// Although we are nominally an SMS messaging app, it is possible to send messages to phone numbers using email -> sms bridges
if (address == email) {
return person;
}
}
// TODO: Either upgrade KPeople with an allPhoneNumbers method
const QVariantList allPhoneNumbers = person->contactCustomProperty(QStringLiteral("all-phoneNumber")).toList();
for (const QVariant& rawPhoneNumber : allPhoneNumbers) {
const QString& phoneNumber = SmsHelper::canonicalizePhoneNumber(rawPhoneNumber.toString());
bool matchingPhoneNumber = SmsHelper::isPhoneNumberMatchCanonicalized(canonicalAddress, phoneNumber);
if (matchingPhoneNumber) {
//qCDebug(KDECONNECT_SMS_CONVERSATIONS_LIST_MODEL) << "Matched" << address << "to" << person->name();
return person;
}
}
delete person;
}
return nullptr;
}
......@@ -25,8 +25,6 @@
#include <QStandardItemModel>
#include <QLoggingCategory>
#include <QQmlParserStatus>
#include <KPeople/kpeople/personsmodel.h>
#include <KPeople/kpeople/persondata.h>
#include "interfaces/conversationmessage.h"
#include "interfaces/dbusinterfaces.h"
......@@ -78,12 +76,14 @@ public:
~ConversationListModel();
enum Roles {
/* Roles which apply while working as a single message */
FromMeRole = Qt::UserRole,
PersonUriRole,
AddressRole,
ConversationIdRole,
DateRole,
MultitargetRole, // Indicate that this conversation is multitarget
SenderRole, // The sender of the message. Undefined if this is an outgoing message
DateRole, // The date of this message
/* Roles which apply while working as the head of a conversation */
AddressesRole, // The Addresses involved in the conversation
ConversationIdRole, // The ThreadID of the conversation
MultitargetRole, // Indicate that this conversation is multitarget
};
Q_ENUM(Roles)
......@@ -91,9 +91,9 @@ public:
void setDeviceId(const QString &/*deviceId*/);
public Q_SLOTS:
void handleCreatedConversation(const QVariantMap& msg);
void handleConversationUpdated(const QVariantMap& msg);
void createRowFromMessage(const QVariantMap& message);
void handleCreatedConversation(const QDBusVariant& msg);
void handleConversationUpdated(const QDBusVariant& msg);
void createRowFromMessage(const ConversationMessage& message);
void printDBusError(const QDBusError& error);
Q_SIGNALS:
......@@ -105,16 +105,10 @@ private:
*/
void prepareConversationsList();
/**
* Get the data for a particular person given their contact address
*/
KPeople::PersonData* lookupPersonByAddress(const QString& address);
QStandardItem* conversationForThreadId(qint32 threadId);
DeviceConversationsDbusInterface* m_conversationsInterface;
QString m_deviceId;
KPeople::PersonsModel m_people;
};
#endif // CONVERSATIONLISTMODEL_H
......@@ -25,6 +25,7 @@
#include <KLocalizedString>
#include "interfaces/conversationmessage.h"
#include "smshelper.h"
Q_LOGGING_CATEGORY(KDECONNECT_SMS_CONVERSATION_MODEL, "kdeconnect.sms.conversation")
......@@ -35,6 +36,8 @@ ConversationModel::ConversationModel(QObject* parent)
auto roles = roleNames();
roles.insert(FromMeRole, "fromMe");
roles.insert(DateRole, "date");
roles.insert(SenderRole, "sender");
roles.insert(AvatarRole, "avatar");
setItemRoleNames(roles);
}
......@@ -67,14 +70,14 @@ void ConversationModel::setDeviceId(const QString& deviceId)
qCDebug(KDECONNECT_SMS_CONVERSATION_MODEL) << "setDeviceId" << "of" << this;
if (m_conversationsInterface) {
disconnect(m_conversationsInterface, SIGNAL(conversationUpdated(QVariantMap)), this, SLOT(handleConversationUpdate(QVariantMap)));
disconnect(m_conversationsInterface, SIGNAL(conversationUpdated(QDBusVariant)), this, SLOT(handleConversationUpdate(QDBusVariant)));
delete m_conversationsInterface;
}
m_deviceId = deviceId;
m_conversationsInterface = new DeviceConversationsDbusInterface(deviceId, this);
connect(m_conversationsInterface, SIGNAL(conversationUpdated(QVariantMap)), this, SLOT(handleConversationUpdate(QVariantMap)));
connect(m_conversationsInterface, SIGNAL(conversationUpdated(QDBusVariant)), this, SLOT(handleConversationUpdate(QDBusVariant)));
}
void ConversationModel::sendReplyToConversation(const QString& message)
......@@ -92,10 +95,12 @@ void ConversationModel::requestMoreMessages(const quint32& howMany)
m_conversationsInterface->requestConversation(m_threadId, numMessages, numMessages + howMany);
}
void ConversationModel::createRowFromMessage(const QVariantMap& msg, int pos)
{
const ConversationMessage message(msg);
QString ConversationModel::getTitleForAddresses(const QList<ConversationAddress>& addresses) {
return SmsHelper::getTitleForAddresses(addresses);
}
void ConversationModel::createRowFromMessage(const ConversationMessage& message, int pos)
{
if (message.threadID() != m_threadId) {
// Because of the asynchronous nature of the current implementation of this model, if the
// user clicks quickly between threads or for some other reason a message comes when we're
......@@ -117,17 +122,21 @@ void ConversationModel::createRowFromMessage(const QVariantMap& msg, int pos)
// Get the body that we should display
QString displayBody = message.containsTextBody() ? message.body() : i18n("(Unsupported Message Type)");
ConversationAddress sender = message.addresses().first();
QString senderName = message.isMultitarget() ? SmsHelper::getTitleForAddresses({sender}) : QString();
auto item = new QStandardItem;
item->setText(displayBody);
item->setData(message.type() == ConversationMessage::MessageTypeSent, FromMeRole);