2020-09-02 23:49:15 +03:00
|
|
|
/*
|
2020-10-19 20:34:47 +03:00
|
|
|
Copyright (C) 2020 Sebastian J. Wolf and other contributors
|
2020-09-02 23:49:15 +03:00
|
|
|
|
|
|
|
This file is part of Fernschreiber.
|
|
|
|
|
|
|
|
Fernschreiber is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Fernschreiber is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "notificationmanager.h"
|
2020-10-03 23:58:45 +03:00
|
|
|
#include "fernschreiberutils.h"
|
2020-09-04 00:20:46 +03:00
|
|
|
#include <nemonotifications-qt5/notification.h>
|
|
|
|
#include <sailfishapp.h>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QListIterator>
|
|
|
|
#include <QUrl>
|
2020-09-13 00:22:33 +03:00
|
|
|
#include <QDateTime>
|
2020-09-13 22:54:36 +03:00
|
|
|
#include <QDBusConnection>
|
2020-09-02 23:49:15 +03:00
|
|
|
|
2020-10-10 16:48:12 +03:00
|
|
|
#define LOG(x) qDebug() << "[NotificationManager]" << x
|
|
|
|
|
2020-10-28 02:58:41 +03:00
|
|
|
namespace {
|
|
|
|
const QString _TYPE("@type");
|
|
|
|
const QString TYPE("type");
|
|
|
|
const QString ID("id");
|
|
|
|
const QString CHAT_ID("chat_id");
|
|
|
|
const QString IS_SILENT("is_silent");
|
|
|
|
const QString IS_CHANNEL("is_channel");
|
|
|
|
const QString REPLACES_ID("replaces_id");
|
|
|
|
const QString TOTAL_COUNT("total_count");
|
|
|
|
const QString DATE("date");
|
|
|
|
const QString TITLE("title");
|
|
|
|
const QString CONTENT("content");
|
|
|
|
const QString MESSAGE("message");
|
|
|
|
const QString FIRST_NAME("first_name");
|
|
|
|
const QString LAST_NAME("last_name");
|
|
|
|
const QString SENDER_USER_ID("sender_user_id");
|
|
|
|
const QString NOTIFICATIONS("notifications");
|
|
|
|
const QString NOTIFICATION_GROUP_ID("notification_group_id");
|
|
|
|
const QString NOTIFICATION_SETTINGS_CHAT_ID("notification_settings_chat_id");
|
|
|
|
const QString ADDED_NOTIFICATIONS("added_notifications");
|
|
|
|
const QString REMOVED_NOTIFICATION_IDS("removed_notification_ids");
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2020-10-10 18:46:08 +03:00
|
|
|
NotificationManager::NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings) :
|
2020-10-28 02:58:41 +03:00
|
|
|
mceInterface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request", QDBusConnection::systemBus()),
|
|
|
|
appIconFile(SailfishApp::pathTo("images/fernschreiber-notification.png").toLocalFile())
|
2020-09-02 23:49:15 +03:00
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("Initializing...");
|
2020-09-02 23:49:15 +03:00
|
|
|
this->tdLibWrapper = tdLibWrapper;
|
2020-10-10 18:46:08 +03:00
|
|
|
this->appSettings = appSettings;
|
2020-09-13 22:54:36 +03:00
|
|
|
this->ngfClient = new Ngf::Client(this);
|
2020-09-02 23:49:15 +03:00
|
|
|
|
|
|
|
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)));
|
2020-09-03 00:05:09 +03:00
|
|
|
connect(this->tdLibWrapper, SIGNAL(newChatDiscovered(QString, QVariantMap)), this, SLOT(handleChatDiscovered(QString, QVariantMap)));
|
2020-09-13 22:54:36 +03:00
|
|
|
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()) {
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("NGF Client successfully initialized...");
|
2020-09-13 22:54:36 +03:00
|
|
|
} else {
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("Failed to initialize NGF Client...");
|
2020-09-13 22:54:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
this->controlLedNotification(false);
|
2020-09-02 23:49:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
NotificationManager::~NotificationManager()
|
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("Destroying myself...");
|
2020-09-02 23:49:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationManager::handleUpdateActiveNotifications(const QVariantList notificationGroups)
|
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("Received active notifications, number of groups:" << notificationGroups.size());
|
2020-09-02 23:49:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationManager::handleUpdateNotificationGroup(const QVariantMap notificationGroupUpdate)
|
|
|
|
{
|
2020-10-28 02:58:41 +03:00
|
|
|
const QString chatId = notificationGroupUpdate.value(CHAT_ID).toString();
|
|
|
|
const QString notificationGroupId = notificationGroupUpdate.value(NOTIFICATION_GROUP_ID).toString();
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("Received notification group update, group ID:" << notificationGroupId);
|
2020-09-04 00:20:46 +03:00
|
|
|
|
2020-10-28 02:58:41 +03:00
|
|
|
QVariantMap notificationGroup = this->notificationGroups.value(notificationGroupId).toMap();
|
|
|
|
notificationGroup.insert(TYPE, notificationGroupUpdate.value(TYPE));
|
|
|
|
notificationGroup.insert(CHAT_ID, chatId);
|
|
|
|
notificationGroup.insert(NOTIFICATION_GROUP_ID, notificationGroupId);
|
|
|
|
notificationGroup.insert(NOTIFICATION_SETTINGS_CHAT_ID, notificationGroupUpdate.value(NOTIFICATION_SETTINGS_CHAT_ID));
|
|
|
|
notificationGroup.insert(IS_SILENT, notificationGroupUpdate.value(IS_SILENT));
|
|
|
|
notificationGroup.insert(TOTAL_COUNT, notificationGroupUpdate.value(TOTAL_COUNT));
|
2020-09-04 00:20:46 +03:00
|
|
|
|
2020-10-28 02:58:41 +03:00
|
|
|
QVariantMap activeNotifications = notificationGroup.value(NOTIFICATIONS).toMap();
|
2020-09-09 00:44:57 +03:00
|
|
|
|
2020-10-28 02:58:41 +03:00
|
|
|
const QVariantList removedNotificationIds = notificationGroupUpdate.value(REMOVED_NOTIFICATION_IDS).toList();
|
2020-09-09 00:44:57 +03:00
|
|
|
QListIterator<QVariant> removedNotificationsIterator(removedNotificationIds);
|
|
|
|
while (removedNotificationsIterator.hasNext()) {
|
2020-10-28 02:58:41 +03:00
|
|
|
const QString removedNotificationId = removedNotificationsIterator.next().toString();
|
|
|
|
const QVariantMap notificationInformation = activeNotifications.value(removedNotificationId).toMap();
|
2020-09-09 00:44:57 +03:00
|
|
|
if (!notificationInformation.isEmpty()) {
|
|
|
|
this->removeNotification(notificationInformation);
|
|
|
|
activeNotifications.remove(removedNotificationId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-10 00:44:02 +03:00
|
|
|
// If we have deleted notifications, we need to update possibly existing ones
|
|
|
|
if (!removedNotificationIds.isEmpty() && !activeNotifications.isEmpty()) {
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("Some removals happend, but we have" << activeNotifications.size() << "existing notifications.");
|
2020-10-28 02:58:41 +03:00
|
|
|
const QVariantMap firstActiveNotification = activeNotifications.first().toMap();
|
|
|
|
activeNotifications.remove(firstActiveNotification.value(ID).toString());
|
2020-09-10 00:44:02 +03:00
|
|
|
QVariantMap newFirstActiveNotification = this->sendNotification(chatId, firstActiveNotification, activeNotifications);
|
|
|
|
QVariantMap newActiveNotifications;
|
|
|
|
QListIterator<QVariant> activeNotificationsIterator(activeNotifications.values());
|
|
|
|
while (activeNotificationsIterator.hasNext()) {
|
|
|
|
QVariantMap newActiveNotification = activeNotificationsIterator.next().toMap();
|
2020-10-28 02:58:41 +03:00
|
|
|
newActiveNotification.insert(REPLACES_ID, newFirstActiveNotification.value(REPLACES_ID));
|
|
|
|
newActiveNotifications.insert(newActiveNotification.value(ID).toString(), newActiveNotification);
|
2020-09-10 00:44:02 +03:00
|
|
|
}
|
2020-10-28 02:58:41 +03:00
|
|
|
newActiveNotifications.insert(newFirstActiveNotification.value(ID).toString(), newFirstActiveNotification);
|
2020-09-10 00:44:02 +03:00
|
|
|
activeNotifications = newActiveNotifications;
|
|
|
|
}
|
|
|
|
|
2020-09-13 22:54:36 +03:00
|
|
|
if (activeNotifications.isEmpty()) {
|
|
|
|
this->controlLedNotification(false);
|
|
|
|
}
|
|
|
|
|
2020-10-28 02:58:41 +03:00
|
|
|
const QVariantList addedNotifications = notificationGroupUpdate.value(ADDED_NOTIFICATIONS).toList();
|
2020-09-04 00:20:46 +03:00
|
|
|
QListIterator<QVariant> addedNotificationIterator(addedNotifications);
|
|
|
|
while (addedNotificationIterator.hasNext()) {
|
2020-10-28 02:58:41 +03:00
|
|
|
const QVariantMap addedNotification = addedNotificationIterator.next().toMap();
|
|
|
|
const QVariantMap activeNotification = this->sendNotification(chatId, addedNotification, activeNotifications);
|
|
|
|
activeNotifications.insert(activeNotification.value(ID).toString(), activeNotification);
|
2020-09-04 00:20:46 +03:00
|
|
|
}
|
2020-09-09 00:44:57 +03:00
|
|
|
|
2020-10-28 02:58:41 +03:00
|
|
|
notificationGroup.insert(NOTIFICATIONS, activeNotifications);
|
2020-09-04 00:20:46 +03:00
|
|
|
this->notificationGroups.insert(notificationGroupId, notificationGroup);
|
2020-09-02 23:49:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationManager::handleUpdateNotification(const QVariantMap updatedNotification)
|
|
|
|
{
|
2020-10-28 02:58:41 +03:00
|
|
|
LOG("Received notification update, group ID:" << updatedNotification.value(NOTIFICATION_GROUP_ID).toInt());
|
2020-09-02 23:49:15 +03:00
|
|
|
}
|
2020-09-03 00:05:09 +03:00
|
|
|
|
|
|
|
void NotificationManager::handleChatDiscovered(const QString &chatId, const QVariantMap &chatInformation)
|
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("Adding chat to internal map" << chatId);
|
2020-09-03 00:05:09 +03:00
|
|
|
this->chatMap.insert(chatId, chatInformation);
|
|
|
|
}
|
2020-09-04 00:20:46 +03:00
|
|
|
|
2020-10-28 02:36:14 +03:00
|
|
|
void NotificationManager::handleNgfConnectionStatus(bool connected)
|
2020-09-13 22:54:36 +03:00
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("NGF Daemon connection status changed" << connected);
|
2020-09-13 22:54:36 +03:00
|
|
|
}
|
|
|
|
|
2020-10-28 02:36:14 +03:00
|
|
|
void NotificationManager::handleNgfEventFailed(quint32 eventId)
|
2020-09-13 22:54:36 +03:00
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("NGF event failed, id:" << eventId);
|
2020-09-13 22:54:36 +03:00
|
|
|
}
|
|
|
|
|
2020-10-28 02:36:14 +03:00
|
|
|
void NotificationManager::handleNgfEventCompleted(quint32 eventId)
|
2020-09-13 22:54:36 +03:00
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("NGF event completed, id:" << eventId);
|
2020-09-13 22:54:36 +03:00
|
|
|
}
|
|
|
|
|
2020-10-28 02:36:14 +03:00
|
|
|
void NotificationManager::handleNgfEventPlaying(quint32 eventId)
|
2020-09-13 22:54:36 +03:00
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("NGF event playing, id:" << eventId);
|
2020-09-13 22:54:36 +03:00
|
|
|
}
|
|
|
|
|
2020-10-28 02:36:14 +03:00
|
|
|
void NotificationManager::handleNgfEventPaused(quint32 eventId)
|
2020-09-13 22:54:36 +03:00
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("NGF event paused, id:" << eventId);
|
2020-09-13 22:54:36 +03:00
|
|
|
}
|
|
|
|
|
2020-09-10 00:44:02 +03:00
|
|
|
QVariantMap NotificationManager::sendNotification(const QString &chatId, const QVariantMap ¬ificationInformation, const QVariantMap &activeNotifications)
|
2020-09-04 00:20:46 +03:00
|
|
|
{
|
2020-10-28 02:58:41 +03:00
|
|
|
LOG("Sending notification" << notificationInformation.value(ID).toString());
|
2020-09-09 00:44:57 +03:00
|
|
|
|
2020-10-28 02:58:41 +03:00
|
|
|
const QVariantMap chatInformation = this->chatMap.value(chatId).toMap();
|
|
|
|
const QVariantMap chatTypeInformation = chatInformation.value(TYPE).toMap();
|
|
|
|
const QString chatType = chatTypeInformation.value(_TYPE).toString();
|
|
|
|
const bool addAuthor = (chatType == CHAT_TYPE_BASIC_GROUP || ( chatType == CHAT_TYPE_SUPERGROUP && !chatTypeInformation.value(IS_CHANNEL).toBool() ));
|
2020-09-09 00:44:57 +03:00
|
|
|
|
2020-10-28 02:58:41 +03:00
|
|
|
const QVariantMap messageMap = notificationInformation.value(TYPE).toMap().value(MESSAGE).toMap();
|
2020-09-09 00:44:57 +03:00
|
|
|
Notification nemoNotification;
|
2020-10-28 02:58:41 +03:00
|
|
|
nemoNotification.setAppName(APP_NAME);
|
|
|
|
nemoNotification.setAppIcon(appIconFile);
|
|
|
|
nemoNotification.setSummary(chatInformation.value(TITLE).toString());
|
|
|
|
nemoNotification.setTimestamp(QDateTime::fromMSecsSinceEpoch(messageMap.value(DATE).toLongLong() * 1000));
|
2020-09-15 00:43:21 +03:00
|
|
|
QVariantList remoteActionArguments;
|
|
|
|
remoteActionArguments.append(chatId);
|
2020-10-28 02:58:41 +03:00
|
|
|
remoteActionArguments.append(messageMap.value(ID).toString());
|
2020-09-15 00:43:21 +03:00
|
|
|
nemoNotification.setRemoteAction(Notification::remoteAction("default", "openMessage", "de.ygriega.fernschreiber", "/de/ygriega/fernschreiber", "de.ygriega.fernschreiber", "openMessage", remoteActionArguments));
|
2020-10-10 18:46:08 +03:00
|
|
|
|
|
|
|
bool needFeedback;
|
|
|
|
const AppSettings::NotificationFeedback feedbackStyle = appSettings->notificationFeedback();
|
|
|
|
|
2020-09-10 00:44:02 +03:00
|
|
|
if (activeNotifications.isEmpty()) {
|
2020-09-13 00:22:33 +03:00
|
|
|
QString notificationBody;
|
|
|
|
if (addAuthor) {
|
2020-10-28 02:58:41 +03:00
|
|
|
const QVariantMap authorInformation = tdLibWrapper->getUserInformation(messageMap.value(SENDER_USER_ID).toString());
|
|
|
|
const QString firstName = authorInformation.value(FIRST_NAME).toString();
|
|
|
|
const QString lastName = authorInformation.value(LAST_NAME).toString();
|
|
|
|
const QString fullName = firstName + " " + lastName;
|
2020-09-13 00:22:33 +03:00
|
|
|
notificationBody = notificationBody + fullName.trimmed() + ": ";
|
|
|
|
}
|
2020-10-28 02:58:41 +03:00
|
|
|
notificationBody = notificationBody + this->getNotificationText(messageMap.value(CONTENT).toMap());
|
2020-09-13 00:22:33 +03:00
|
|
|
nemoNotification.setBody(notificationBody);
|
2020-10-10 18:46:08 +03:00
|
|
|
needFeedback = (feedbackStyle != AppSettings::NotificationFeedbackNone);
|
2020-09-10 00:44:02 +03:00
|
|
|
} else {
|
2020-10-28 02:58:41 +03:00
|
|
|
nemoNotification.setReplacesId(activeNotifications.first().toMap().value(REPLACES_ID).toUInt());
|
2020-09-10 00:44:02 +03:00
|
|
|
nemoNotification.setBody(tr("%1 unread messages").arg(activeNotifications.size() + 1));
|
2020-10-10 18:46:08 +03:00
|
|
|
needFeedback = (feedbackStyle == AppSettings::NotificationFeedbackAll);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needFeedback) {
|
2020-10-28 02:58:41 +03:00
|
|
|
nemoNotification.setCategory(NOTIFICATION_CATEGORY);
|
|
|
|
ngfClient->play(NGF_EVENT);
|
2020-09-10 00:44:02 +03:00
|
|
|
}
|
2020-09-09 00:44:57 +03:00
|
|
|
|
|
|
|
nemoNotification.publish();
|
2020-09-13 22:54:36 +03:00
|
|
|
this->controlLedNotification(true);
|
2020-10-28 02:58:41 +03:00
|
|
|
|
|
|
|
QVariantMap updatedNotificationInformation = notificationInformation;
|
|
|
|
updatedNotificationInformation.insert(REPLACES_ID, nemoNotification.replacesId());
|
2020-09-09 00:44:57 +03:00
|
|
|
return updatedNotificationInformation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationManager::removeNotification(const QVariantMap ¬ificationInformation)
|
|
|
|
{
|
2020-10-28 02:58:41 +03:00
|
|
|
LOG("Removing notification" << notificationInformation.value(ID).toString());
|
2020-09-09 00:44:57 +03:00
|
|
|
Notification nemoNotification;
|
2020-10-28 02:58:41 +03:00
|
|
|
nemoNotification.setReplacesId(notificationInformation.value(REPLACES_ID).toUInt());
|
2020-09-09 00:44:57 +03:00
|
|
|
nemoNotification.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString NotificationManager::getNotificationText(const QVariantMap ¬ificationContent)
|
|
|
|
{
|
2020-10-10 16:48:12 +03:00
|
|
|
LOG("Getting notification text from content" << notificationContent);
|
2020-09-13 00:22:33 +03:00
|
|
|
|
2020-10-03 23:58:45 +03:00
|
|
|
return FernschreiberUtils::getMessageShortText(notificationContent, false);
|
2020-09-04 00:20:46 +03:00
|
|
|
}
|
2020-09-13 22:54:36 +03:00
|
|
|
|
2020-10-28 02:36:14 +03:00
|
|
|
void NotificationManager::controlLedNotification(bool enabled)
|
2020-09-13 22:54:36 +03:00
|
|
|
{
|
2020-10-10 16:55:46 +03:00
|
|
|
static const QString PATTERN("PatternCommunicationIM");
|
|
|
|
static const QString ACTIVATE("req_led_pattern_activate");
|
|
|
|
static const QString DEACTIVATE("req_led_pattern_deactivate");
|
2020-09-13 22:54:36 +03:00
|
|
|
|
2020-10-10 16:55:46 +03:00
|
|
|
LOG("Controlling notification LED" << enabled);
|
|
|
|
mceInterface.call(enabled ? ACTIVATE : DEACTIVATE, PATTERN);
|
2020-09-13 22:54:36 +03:00
|
|
|
}
|