Merge pull request #184 from monich/notifications

Show notification popups except for the current chat
This commit is contained in:
Sebastian Wolf 2020-11-20 21:37:17 +01:00 committed by GitHub
commit b7b9715969
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 70 additions and 68 deletions

View file

@ -14,7 +14,7 @@ TARGET = harbour-fernschreiber
CONFIG += sailfishapp sailfishapp_i18n CONFIG += sailfishapp sailfishapp_i18n
PKGCONFIG += nemonotifications-qt5 ngf-qt5 zlib PKGCONFIG += nemonotifications-qt5 zlib
QT += core dbus sql QT += core dbus sql

View file

@ -35,6 +35,7 @@ Page {
property bool isInitialized: false; property bool isInitialized: false;
readonly property int myUserId: tdLibWrapper.getUserInformation().id; readonly property int myUserId: tdLibWrapper.getUserInformation().id;
property var chatInformation; property var chatInformation;
property alias chatPicture: chatPictureThumbnail.photoData
property bool isPrivateChat: false; property bool isPrivateChat: false;
property bool isBasicGroup: false; property bool isBasicGroup: false;
property bool isSuperGroup: false; property bool isSuperGroup: false;
@ -353,6 +354,9 @@ Page {
chatPage.isInitialized = true; chatPage.isInitialized = true;
} }
break; break;
case PageStatus.Inactive:
chatModel.clear();
break;
} }
} }

View file

@ -237,7 +237,10 @@ Page {
ownUserId: overviewPage.ownUserId ownUserId: overviewPage.ownUserId
onClicked: { onClicked: {
pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { "chatInformation" : display }); pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), {
chatInformation : display,
chatPicture: photo_small
})
} }
Connections { Connections {

View file

@ -85,6 +85,23 @@ bool ChatModel::insertRows(int row, int count, const QModelIndex &parent)
return true; 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) void ChatModel::initialize(const QVariantMap &chatInformation)
{ {
LOG("Initializing chat model..."); LOG("Initializing chat model...");
@ -157,6 +174,11 @@ QVariantMap ChatModel::smallPhoto() const
return chatInformation.value(PHOTO).toMap().value(SMALL).toMap(); return chatInformation.value(PHOTO).toMap().value(SMALL).toMap();
} }
qlonglong ChatModel::getChatId() const
{
return chatId;
}
static bool compareMessages(const QVariant &message1, const QVariant &message2) static bool compareMessages(const QVariant &message1, const QVariant &message2)
{ {
const QVariantMap messageMap1 = message1.toMap(); const QVariantMap messageMap1 = message1.toMap();

View file

@ -36,14 +36,16 @@ public:
virtual QVariant data(const QModelIndex &index, int role) const override; virtual QVariant data(const QModelIndex &index, int role) const override;
virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) 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 initialize(const QVariantMap &chatInformation);
Q_INVOKABLE void triggerLoadMoreHistory(); Q_INVOKABLE void triggerLoadMoreHistory();
Q_INVOKABLE void triggerLoadMoreFuture(); Q_INVOKABLE void triggerLoadMoreFuture();
Q_INVOKABLE QVariantMap getChatInformation(); Q_INVOKABLE QVariantMap getChatInformation();
Q_INVOKABLE QVariantMap getMessage(int index); Q_INVOKABLE QVariantMap getMessage(int index);
Q_INVOKABLE int getLastReadMessageIndex(); Q_INVOKABLE int getLastReadMessageIndex();
QVariantMap smallPhoto() const; QVariantMap smallPhoto() const;
qlonglong getChatId() const;
signals: signals:
void messagesReceived(int modelIndex, int lastReadSentIndex, int totalCount); void messagesReceived(int modelIndex, int lastReadSentIndex, int totalCount);

View file

@ -73,7 +73,7 @@ int main(int argc, char *argv[])
ChatModel chatModel(tdLibWrapper); ChatModel chatModel(tdLibWrapper);
context->setContextProperty("chatModel", &chatModel); context->setContextProperty("chatModel", &chatModel);
NotificationManager notificationManager(tdLibWrapper, appSettings); NotificationManager notificationManager(tdLibWrapper, appSettings, &chatModel);
context->setContextProperty("notificationManager", &notificationManager); context->setContextProperty("notificationManager", &notificationManager);
ProcessLauncher processLauncher; ProcessLauncher processLauncher;

View file

@ -19,6 +19,7 @@
#include "notificationmanager.h" #include "notificationmanager.h"
#include "fernschreiberutils.h" #include "fernschreiberutils.h"
#include "chatmodel.h"
#include <sailfishapp.h> #include <sailfishapp.h>
#include <QDebug> #include <QDebug>
#include <QListIterator> #include <QListIterator>
@ -50,15 +51,17 @@ namespace {
const QString CHAT_TYPE_BASIC_GROUP("chatTypeBasicGroup"); const QString CHAT_TYPE_BASIC_GROUP("chatTypeBasicGroup");
const QString CHAT_TYPE_SUPERGROUP("chatTypeSupergroup"); const QString CHAT_TYPE_SUPERGROUP("chatTypeSupergroup");
const QString NOTIFICATION_CATEGORY("x-nemo.messaging.im");
const QString NGF_EVENT("chat");
const QString APP_NAME("Fernschreiber"); const QString APP_NAME("Fernschreiber");
// Notification hints // Notification hints
const QString HINT_GROUP_ID("x-fernschreiber.group_id"); // int const QString HINT_GROUP_ID("x-fernschreiber.group_id"); // int
const QString HINT_CHAT_ID("x-fernschreiber.chat_id"); // qlonglong const QString HINT_CHAT_ID("x-fernschreiber.chat_id"); // qlonglong
const QString HINT_TOTAL_COUNT("x-fernschreiber.total_count"); // int 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 class NotificationManager::ChatInfo
@ -116,30 +119,21 @@ NotificationManager::NotificationGroup::~NotificationGroup()
delete nemoNotification; 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()), mceInterface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request", QDBusConnection::systemBus()),
appIconFile(SailfishApp::pathTo("images/fernschreiber-notification.png").toLocalFile()) appIconFile(SailfishApp::pathTo("images/fernschreiber-notification.png").toLocalFile())
{ {
LOG("Initializing..."); LOG("Initializing...");
this->tdLibWrapper = tdLibWrapper; this->tdLibWrapper = tdLibWrapper;
this->appSettings = appSettings; 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(activeNotificationsUpdated(QVariantList)), this, SLOT(handleUpdateActiveNotifications(QVariantList)));
connect(this->tdLibWrapper, SIGNAL(notificationGroupUpdated(QVariantMap)), this, SLOT(handleUpdateNotificationGroup(QVariantMap))); connect(this->tdLibWrapper, SIGNAL(notificationGroupUpdated(QVariantMap)), this, SLOT(handleUpdateNotificationGroup(QVariantMap)));
connect(this->tdLibWrapper, SIGNAL(notificationUpdated(QVariantMap)), this, SLOT(handleUpdateNotification(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(newChatDiscovered(QString, QVariantMap)), this, SLOT(handleChatDiscovered(QString, QVariantMap)));
connect(this->tdLibWrapper, SIGNAL(chatTitleUpdated(QString, QString)), this, SLOT(handleChatTitleUpdated(QString, QString))); 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); this->controlLedNotification(false);
@ -236,6 +230,12 @@ void NotificationManager::updateNotificationGroup(int groupId, qlonglong chatId,
notificationGroup->notificationOrder.removeOne(removedId); 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 // Decide if we need a bzzz
switch (feedback) { switch (feedback) {
case AppSettings::NotificationFeedbackNone: case AppSettings::NotificationFeedbackNone:
@ -251,6 +251,7 @@ void NotificationManager::updateNotificationGroup(int groupId, qlonglong chatId,
} }
// Publish new or update the existing notification // Publish new or update the existing notification
LOG("Feedback" << needFeedback);
publishNotification(notificationGroup, needFeedback); publishNotification(notificationGroup, needFeedback);
} else if (notificationGroup) { } else if (notificationGroup) {
// No active notifications left in this group // 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) void NotificationManager::publishNotification(const NotificationGroup *notificationGroup, bool needFeedback)
{ {
QVariantMap messageMap; QVariantMap messageMap;
@ -374,25 +350,24 @@ void NotificationManager::publishNotification(const NotificationGroup *notificat
notificationBody = tr("%Ln unread messages", "", notificationGroup->totalCount); notificationBody = tr("%Ln unread messages", "", notificationGroup->totalCount);
} }
const QString summary(chatInformation ? chatInformation->title : QString());
nemoNotification->setBody(notificationBody); nemoNotification->setBody(notificationBody);
nemoNotification->setSummary(chatInformation ? chatInformation->title : QString()); nemoNotification->setSummary(summary);
if (needFeedback) { nemoNotification->setPreviewBody(notificationBody);
nemoNotification->setCategory(NOTIFICATION_CATEGORY); nemoNotification->setPreviewSummary(summary);
nemoNotification->setHintValue(HINT_VIBRA, needFeedback);
// Setting preview body & summary to a non-empty string causes a notification popup, // Don't show popup for the currently open chat
// no matter if we are in the current chat, in the app or not. That might be annoying if (!needFeedback || (chatModel->getChatId() == notificationGroup->chatId &&
// In the future, we can show this popup depending if the app/chat is open or not qGuiApp->applicationState() == Qt::ApplicationActive)) {
// nemoNotification->setHintValue(HINT_DISPLAY_ON, false);
// nemoNotification->setPreviewBody(nemoNotification->body()); nemoNotification->setHintValue(HINT_VISIBILITY, QVariant());
// nemoNotification->setPreviewSummary(nemoNotification->summary()); nemoNotification->setUrgency(Notification::Low);
nemoNotification->setPreviewBody(QString());
nemoNotification->setPreviewSummary(QString());
ngfClient->play(NGF_EVENT);
} else { } else {
nemoNotification->setCategory(QString()); // The "display on" option will be configurable
nemoNotification->setPreviewBody(QString()); nemoNotification->setHintValue(HINT_DISPLAY_ON, true);
nemoNotification->setPreviewSummary(QString()); nemoNotification->setHintValue(HINT_VISIBILITY, VISIBILITY_PUBLIC);
nemoNotification->setUrgency(Notification::Normal);
} }
nemoNotification->publish(); nemoNotification->publish();

View file

@ -23,10 +23,11 @@
#include <QObject> #include <QObject>
#include <QDBusInterface> #include <QDBusInterface>
#include <nemonotifications-qt5/notification.h> #include <nemonotifications-qt5/notification.h>
#include <ngf-qt5/NgfClient>
#include "tdlibwrapper.h" #include "tdlibwrapper.h"
#include "appsettings.h" #include "appsettings.h"
class ChatModel;
class NotificationManager : public QObject class NotificationManager : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -35,7 +36,7 @@ class NotificationManager : public QObject
public: public:
NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings); NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings, ChatModel *chatModel);
~NotificationManager() override; ~NotificationManager() override;
public slots: public slots:
@ -45,11 +46,6 @@ public slots:
void handleUpdateNotification(const QVariantMap &updatedNotification); void handleUpdateNotification(const QVariantMap &updatedNotification);
void handleChatDiscovered(const QString &chatId, const QVariantMap &chatInformation); void handleChatDiscovered(const QString &chatId, const QVariantMap &chatInformation);
void handleChatTitleUpdated(const QString &chatId, const QString &title); 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: private:
@ -65,7 +61,7 @@ private:
TDLibWrapper *tdLibWrapper; TDLibWrapper *tdLibWrapper;
AppSettings *appSettings; AppSettings *appSettings;
Ngf::Client *ngfClient; ChatModel *chatModel;
QMap<qlonglong,ChatInfo*> chatMap; QMap<qlonglong,ChatInfo*> chatMap;
QMap<int,NotificationGroup*> notificationGroups; QMap<int,NotificationGroup*> notificationGroups;
QDBusInterface mceInterface; QDBusInterface mceInterface;