From d1ccf9f7965c1fbc735528ee879ec11939bb58f0 Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Fri, 20 Nov 2020 21:39:23 +0200 Subject: [PATCH] Show notification popups except for the current chat And drop dependency on Ngf. Also, pre-initialize the chat photo when pushing the chat page. --- harbour-fernschreiber.pro | 2 +- qml/pages/ChatPage.qml | 4 ++ qml/pages/OverviewPage.qml | 5 +- src/chatmodel.cpp | 22 +++++++++ src/chatmodel.h | 4 +- src/harbour-fernschreiber.cpp | 2 +- src/notificationmanager.cpp | 87 +++++++++++++---------------------- src/notificationmanager.h | 12 ++--- 8 files changed, 70 insertions(+), 68 deletions(-) diff --git a/harbour-fernschreiber.pro b/harbour-fernschreiber.pro index 31887de..1276f8d 100644 --- a/harbour-fernschreiber.pro +++ b/harbour-fernschreiber.pro @@ -14,7 +14,7 @@ TARGET = harbour-fernschreiber CONFIG += sailfishapp sailfishapp_i18n -PKGCONFIG += nemonotifications-qt5 ngf-qt5 zlib +PKGCONFIG += nemonotifications-qt5 zlib QT += core dbus sql diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index 3fe7636..a8f335a 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -35,6 +35,7 @@ Page { property bool isInitialized: false; readonly property int myUserId: tdLibWrapper.getUserInformation().id; property var chatInformation; + property alias chatPicture: chatPictureThumbnail.photoData property bool isPrivateChat: false; property bool isBasicGroup: false; property bool isSuperGroup: false; @@ -353,6 +354,9 @@ Page { chatPage.isInitialized = true; } break; + case PageStatus.Inactive: + chatModel.clear(); + break; } } diff --git a/qml/pages/OverviewPage.qml b/qml/pages/OverviewPage.qml index b6f70ab..3296fc6 100644 --- a/qml/pages/OverviewPage.qml +++ b/qml/pages/OverviewPage.qml @@ -237,7 +237,10 @@ Page { ownUserId: overviewPage.ownUserId onClicked: { - pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { "chatInformation" : display }); + pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { + chatInformation : display, + chatPicture: photo_small + }) } Connections { diff --git a/src/chatmodel.cpp b/src/chatmodel.cpp index ab84c14..084a737 100644 --- a/src/chatmodel.cpp +++ b/src/chatmodel.cpp @@ -85,6 +85,23 @@ bool ChatModel::insertRows(int row, int count, const QModelIndex &parent) return true; } +void ChatModel::clear() +{ + LOG("Clearing chat model"); + chatId = 0; + inReload = false; + inIncrementalUpdate = false; + if (!messages.isEmpty()) { + beginResetModel(); + messages.clear(); + endResetModel(); + } + if (!chatInformation.isEmpty()) { + chatInformation.clear(); + emit smallPhotoChanged(); + } +} + void ChatModel::initialize(const QVariantMap &chatInformation) { LOG("Initializing chat model..."); @@ -157,6 +174,11 @@ QVariantMap ChatModel::smallPhoto() const return chatInformation.value(PHOTO).toMap().value(SMALL).toMap(); } +qlonglong ChatModel::getChatId() const +{ + return chatId; +} + static bool compareMessages(const QVariant &message1, const QVariant &message2) { const QVariantMap messageMap1 = message1.toMap(); diff --git a/src/chatmodel.h b/src/chatmodel.h index 7c54f5e..10217d5 100644 --- a/src/chatmodel.h +++ b/src/chatmodel.h @@ -36,14 +36,16 @@ public: virtual QVariant data(const QModelIndex &index, int role) const override; virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; - + Q_INVOKABLE void clear(); Q_INVOKABLE void initialize(const QVariantMap &chatInformation); Q_INVOKABLE void triggerLoadMoreHistory(); Q_INVOKABLE void triggerLoadMoreFuture(); Q_INVOKABLE QVariantMap getChatInformation(); Q_INVOKABLE QVariantMap getMessage(int index); Q_INVOKABLE int getLastReadMessageIndex(); + QVariantMap smallPhoto() const; + qlonglong getChatId() const; signals: void messagesReceived(int modelIndex, int lastReadSentIndex, int totalCount); diff --git a/src/harbour-fernschreiber.cpp b/src/harbour-fernschreiber.cpp index 631f28b..5d413a1 100644 --- a/src/harbour-fernschreiber.cpp +++ b/src/harbour-fernschreiber.cpp @@ -73,7 +73,7 @@ int main(int argc, char *argv[]) ChatModel chatModel(tdLibWrapper); context->setContextProperty("chatModel", &chatModel); - NotificationManager notificationManager(tdLibWrapper, appSettings); + NotificationManager notificationManager(tdLibWrapper, appSettings, &chatModel); context->setContextProperty("notificationManager", ¬ificationManager); ProcessLauncher processLauncher; diff --git a/src/notificationmanager.cpp b/src/notificationmanager.cpp index e499636..c8fe0c7 100644 --- a/src/notificationmanager.cpp +++ b/src/notificationmanager.cpp @@ -19,6 +19,7 @@ #include "notificationmanager.h" #include "fernschreiberutils.h" +#include "chatmodel.h" #include #include #include @@ -50,15 +51,17 @@ namespace { const QString CHAT_TYPE_BASIC_GROUP("chatTypeBasicGroup"); const QString CHAT_TYPE_SUPERGROUP("chatTypeSupergroup"); - const QString NOTIFICATION_CATEGORY("x-nemo.messaging.im"); - const QString NGF_EVENT("chat"); - const QString APP_NAME("Fernschreiber"); // Notification hints const QString HINT_GROUP_ID("x-fernschreiber.group_id"); // int const QString HINT_CHAT_ID("x-fernschreiber.chat_id"); // qlonglong const QString HINT_TOTAL_COUNT("x-fernschreiber.total_count"); // int + + const QString HINT_VIBRA("x-nemo-vibrate"); // bool + const QString HINT_DISPLAY_ON("x-nemo-display-on"); // bool + const QString HINT_VISIBILITY("x-nemo-visibility"); // QString + const QString VISIBILITY_PUBLIC("public"); } class NotificationManager::ChatInfo @@ -116,30 +119,21 @@ NotificationManager::NotificationGroup::~NotificationGroup() delete nemoNotification; } -NotificationManager::NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings) : +NotificationManager::NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings, ChatModel *chatModel) : mceInterface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request", QDBusConnection::systemBus()), appIconFile(SailfishApp::pathTo("images/fernschreiber-notification.png").toLocalFile()) { LOG("Initializing..."); this->tdLibWrapper = tdLibWrapper; this->appSettings = appSettings; - this->ngfClient = new Ngf::Client(this); + this->appSettings = appSettings; + this->chatModel = chatModel; connect(this->tdLibWrapper, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SLOT(handleUpdateActiveNotifications(QVariantList))); connect(this->tdLibWrapper, SIGNAL(notificationGroupUpdated(QVariantMap)), this, SLOT(handleUpdateNotificationGroup(QVariantMap))); connect(this->tdLibWrapper, SIGNAL(notificationUpdated(QVariantMap)), this, SLOT(handleUpdateNotification(QVariantMap))); connect(this->tdLibWrapper, SIGNAL(newChatDiscovered(QString, QVariantMap)), this, SLOT(handleChatDiscovered(QString, QVariantMap))); connect(this->tdLibWrapper, SIGNAL(chatTitleUpdated(QString, QString)), this, SLOT(handleChatTitleUpdated(QString, QString))); - connect(this->ngfClient, SIGNAL(connectionStatus(bool)), this, SLOT(handleNgfConnectionStatus(bool))); - connect(this->ngfClient, SIGNAL(eventCompleted(quint32)), this, SLOT(handleNgfEventCompleted(quint32))); - connect(this->ngfClient, SIGNAL(eventFailed(quint32)), this, SLOT(handleNgfEventFailed(quint32))); - connect(this->ngfClient, SIGNAL(eventPlaying(quint32)), this, SLOT(handleNgfEventPlaying(quint32))); - - if (this->ngfClient->connect()) { - LOG("NGF Client successfully initialized..."); - } else { - LOG("Failed to initialize NGF Client..."); - } this->controlLedNotification(false); @@ -236,6 +230,12 @@ void NotificationManager::updateNotificationGroup(int groupId, qlonglong chatId, notificationGroup->notificationOrder.removeOne(removedId); } + // Make sure that if there's no notifications, order is empty too. + // That's usually already the case but double-check won't wort. It's cheap. + if (notificationGroup->activeNotifications.isEmpty()) { + notificationGroup->notificationOrder.clear(); + } + // Decide if we need a bzzz switch (feedback) { case AppSettings::NotificationFeedbackNone: @@ -251,6 +251,7 @@ void NotificationManager::updateNotificationGroup(int groupId, qlonglong chatId, } // Publish new or update the existing notification + LOG("Feedback" << needFeedback); publishNotification(notificationGroup, needFeedback); } else if (notificationGroup) { // No active notifications left in this group @@ -307,31 +308,6 @@ void NotificationManager::handleChatTitleUpdated(const QString &chatId, const QS } } -void NotificationManager::handleNgfConnectionStatus(bool connected) -{ - LOG("NGF Daemon connection status changed" << connected); -} - -void NotificationManager::handleNgfEventFailed(quint32 eventId) -{ - LOG("NGF event failed, id:" << eventId); -} - -void NotificationManager::handleNgfEventCompleted(quint32 eventId) -{ - LOG("NGF event completed, id:" << eventId); -} - -void NotificationManager::handleNgfEventPlaying(quint32 eventId) -{ - LOG("NGF event playing, id:" << eventId); -} - -void NotificationManager::handleNgfEventPaused(quint32 eventId) -{ - LOG("NGF event paused, id:" << eventId); -} - void NotificationManager::publishNotification(const NotificationGroup *notificationGroup, bool needFeedback) { QVariantMap messageMap; @@ -374,25 +350,24 @@ void NotificationManager::publishNotification(const NotificationGroup *notificat notificationBody = tr("%Ln unread messages", "", notificationGroup->totalCount); } + const QString summary(chatInformation ? chatInformation->title : QString()); nemoNotification->setBody(notificationBody); - nemoNotification->setSummary(chatInformation ? chatInformation->title : QString()); - if (needFeedback) { - nemoNotification->setCategory(NOTIFICATION_CATEGORY); + nemoNotification->setSummary(summary); + nemoNotification->setPreviewBody(notificationBody); + nemoNotification->setPreviewSummary(summary); + nemoNotification->setHintValue(HINT_VIBRA, needFeedback); - // Setting preview body & summary to a non-empty string causes a notification popup, - // no matter if we are in the current chat, in the app or not. That might be annoying - // In the future, we can show this popup depending if the app/chat is open or not - // - // nemoNotification->setPreviewBody(nemoNotification->body()); - // nemoNotification->setPreviewSummary(nemoNotification->summary()); - - nemoNotification->setPreviewBody(QString()); - nemoNotification->setPreviewSummary(QString()); - ngfClient->play(NGF_EVENT); + // Don't show popup for the currently open chat + if (!needFeedback || (chatModel->getChatId() == notificationGroup->chatId && + qGuiApp->applicationState() == Qt::ApplicationActive)) { + nemoNotification->setHintValue(HINT_DISPLAY_ON, false); + nemoNotification->setHintValue(HINT_VISIBILITY, QVariant()); + nemoNotification->setUrgency(Notification::Low); } else { - nemoNotification->setCategory(QString()); - nemoNotification->setPreviewBody(QString()); - nemoNotification->setPreviewSummary(QString()); + // The "display on" option will be configurable + nemoNotification->setHintValue(HINT_DISPLAY_ON, true); + nemoNotification->setHintValue(HINT_VISIBILITY, VISIBILITY_PUBLIC); + nemoNotification->setUrgency(Notification::Normal); } nemoNotification->publish(); diff --git a/src/notificationmanager.h b/src/notificationmanager.h index 4fa4bd6..79e242f 100644 --- a/src/notificationmanager.h +++ b/src/notificationmanager.h @@ -23,10 +23,11 @@ #include #include #include -#include #include "tdlibwrapper.h" #include "appsettings.h" +class ChatModel; + class NotificationManager : public QObject { Q_OBJECT @@ -35,7 +36,7 @@ class NotificationManager : public QObject public: - NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings); + NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings, ChatModel *chatModel); ~NotificationManager() override; public slots: @@ -45,11 +46,6 @@ public slots: void handleUpdateNotification(const QVariantMap &updatedNotification); void handleChatDiscovered(const QString &chatId, const QVariantMap &chatInformation); void handleChatTitleUpdated(const QString &chatId, const QString &title); - void handleNgfConnectionStatus(bool connected); - void handleNgfEventFailed(quint32 eventId); - void handleNgfEventCompleted(quint32 eventId); - void handleNgfEventPlaying(quint32 eventId); - void handleNgfEventPaused(quint32 eventId); private: @@ -65,7 +61,7 @@ private: TDLibWrapper *tdLibWrapper; AppSettings *appSettings; - Ngf::Client *ngfClient; + ChatModel *chatModel; QMap chatMap; QMap notificationGroups; QDBusInterface mceInterface;