From 8da3d82c9bfce8a58908a38b9b80ab33de5dfb1d Mon Sep 17 00:00:00 2001 From: LNJ Date: Mon, 5 Jun 2017 19:00:18 +0200 Subject: [PATCH] Count unread messages and save them in the db Clean up all includes and don't use "Swiften/Swiften.h" anymore. This will speed up builds much. --- i18n/de.ts | 31 +++++++++++++++- i18n/fr.ts | 33 +++++++++++++---- i18n/ja.ts | 33 +++++++++++++---- i18n/ru.ts | 35 +++++++++++++---- src/Kaidan.cpp | 9 +++-- src/Kaidan.h | 3 +- src/MessageController.cpp | 32 +++++++++++----- src/MessageController.h | 4 +- src/MessageModel.cpp | 66 +++++++++++++-------------------- src/MessageModel.h | 1 - src/PresenceController.cpp | 3 +- src/PresenceController.h | 3 +- src/RosterController.cpp | 27 +++++++++++++- src/RosterController.h | 7 +++- src/RosterModel.cpp | 40 ++++++++++++++++++-- src/RosterModel.h | 7 +--- src/ServiceDiscoveryManager.cpp | 4 +- src/ServiceDiscoveryManager.h | 4 +- src/VCard.cpp | 4 +- src/VCard.h | 2 +- src/VCardController.cpp | 3 +- src/VCardController.h | 4 +- src/main.cpp | 1 + src/qml/AboutPage.qml | 8 +++- src/qml/ChatPage.qml | 7 ---- src/qml/RosterPage.qml | 11 +++++- 26 files changed, 268 insertions(+), 114 deletions(-) diff --git a/i18n/de.ts b/i18n/de.ts index b2a70868..44e4fdf9 100644 --- a/i18n/de.ts +++ b/i18n/de.ts @@ -39,7 +39,7 @@ GlobalDrawer Add Contact - Kontakt Hinzufügen + Kontakt Hinzufügen Logout @@ -49,6 +49,10 @@ About Über + + Add new contact + + LoginPage @@ -101,7 +105,7 @@ RosterAddContactSheet Add Contact - Kontakt Hinzufügen + Kontakt Hinzufügen Nickname: @@ -123,6 +127,10 @@ Add Hinzufügen + + Add new contact + + RosterPage @@ -131,6 +139,25 @@ Kontakte + + RosterRemoveContactSheet + + Do you really want to delete the contact "%1" from your roster? + + + + Delete contact + + + + Cancel + Abbrechen + + + Delete + + + main diff --git a/i18n/fr.ts b/i18n/fr.ts index a8d4ce74..a0e2f136 100644 --- a/i18n/fr.ts +++ b/i18n/fr.ts @@ -38,15 +38,15 @@ GlobalDrawer - Add Contact + Logout - Logout + About - About + Add new contact @@ -95,10 +95,6 @@ RosterAddContactSheet - - Add Contact - - Nickname: @@ -119,6 +115,10 @@ Add + + Add new contact + + RosterPage @@ -127,4 +127,23 @@ + + RosterRemoveContactSheet + + Do you really want to delete the contact "%1" from your roster? + + + + Delete contact + + + + Cancel + + + + Delete + + + diff --git a/i18n/ja.ts b/i18n/ja.ts index 43f87f58..350ffd23 100644 --- a/i18n/ja.ts +++ b/i18n/ja.ts @@ -38,15 +38,15 @@ GlobalDrawer - Add Contact + Logout - Logout + About - About + Add new contact @@ -99,10 +99,6 @@ RosterAddContactSheet - - Add Contact - - Nickname: @@ -123,6 +119,10 @@ Add + + Add new contact + + RosterPage @@ -131,4 +131,23 @@ + + RosterRemoveContactSheet + + Do you really want to delete the contact "%1" from your roster? + + + + Delete contact + + + + Cancel + + + + Delete + + + diff --git a/i18n/ru.ts b/i18n/ru.ts index 1c61660d..9256f5fc 100644 --- a/i18n/ru.ts +++ b/i18n/ru.ts @@ -37,10 +37,6 @@ GlobalDrawer - - Add Contact - - Logout Выйти @@ -49,6 +45,10 @@ About О программе + + Add new contact + + LoginPage @@ -99,10 +99,6 @@ RosterAddContactSheet - - Add Contact - - Nickname: @@ -123,6 +119,10 @@ Add + + Add new contact + + RosterPage @@ -131,6 +131,25 @@ Контакты + + RosterRemoveContactSheet + + Do you really want to delete the contact "%1" from your roster? + + + + Delete contact + + + + Cancel + + + + Delete + + + main diff --git a/src/Kaidan.cpp b/src/Kaidan.cpp index 8b6cd504..b16e3da8 100644 --- a/src/Kaidan.cpp +++ b/src/Kaidan.cpp @@ -31,12 +31,15 @@ // Boost #include // Swiften -#include +#include +#include #include +#include // Kaidan #include "RosterController.h" #include "PresenceController.h" #include "MessageController.h" +#include "MessageModel.h" #include "VCardController.h" #include "ServiceDiscoveryManager.h" @@ -69,7 +72,7 @@ Kaidan::Kaidan(Swift::NetworkFactories* networkFactories, QObject *parent) : QOb // create/update the full jid updateFullJid(); - // load controlers + // load controllers messageController = new MessageController(&jid); rosterController = new RosterController(); presenceController = new PresenceController(); @@ -130,7 +133,7 @@ void Kaidan::mainConnect() Swift::ClientOptions options; options.useStreamCompression = false; - + // .. and connect! client->connect(options); } diff --git a/src/Kaidan.h b/src/Kaidan.h index c06be24d..35d2aa5b 100644 --- a/src/Kaidan.h +++ b/src/Kaidan.h @@ -28,7 +28,8 @@ #include #include // Swiften -#include +#include +#include // Kaidan #include "RosterController.h" #include "MessageController.h" diff --git a/src/MessageController.cpp b/src/MessageController.cpp index 55bda960..71a4420f 100644 --- a/src/MessageController.cpp +++ b/src/MessageController.cpp @@ -32,7 +32,11 @@ #include #include // Swiften -#include +#include +#include +#include +#include +#include // Kaidan #include "MessageModel.h" #include "Notifications.h" @@ -67,6 +71,7 @@ MessageModel* MessageController::getMessageModel() void MessageController::setRecipient(QString recipient_) { + // update the recipient if (recipient == recipient_) return; @@ -77,6 +82,9 @@ void MessageController::setRecipient(QString recipient_) // we're offline or we haven't connected already. messageModel->applyRecipientFilter(recipient, *ownJid); emit messageModelChanged(); + + // reset the unread message counter for this contact + rosterController->resetUnreadMessagesForJid(recipient_); } QString MessageController::getRecipient() @@ -84,11 +92,6 @@ QString MessageController::getRecipient() return recipient; } -void MessageController::setMessageAsRead(const QString msgId) -{ - messageModel->setMessageAsRead(msgId); -} - void MessageController::handleMessageReceived(Swift::Message::ref message_) { boost::optional bodyOpt = message_->getBody(); @@ -100,7 +103,7 @@ void MessageController::handleMessageReceived(Swift::Message::ref message_) // // author is only the 'bare' JID: e.g. 'albert@einstein.ch' - const QString author = QString(message_->getFrom().toBare().toString().c_str()); + const QString author = QString::fromStdString(message_->getFrom().toBare().toString()); const QString author_resource = QString(message_->getFrom().getResource().c_str()); const QString recipient_resource = QString::fromStdString(client->getJID().getResource()); QString timestamp = QDateTime::currentDateTime().toString(Qt::ISODate); // fallback timestamp @@ -162,11 +165,20 @@ void MessageController::handleMessageReceived(Swift::Message::ref message_) } // - // Update lastExchanged in roster controller + // Update last exchanged, unread message count in roster controller // - rosterController->updateLastExchangedOfJid(QString::fromStdString( - message_->getFrom().toBare().toString())); + if (bodyOpt) + { + const QString msgAuthor = QString::fromStdString(message_->getFrom().toBare().toString()); + + rosterController->updateLastExchangedOfJid(msgAuthor); + + if (msgAuthor != this->recipient) + { + rosterController->newUnreadMessageForJid(msgAuthor); + } + } } void MessageController::sendMessage(const QString recipient_, const QString message_) diff --git a/src/MessageController.h b/src/MessageController.h index 529cc1d8..9970b87e 100644 --- a/src/MessageController.h +++ b/src/MessageController.h @@ -24,7 +24,8 @@ #include #include // Swiften -#include +#include +#include // Kaidan #include "MessageModel.h" #include "RosterController.h" @@ -47,7 +48,6 @@ class MessageController : public QObject QString getRecipient(); Q_INVOKABLE void sendMessage(const QString recipient_, const QString message_); - Q_INVOKABLE void setMessageAsRead(const QString msgId); signals: void messageModelChanged(); diff --git a/src/MessageModel.cpp b/src/MessageModel.cpp index d2347436..b592d820 100644 --- a/src/MessageModel.cpp +++ b/src/MessageModel.cpp @@ -47,20 +47,17 @@ static void createTable() "'timestamp' TEXT NOT NULL," "'message' TEXT NOT NULL," "'id' TEXT NOT NULL," - "'isSent' BOOL," - "'isDelivered' BOOL," - "'isRead' BOOL," - "'meta' TEXT," // placeholder field for later additons - "FOREIGN KEY('author') REFERENCES Contacts ('jid')," - "FOREIGN KEY('recipient') REFERENCES Contacts ('jid')" + "'isSent' BOOL," // is sent to server + "'isDelivered' BOOL," // message has arrived at other client + "FOREIGN KEY('author') REFERENCES Roster ('jid')," + "FOREIGN KEY('recipient') REFERENCES Roster ('jid')" ")")) { qFatal("Failed to query database: %s", qPrintable(query.lastError().text())); } } -MessageModel::MessageModel(QObject *parent) : - QSqlTableModel(parent) +MessageModel::MessageModel(QObject *parent) : QSqlTableModel(parent) { createTable(); setTable(conversationsTableName); @@ -92,19 +89,12 @@ QVariant MessageModel::data(const QModelIndex &index, int role) const QHash MessageModel::roleNames() const { - QHash names; - names[Qt::UserRole] = "author"; - names[Qt::UserRole + 1] = "author_resource"; - names[Qt::UserRole + 2] = "recipient"; - names[Qt::UserRole + 3] = "recipient_resource"; - names[Qt::UserRole + 4] = "timestamp"; - names[Qt::UserRole + 5] = "message"; - names[Qt::UserRole + 6] = "id"; - names[Qt::UserRole + 7] = "isSent"; // sent to server - names[Qt::UserRole + 8] = "isDelivered"; // message has arrived on a client - names[Qt::UserRole + 9] = "isRead"; // message has been read from the recipient - names[Qt::UserRole + 10] = "meta"; - return names; + QHash roles; + // record() returns an empty QSqlRecord + for (int i = 0; i < this->record().count(); i++) { + roles.insert(Qt::UserRole + i, record().fieldName(i).toUtf8()); + } + return roles; } void MessageModel::setMessageAsSent(const QString msgId) @@ -121,13 +111,6 @@ void MessageModel::setMessageAsDelivered(const QString msgId) submitAll(); } -void MessageModel::setMessageAsRead(const QString msgId) -{ - QSqlQuery newQuery; - newQuery.exec(QString("UPDATE 'Messages' SET 'isRead' = 1 WHERE id = '%1'").arg(msgId)); - submitAll(); -} - void MessageModel::addMessage(const QString* author, const QString* author_resource, const QString* recipient, const QString* recipient_resource, const QString* timestamp, const QString* message, const QString* msgId, @@ -137,19 +120,20 @@ void MessageModel::addMessage(const QString* author, const QString* author_resou // add the new message // - QSqlRecord newRecord = record(); - newRecord.setValue("author", *author); - newRecord.setValue("author_resource", *author_resource); - newRecord.setValue("recipient", *recipient); - newRecord.setValue("recipient_resource", *recipient_resource); - newRecord.setValue("timestamp", *timestamp); - newRecord.setValue("message", *message); - newRecord.setValue("id", *msgId); - newRecord.setValue("isSent", sentByMe ? false : true); - newRecord.setValue("isDelivered", sentByMe ? false : true); - newRecord.setValue("isRead", sentByMe ? true : false); - - if (!insertRecord(rowCount(), newRecord)) { + QSqlRecord record = this->record(); + record.setValue("author", *author); + record.setValue("author_resource", *author_resource); + record.setValue("recipient", *recipient); + record.setValue("recipient_resource", *recipient_resource); + record.setValue("timestamp", *timestamp); + record.setValue("message", *message); + record.setValue("id", *msgId); + record.setValue("isSent", sentByMe ? false : true); + record.setValue("isDelivered", sentByMe ? false : true); + record.setValue("isRead", sentByMe ? false : true); + record.setValue("isReadByMe", sentByMe ? true : false); + + if (!insertRecord(rowCount(), record)) { qWarning() << "Failed to add message to DB:" << lastError().text(); return; } diff --git a/src/MessageModel.h b/src/MessageModel.h index fb014d9d..96585c32 100644 --- a/src/MessageModel.h +++ b/src/MessageModel.h @@ -39,7 +39,6 @@ class MessageModel : public QSqlTableModel const QString* msgId, bool sentByMe); void setMessageAsSent(const QString msgId); void setMessageAsDelivered(const QString msgId); - void setMessageAsRead(const QString msgId); signals: void recipientChanged(); diff --git a/src/PresenceController.cpp b/src/PresenceController.cpp index faa017c3..8ff003f2 100644 --- a/src/PresenceController.cpp +++ b/src/PresenceController.cpp @@ -19,7 +19,8 @@ #include "PresenceController.h" #include -#include +#include +#include #include PresenceController::PresenceController(QObject* parent) : QObject(parent) diff --git a/src/PresenceController.h b/src/PresenceController.h index 9b7c276b..b23238bd 100644 --- a/src/PresenceController.h +++ b/src/PresenceController.h @@ -21,7 +21,8 @@ #define PRESENCECONTROLLER_H #include -#include +#include +#include class PresenceController : public QObject { diff --git a/src/RosterController.cpp b/src/RosterController.cpp index 626c0ccb..ef266384 100644 --- a/src/RosterController.cpp +++ b/src/RosterController.cpp @@ -20,7 +20,8 @@ // RosterController #include "RosterController.h" -// C++ +// Std +#include #include // Qt 5 #include @@ -32,7 +33,13 @@ // Kaidan #include "RosterModel.h" // Swiften -#include +#include +#include +#include +#include +#include +#include +#include // Boost #include @@ -237,3 +244,19 @@ void RosterController::updateLastExchangedOfJid(const QString jid_) // send signal for updating the GUI emit rosterModelChanged(); } + +void RosterController::newUnreadMessageForJid(const QString jid_) +{ + // get the current unread message count + int msgCount = rosterModel->getUnreadMessageCountOfJid(&jid_); + // increase it by one + msgCount++; + // set the new increased count + rosterModel->setUnreadMessageCountOfJid(&jid_, msgCount); +} + +void RosterController::resetUnreadMessagesForJid(const QString jid_) +{ + rosterModel->setUnreadMessageCountOfJid(&jid_, 0); + emit rosterModelChanged(); +} diff --git a/src/RosterController.h b/src/RosterController.h index 84663911..1384f442 100644 --- a/src/RosterController.h +++ b/src/RosterController.h @@ -26,7 +26,8 @@ #include #include // Swiften -#include +#include +#include // Kaidan #include "RosterModel.h" @@ -43,6 +44,8 @@ class RosterController : public QObject void requestRosterFromClient(); RosterModel* getRosterModel(); void updateLastExchangedOfJid(const QString jid_); + void newUnreadMessageForJid(const QString jid_); + void resetUnreadMessagesForJid(const QString jid_); Q_INVOKABLE void addContact(const QString jid_, const QString name_); Q_INVOKABLE void removeContact(const QString); @@ -57,7 +60,7 @@ class RosterController : public QObject void handleJidUpdated(const Swift::JID &jid_, const std::string &name_, const std::vector&); void handleRosterCleared(); Swift::Client* client; - Swift::IQRouter *iqRouter; + Swift::IQRouter* iqRouter; Swift::XMPPRoster* xmppRoster; RosterModel* rosterModel; }; diff --git a/src/RosterModel.cpp b/src/RosterModel.cpp index 303f0879..891344aa 100644 --- a/src/RosterModel.cpp +++ b/src/RosterModel.cpp @@ -40,12 +40,12 @@ static void createTable() "'jid' TEXT NOT NULL," "'name' TEXT NOT NULL," "'lastExchanged' TEXT NOT NULL," - "'unreadMessages' INTEGER," // < UNUSED v - "'lastMessage' TEXT," + "'unreadMessages' INTEGER," + "'lastMessage' TEXT," // < UNUSED v "'lastOnline' TEXT," "'activity' TEXT," "'status' TEXT," - "'mood' TEXT" // < UNUSED ^ + "'mood' TEXT" // < UNUSED ^ ")")) { qFatal("Failed to query database: %s", qPrintable(query.lastError().text())); @@ -138,7 +138,7 @@ QStringList RosterModel::getJidList() QStringList retVar; QSqlQuery query; - query.exec("SELECT * FROM 'Roster'"); + query.exec("SELECT jid FROM Roster"); int jidCol = query.record().indexOf("jid"); @@ -164,3 +164,35 @@ void RosterModel::setLastExchangedOfJid(const QString jid_, const QString date_) newQuery.exec(QString("UPDATE 'Roster' SET lastExchanged = '%1' WHERE jid = '%2'").arg(date_, jid_)); submitAll(); } + +int RosterModel::getUnreadMessageCountOfJid(const QString* jid_) +{ + QSqlQuery query; + + query.prepare(QString("SELECT unreadMessages FROM Roster WHERE jid = '%1'").arg(*jid_)); + if (!query.exec()) + { + qDebug("Failed to query database: %s", qPrintable(query.lastError().text())); + return 0; + } + + query.next(); + return query.value("unreadMessages").toInt(); +} + +void RosterModel::setUnreadMessageCountOfJid(const QString* jid_, const int count_) +{ + QSqlQuery query; + query.prepare(QString("UPDATE Roster SET unreadMessages = %1 WHERE jid = '%2'") + .arg(QString::number(count_), *jid_)); + + if (!query.exec()) { + qDebug("Failed to query database: %s", qPrintable(query.lastError().text())); + qDebug() << query.lastQuery(); + } + if (!select()) { + qDebug() << "Error on select in RosterModel::setUnreadMessageCountOfJid"; + } + + submit(); +} diff --git a/src/RosterModel.h b/src/RosterModel.h index 031a259b..83096cad 100644 --- a/src/RosterModel.h +++ b/src/RosterModel.h @@ -24,8 +24,6 @@ #include #include #include -// Swiften -#include class RosterModel : public QSqlTableModel { @@ -43,9 +41,8 @@ class RosterModel : public QSqlTableModel QStringList getJidList(); void removeListOfJids(QStringList*); void setLastExchangedOfJid(const QString, const QString); - -private: - Swift::Client* client; + int getUnreadMessageCountOfJid(const QString* jid_); + void setUnreadMessageCountOfJid(const QString* jid_, const int unreadMessageCount); }; #endif // ROSTERMODEL_H diff --git a/src/ServiceDiscoveryManager.cpp b/src/ServiceDiscoveryManager.cpp index a36a787b..c188a2ff 100644 --- a/src/ServiceDiscoveryManager.cpp +++ b/src/ServiceDiscoveryManager.cpp @@ -26,7 +26,9 @@ // Boost #include // Swiften -#include +#include +#include +#include ServiceDiscoveryManager::ServiceDiscoveryManager() { diff --git a/src/ServiceDiscoveryManager.h b/src/ServiceDiscoveryManager.h index ce0b2d52..a88eac67 100644 --- a/src/ServiceDiscoveryManager.h +++ b/src/ServiceDiscoveryManager.h @@ -25,7 +25,9 @@ #define SERVICEDISCOVERYMANAGER_H // Swiften -#include +#include +#include +#include class ServiceDiscoveryManager { diff --git a/src/VCard.cpp b/src/VCard.cpp index f7a60060..b9747804 100644 --- a/src/VCard.cpp +++ b/src/VCard.cpp @@ -19,12 +19,14 @@ // VCard #include "VCard.h" +// Std +#include // Qt 5 #include // Boost #include // Swiften -#include +#include VCard::VCard(QObject *parent) : QObject(parent) { diff --git a/src/VCard.h b/src/VCard.h index 4924ebb7..e312a1e2 100644 --- a/src/VCard.h +++ b/src/VCard.h @@ -26,7 +26,7 @@ // Boost #include // Swiften -#include +#include class VCard : public QObject { diff --git a/src/VCardController.cpp b/src/VCardController.cpp index e9eb37f3..84f774f9 100644 --- a/src/VCardController.cpp +++ b/src/VCardController.cpp @@ -24,7 +24,8 @@ // Qt 5 #include // Swiften -#include +#include +#include // Boost #include // Kaidan diff --git a/src/VCardController.h b/src/VCardController.h index 015a6f16..29633006 100644 --- a/src/VCardController.h +++ b/src/VCardController.h @@ -23,7 +23,9 @@ // Qt #include // Swiften -#include +#include +#include +#include // Kaidan #include "VCard.h" diff --git a/src/main.cpp b/src/main.cpp index 7180d0e3..f4209c60 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,7 @@ #include // Swiften #include +#include // Kaidan #include "Kaidan.h" #include "VCard.h" diff --git a/src/qml/AboutPage.qml b/src/qml/AboutPage.qml index 97e10203..253e6498 100644 --- a/src/qml/AboutPage.qml +++ b/src/qml/AboutPage.qml @@ -63,9 +63,13 @@ Kirigami.Page { } Controls.Button { - anchors.horizontalCenter: parent.horizontalCenter + id: closeButton text: qsTr("Close") - onClicked: pageStack.pop() + anchors.horizontalCenter: parent.horizontalCenter + onClicked: { + closeButton.enabled = false; + pageStack.pop(); + } } } } diff --git a/src/qml/ChatPage.qml b/src/qml/ChatPage.qml index e89fa039..0ad7fa09 100644 --- a/src/qml/ChatPage.qml +++ b/src/qml/ChatPage.qml @@ -110,13 +110,6 @@ Kirigami.Page { } } } - - Component.onCompleted: { - // mark unread messages as read - if (!model.isRead) { - kaidan.messageController.setMessageAsRead(model.id); - } - } } } diff --git a/src/qml/RosterPage.qml b/src/qml/RosterPage.qml index 57281f4f..dface14a 100644 --- a/src/qml/RosterPage.qml +++ b/src/qml/RosterPage.qml @@ -46,13 +46,20 @@ Kirigami.ScrollablePage { text: model.name ? model.name : model.jid } - onClicked: { - kaidan.messageController.recipient = model.jid; + // TODO: Add unread message counter: model.unreadMessages + onClicked: { + // first push the chat page pageStack.push(chatPage, { "chatName": (model.name ? model.name : model.jid), "recipientJid": model.jid }); + + // then set the message filter for this jid + // this will update the unread message count, + // which will update the roster and will reset the + // model variable + kaidan.messageController.recipient = model.jid; } actions: [