From 4b508d6344f76ce69055ee8eb79bf43cc89ad69c Mon Sep 17 00:00:00 2001 From: Javier Date: Sun, 29 Mar 2015 04:45:23 +0200 Subject: support recent comms and contacts --- rpm/saltoq.spec | 2 + rpm/saltoq.yaml | 2 + saltoqd/commmanager.cpp | 164 +++++++++++++++++++++++++++++++++++--------- saltoqd/commmanager.h | 5 +- saltoqd/contactsmanager.cpp | 111 ++++++++++++++++++++++++++++++ saltoqd/contactsmanager.h | 31 +++++++++ saltoqd/obexconnection.cpp | 11 +-- saltoqd/obexconnection.h | 1 - saltoqd/saltoqd.pro | 10 +-- saltoqd/storagemanager.cpp | 2 - saltoqd/toqmanager.cpp | 10 ++- saltoqd/toqmanager.h | 2 + 12 files changed, 299 insertions(+), 52 deletions(-) create mode 100644 saltoqd/contactsmanager.cpp create mode 100644 saltoqd/contactsmanager.h diff --git a/rpm/saltoq.spec b/rpm/saltoq.spec index db39c0c..d628acf 100644 --- a/rpm/saltoq.spec +++ b/rpm/saltoq.spec @@ -31,10 +31,12 @@ BuildRequires: pkgconfig(Qt5Qml) BuildRequires: pkgconfig(Qt5Quick) BuildRequires: pkgconfig(Qt5DBus) BuildRequires: pkgconfig(Qt5Bluetooth) >= 5.2 +BuildRequires: pkgconfig(Qt5Contacts) BuildRequires: pkgconfig(mlite5) BuildRequires: pkgconfig(libiphb) BuildRequires: pkgconfig(zlib) BuildRequires: pkgconfig(commhistory-qt5) +BuildRequires: pkgconfig(qtcontacts-sqlite-qt5-extensions) BuildRequires: pkgconfig(openobex) BuildRequires: qt5-qtconnectivity-qtbluetooth-devel diff --git a/rpm/saltoq.yaml b/rpm/saltoq.yaml index 8d90119..5626da9 100644 --- a/rpm/saltoq.yaml +++ b/rpm/saltoq.yaml @@ -19,10 +19,12 @@ PkgConfigBR: - Qt5Quick - Qt5DBus - Qt5Bluetooth >= 5.2 + - Qt5Contacts - mlite5 - libiphb - zlib - commhistory-qt5 + - qtcontacts-sqlite-qt5-extensions - openobex PkgBR: diff --git a/saltoqd/commmanager.cpp b/saltoqd/commmanager.cpp index dc17e7d..f54bb89 100644 --- a/saltoqd/commmanager.cpp +++ b/saltoqd/commmanager.cpp @@ -1,17 +1,19 @@ #include +#include +#include "contactsmanager.h" #include "commmanager.h" using namespace CommHistory; static const int RECORD_LIMIT = 20; +static const int PER_GROUP_LIMIT = 10; -CommManager::CommManager(StorageManager *storage, ToqManager *toq) : - QObject(toq), _toq(toq), _storage(storage), +CommManager::CommManager(StorageManager *storage, ContactsManager *contacts, ToqManager *toq) : + QObject(toq), _toq(toq), _contacts(contacts), _storage(storage), _calls(new CallModel(this)), _convs(new GroupModel(this)), _refreshTimer(new QTimer(this)) { - _calls->setTreeMode(false); _calls->setQueryMode(EventModel::AsyncQuery); _calls->setSorting(CallModel::SortByTime); _calls->setResolveContacts(true); @@ -21,7 +23,7 @@ CommManager::CommManager(StorageManager *storage, ToqManager *toq) : _convs->setLimit(RECORD_LIMIT); _refreshTimer->setSingleShot(true); - _refreshTimer->setInterval(1000); + _refreshTimer->setInterval(2000); connect(_calls, SIGNAL(modelReady(bool)), this, SLOT(scheduleRefresh())); @@ -34,6 +36,12 @@ CommManager::CommManager(StorageManager *storage, ToqManager *toq) : connect(_convs, SIGNAL(modelReady(bool)), this, SLOT(scheduleRefresh())); + connect(_convs, SIGNAL(modelReset()), + this, SLOT(scheduleRefresh())); + connect(_convs, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(scheduleRefresh())); + connect(_convs, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(scheduleRefresh())); connect(_refreshTimer, &QTimer::timeout, this, &CommManager::refresh); @@ -60,60 +68,150 @@ void CommManager::refresh() int rows = _calls->rowCount(); for (int i = 0; i < rows; i++) { - Event e = _calls->event(i); + QModelIndex index = _calls->index(i, 0); + Event e = _calls->event(index); + QList contacts = e.contacts(); + QString name; + if (!contacts.empty()) { + name = contacts.first().second; + } + if (name.isEmpty()) { + name = e.remoteUid(); + } + if (name.isEmpty()) { + name = tr("Private number"); + } QDateTime dt = e.startTime(); QJsonObject obj; - obj.insert("Name", e.contactName()); - obj.insert("ContactId", QJsonValue()); + obj.insert("Name", name); + obj.insert("ContactId", _contacts->getRecordIdForContact(e.contactId())); + QJsonArray records; - QJsonObject record; - record.insert("CommsType", QLatin1String("Call")); - record.insert("ReceivedTime", qint64(dt.toTime_t())); - record.insert("CallerId", e.contactName()); - record.insert("ItemId", e.id()); - QJsonObject details; - details.insert("Duration", e.startTime().secsTo(e.endTime())); - details.insert("PhoneType", QLatin1String("Other")); // TODO - switch (e.direction()) { - case Event::Inbound: - details.insert("Direction", QLatin1String("Incoming")); - break; - case Event::Outbound: - details.insert("Direction", QLatin1String("Outgoing")); - break; - default: - details.insert("Direction", QLatin1String("Unknown")); - break; + if (_calls->hasChildren(index)) { + const int subrows = _calls->rowCount(index); + for (int j = 0; j < subrows; j++) { + QModelIndex index2 = _calls->index(j, 0, index); + const Event e = _calls->event(index2); + QJsonObject record; + record.insert("CommsType", QLatin1String("Call")); + record.insert("ReceivedTime", qint64(e.startTime().toTime_t())); + record.insert("CallerId", e.remoteUid()); + record.insert("ItemId", e.id()); + QJsonObject details; + details.insert("Duration", e.startTime().secsTo(e.endTime())); + details.insert("PhoneType", QLatin1String("Other")); // TODO + switch (e.direction()) { + case Event::Inbound: + details.insert("Direction", QLatin1String("Incoming")); + break; + case Event::Outbound: + details.insert("Direction", QLatin1String("Outgoing")); + break; + default: + details.insert("Direction", QLatin1String("Unknown")); + break; + } + details.insert("IsMissedCall", e.isMissedCall()); + record.insert("CommsDetails", details); + records.append(record); + } } - details.insert("IsMissedCall", e.isMissedCall()); - record.insert("CommsDetails", details); - records.append(record); + obj.insert("CommsRecords", records); events.insert(dt, obj); } + QScopedPointer conv(new ConversationModel); + conv->setTreeMode(false); + conv->setLimit(PER_GROUP_LIMIT); + conv->setQueryMode(EventModel::SyncQuery); + rows = _convs->rowCount(); for (int i = 0; i < rows; i++) { Group g = _convs->group(_convs->index(i, 0)); - qDebug() << "Chat" << g.contactName(); + + QList contacts = g.contacts(); + QString name; + if (!contacts.empty()) { + name = contacts.first().second; + } + if (name.isEmpty() && !g.remoteUids().isEmpty()) { + name = g.remoteUids().first(); + } + if (name.isEmpty()) { + name = tr("Unknown contact"); + } + + QJsonObject obj; + obj.insert("Name", name); + obj.insert("ContactId", _contacts->getRecordIdForContact(g.contactId())); + + QJsonArray records; + + if (conv->getEvents(g.id())) { + const int subrows = conv->rowCount(); + for (int j = 0; j < subrows; j++) { + Event e = conv->event(j); + QJsonObject record; + record.insert("CommsType", QLatin1String("Text")); + record.insert("ReceivedTime", qint64(e.startTime().toTime_t())); + record.insert("CallerId", e.remoteUid()); + record.insert("ItemId", e.id()); + QJsonObject details; + details.insert("Message", e.freeText()); + details.insert("privileged", int(0)); // TODO + switch (e.direction()) { + case Event::Inbound: + details.insert("Direction", int(1)); + break; + case Event::Outbound: + details.insert("Direction", int(2)); + break; + default: + details.insert("Direction", int(0)); + break; + } + details.insert("IsRead", e.isRead()); + record.insert("CommsDetails", details); + records.append(record); + } + } else { + qWarning() << "Failed to get events for group id" << g.id(); + QJsonObject record; + record.insert("CommsType", QLatin1String("Text")); + record.insert("ReceivedTime", qint64(g.startTime().toTime_t())); + record.insert("CallerId", g.remoteUids().first()); + record.insert("ItemId", g.id()); + QJsonObject details; + details.insert("Message", g.lastMessageText()); + details.insert("privileged", int(0)); // TODO + details.insert("Direction", int(0)); + details.insert("IsRead", g.unreadMessages() == 0); + record.insert("CommsDetails", details); + records.append(record); + } + + obj.insert("CommsRecords", records); + + events.insert(g.endTime(), obj); } QJsonArray records; int i = 0; - auto it = events.begin(); - while (it != events.end()) { + auto it = events.end(); + while (it != events.begin()) { + --it; + QJsonObject record; record.insert("RecordId", i); record.insert("RecordPayload", it.value()); records.append(record); - ++it; if (++i >= RECORD_LIMIT) break; } - QString storeName("Phub.Phone.RecentComms"); QJsonObject store; store.insert("Name", storeName); diff --git a/saltoqd/commmanager.h b/saltoqd/commmanager.h index 05d2147..b4604bb 100644 --- a/saltoqd/commmanager.h +++ b/saltoqd/commmanager.h @@ -5,11 +5,13 @@ #include #include +class ContactsManager; + class CommManager : public QObject { Q_OBJECT public: - explicit CommManager(StorageManager *storage, ToqManager *toq); + explicit CommManager(StorageManager *storage, ContactsManager *contacts, ToqManager *toq); public slots: void scheduleRefresh(); @@ -21,6 +23,7 @@ private slots: private: ToqManager *_toq; + ContactsManager *_contacts; StorageManager *_storage; CommHistory::CallModel *_calls; diff --git a/saltoqd/contactsmanager.cpp b/saltoqd/contactsmanager.cpp new file mode 100644 index 0000000..2bc79d2 --- /dev/null +++ b/saltoqd/contactsmanager.cpp @@ -0,0 +1,111 @@ +#include "contactsmanager.h" +#include +#include + +QTCONTACTS_USE_NAMESPACE + +ContactsManager::ContactsManager(StorageManager *storage, ToqManager *toq) : + QObject(toq), _toq(toq), _storage(storage), + _contacts(new QContactManager(this)), + _refreshTimer(new QTimer(this)) +{ + connect(_contacts, &QContactManager::contactsAdded, + this, &ContactsManager::scheduleRefresh); + connect(_contacts, &QContactManager::dataChanged, + this, &ContactsManager::scheduleRefresh); + + connect(_refreshTimer, &QTimer::timeout, + this, &ContactsManager::refresh); + + _refreshTimer->setSingleShot(true); + _refreshTimer->setInterval(2000); + _refreshTimer->start(); +} + +qint64 ContactsManager::getRecordIdForContact(uint contactId) +{ + return contactId; +} + +void ContactsManager::scheduleRefresh() +{ + if (!_refreshTimer->isActive()) { + _refreshTimer->start(); + } +} + +void ContactsManager::refresh() +{ + qDebug() << "Refreshing contacts"; + + QContactSortOrder order; + order.setBlankPolicy(QContactSortOrder::BlanksLast); + order.setCaseSensitivity(Qt::CaseInsensitive); + order.setDetailType(QContactDetail::TypeDisplayLabel, QContactDisplayLabel::FieldLabel); + + QList contacts = _contacts->contacts(order); + + QJsonArray records; + for (const QContact &contact : contacts) { + QJsonObject payload; + QContactName cName = contact.detail(); + QContactDisplayLabel cDisplay = contact.detail(); + QContactFavorite cFav = contact.detail(); + QJsonObject name; + name.insert("Initial", cName.prefix()); + name.insert("First", cName.firstName()); + name.insert("Middle", cName.middleName()); + name.insert("Last", cName.lastName()); + name.insert("Display", cDisplay.label()); + QJsonArray phones; + for (const QContactPhoneNumber &cPhone : contact.details()) { + QJsonObject phone; + QString type; + if (!cPhone.subTypes().isEmpty()) { + if (cPhone.subTypes().first() == QContactPhoneNumber::SubTypeMobile) { + type = "Mobile"; + } + } + if (type.isEmpty() && !cPhone.contexts().isEmpty()) { + switch (cPhone.contexts().first()) { + case QContactDetail::ContextHome: + type = "Home"; + break; + case QContactDetail::ContextWork: + type = "Work"; + break; + default: + break; + } + } + if (type.isEmpty()) { + type = "Other"; + } + phone.insert("Type", type); + phone.insert("Number", cPhone.number()); + phones.append(phone); + } + payload.insert("Name", name); + payload.insert("PhoneNumber", phones); + payload.insert("IsFav", cFav.isFavorite()); + QJsonObject record; + record.insert("RecordId", getRecordIdForContact(QtContactsSqliteExtensions::internalContactId(contact.id()))); + record.insert("RecordPayload", payload); + records.append(record); + } + + QString storeName("Phub.Phone.Contacts"); + QJsonObject store; + store.insert("Name", storeName); + store.insert("Records", records); + + QJsonObject root; + root.insert("DataStore", store); + + QJsonDocument doc(root); + qDebug() << doc.toJson(); + + _storage->updateStore(storeName, root); + + emit changed(); +} diff --git a/saltoqd/contactsmanager.h b/saltoqd/contactsmanager.h new file mode 100644 index 0000000..0b39d40 --- /dev/null +++ b/saltoqd/contactsmanager.h @@ -0,0 +1,31 @@ +#ifndef CONTACTSMANAGER_H +#define CONTACTSMANAGER_H + +#include +#include "storagemanager.h" + +class ContactsManager : public QObject +{ + Q_OBJECT +public: + explicit ContactsManager(StorageManager *storage, ToqManager *toq); + + qint64 getRecordIdForContact(uint contactId); + +public slots: + void scheduleRefresh(); + +signals: + void changed(); + +private slots: + void refresh(); + +private: + ToqManager *_toq; + StorageManager *_storage; + QtContacts::QContactManager *_contacts; + QTimer *_refreshTimer; +}; + +#endif // CONTACTSMANAGER_H diff --git a/saltoqd/obexconnection.cpp b/saltoqd/obexconnection.cpp index 28aa4e2..5fab0ab 100644 --- a/saltoqd/obexconnection.cpp +++ b/saltoqd/obexconnection.cpp @@ -7,13 +7,6 @@ ObexTransfer::ObexTransfer(obex_t *obex, obex_object_t *obj, QObject *parent) : { } -ObexTransfer::~ObexTransfer() -{ - if (_obj) { - OBEX_ObjectDelete(_obex, _obj); - } -} - void ObexTransfer::cancel() { // TODO @@ -21,8 +14,10 @@ void ObexTransfer::cancel() ObexConnection::ObexConnection(ToqConnection *conn, QObject *parent) : QObject(parent), _conn(conn), + _socket(0), _reconnectTimer(new QTimer(this)), - _obex(0), _connected(false), _busy(false) + _obex(0), + _connected(false), _busy(false) { connect(_conn, &ToqConnection::connected, this, &ObexConnection::handleToqConnected); diff --git a/saltoqd/obexconnection.h b/saltoqd/obexconnection.h index 431af9b..45345c9 100644 --- a/saltoqd/obexconnection.h +++ b/saltoqd/obexconnection.h @@ -16,7 +16,6 @@ class ObexTransfer : public QObject friend class ObexConnection; explicit ObexTransfer(obex_t *obex, obex_object_t *obj, QObject *parent); - ~ObexTransfer(); public slots: void cancel(); diff --git a/saltoqd/saltoqd.pro b/saltoqd/saltoqd.pro index 8b656ba..8661518 100644 --- a/saltoqd/saltoqd.pro +++ b/saltoqd/saltoqd.pro @@ -1,11 +1,11 @@ TEMPLATE = app CONFIG += console QT -= qml -QT += dbus bluetooth +QT += dbus bluetooth contacts CONFIG += c++11 link_pkgconfig -PKGCONFIG += zlib commhistory-qt5 openobex +PKGCONFIG += zlib commhistory-qt5 openobex qtcontacts-sqlite-qt5-extensions INCLUDEPATH += /usr/include/commhistory-qt5 SOURCES += main.cpp \ @@ -20,7 +20,8 @@ SOURCES += main.cpp \ voicecallmanager.cpp \ fmsmanager.cpp \ weathermanager.cpp \ - obexconnection.cpp + obexconnection.cpp \ + contactsmanager.cpp HEADERS += \ toqconnection.h \ @@ -34,7 +35,8 @@ HEADERS += \ voicecallmanager.h \ fmsmanager.h \ weathermanager.h \ - obexconnection.h + obexconnection.h \ + contactsmanager.h DBUS_ADAPTORS += org.freedesktop.Notifications.xml diff --git a/saltoqd/storagemanager.cpp b/saltoqd/storagemanager.cpp index fe53cd6..257faf1 100644 --- a/saltoqd/storagemanager.cpp +++ b/saltoqd/storagemanager.cpp @@ -101,8 +101,6 @@ void StorageManager::updateStore(const QString &storeName, const QJsonObject &js QJsonDocument doc(json); QByteArray data = doc.toJson(QJsonDocument::Compact); - qDebug() << "Store" << storeName << ":" << QString::fromUtf8(data); - quint32 checksum = ToqConnection::checksum(data); if (store.checksum != checksum) { store.contents = data; diff --git a/saltoqd/toqmanager.cpp b/saltoqd/toqmanager.cpp index 27331da..3f850d1 100644 --- a/saltoqd/toqmanager.cpp +++ b/saltoqd/toqmanager.cpp @@ -7,10 +7,13 @@ #include "fmsmanager.h" #include "storagemanager.h" #include "musicmanager.h" +#include "contactsmanager.h" #include "commmanager.h" #include "voicecallmanager.h" #include "weathermanager.h" +static const bool PROTO_DEBUG = true; + ToqManager::ToqManager(const QBluetoothAddress &address, QObject *parent) : QObject(parent), _conn(new ToqConnection(address, this)), @@ -20,7 +23,8 @@ ToqManager::ToqManager(const QBluetoothAddress &address, QObject *parent) : _fmsManager(new FmsManager(_obex, this)), _storageManager(new StorageManager(_obex, this)), _musicManager(new MusicManager(this)), - _commManager(new CommManager(_storageManager, this)), + _contactsManager(new ContactsManager(_storageManager, this)), + _commManager(new CommManager(_storageManager, _contactsManager, this)), _voiceCallManager(new VoiceCallManager(this)), _weatherManager(new WeatherManager(_fmsManager, this)) { @@ -40,7 +44,7 @@ void ToqManager::setEndpointListener(ToqConnection::Endpoint ep, EndpointHandler void ToqManager::sendMessage(const ToqConnection::Message &msg) { - if (1) { + if (PROTO_DEBUG) { QString json = QString::fromUtf8(msg.payload.toJson(QJsonDocument::Compact)); qDebug() << "Sending message to" << ToqConnection::nameOfEndpoint(msg.destination) << "from" << ToqConnection::nameOfEndpoint(msg.source) << "type" << msg.type << json; } @@ -73,7 +77,7 @@ void ToqManager::handleToqMessage(const ToqConnection::Message &msg) { EndpointHandler *handler = _handlers.value(msg.destination, 0); - if (1) { + if (PROTO_DEBUG) { QString json = QString::fromUtf8(msg.payload.toJson(QJsonDocument::Compact)); qDebug() << "Received message to" << ToqConnection::nameOfEndpoint(msg.destination) << "from" << ToqConnection::nameOfEndpoint(msg.destination) << "type" << msg.type << json; } diff --git a/saltoqd/toqmanager.h b/saltoqd/toqmanager.h index d3265a8..b1fe4a5 100644 --- a/saltoqd/toqmanager.h +++ b/saltoqd/toqmanager.h @@ -11,6 +11,7 @@ class SystemManager; class FmsManager; class StorageManager; class MusicManager; +class ContactsManager; class CommManager; class VoiceCallManager; class WeatherManager; @@ -55,6 +56,7 @@ private: FmsManager *_fmsManager; StorageManager *_storageManager; MusicManager *_musicManager; + ContactsManager *_contactsManager; CommManager *_commManager; VoiceCallManager *_voiceCallManager; WeatherManager *_weatherManager; -- cgit v1.2.3