Merge pull request #80 from monich/notifications

Notification feedback control
This commit is contained in:
Sebastian Wolf 2020-10-18 17:36:34 +02:00 committed by GitHub
commit 7c261d1bde
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 133 additions and 44 deletions

View file

@ -18,9 +18,9 @@
*/ */
import QtQuick 2.0 import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import WerkWolf.Fernschreiber 1.0
import "../js/functions.js" as Functions import "../js/functions.js" as Functions
Page { Page {
id: settingsPage id: settingsPage
allowedOrientations: Orientation.All allowedOrientations: Orientation.All
@ -52,6 +52,57 @@ Page {
} }
} }
ComboBox {
id: feedbackComboBox
label: qsTr("Notification feedback")
description: qsTr("Non-graphical feedback adds vibration to visual notifications.")
menu: ContextMenu {
id: feedbackMenu
MenuItem {
readonly property int value: AppSettings.NotificationFeedbackAll
text: qsTr("All events")
onClicked: {
appSettings.notificationFeedback = value
}
}
MenuItem {
readonly property int value: AppSettings.NotificationFeedbackNew
text: qsTr("Only new events")
onClicked: {
appSettings.notificationFeedback = value
}
}
MenuItem {
readonly property int value: AppSettings.NotificationFeedbackNone
text: qsTr("None")
onClicked: {
appSettings.notificationFeedback = value
}
}
}
Component.onCompleted: updateFeedbackSelection()
function updateFeedbackSelection() {
var menuItems = feedbackMenu.children
var n = menuItems.length
for (var i=0; i<n; i++) {
if (menuItems[i].value === appSettings.notificationFeedback) {
currentIndex = i
return
}
}
}
Connections {
target: appSettings
onNotificationFeedbackChanged: {
feedbackComboBox.updateFeedbackSelection()
}
}
}
SectionHeader { SectionHeader {
text: qsTr("Appearance") text: qsTr("Appearance")
} }

View file

@ -23,6 +23,7 @@
namespace { namespace {
const QString KEY_SEND_BY_ENTER("sendByEnter"); const QString KEY_SEND_BY_ENTER("sendByEnter");
const QString KEY_SHOW_STICKERS_AS_IMAGES("showStickersAsImages"); const QString KEY_SHOW_STICKERS_AS_IMAGES("showStickersAsImages");
const QString KEY_NOTIFICATION_FEEDBACK("notificationFeedback");
} }
AppSettings::AppSettings(QObject *parent) : QObject(parent), settings("harbour-fernschreiber", "settings") AppSettings::AppSettings(QObject *parent) : QObject(parent), settings("harbour-fernschreiber", "settings")
@ -56,3 +57,17 @@ void AppSettings::setShowStickersAsImages(bool showAsImages)
emit showStickersAsImagesChanged(); emit showStickersAsImagesChanged();
} }
} }
AppSettings::NotificationFeedback AppSettings::notificationFeedback() const
{
return (NotificationFeedback) settings.value(KEY_NOTIFICATION_FEEDBACK, (int) NotificationFeedbackAll).toInt();
}
void AppSettings::setNotificationFeedback(NotificationFeedback feedback)
{
if (notificationFeedback() != feedback) {
LOG(KEY_NOTIFICATION_FEEDBACK << feedback);
settings.setValue(KEY_NOTIFICATION_FEEDBACK, (int) feedback);
emit notificationFeedbackChanged();
}
}

View file

@ -25,6 +25,15 @@ class AppSettings : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool sendByEnter READ getSendByEnter WRITE setSendByEnter NOTIFY sendByEnterChanged) Q_PROPERTY(bool sendByEnter READ getSendByEnter WRITE setSendByEnter NOTIFY sendByEnterChanged)
Q_PROPERTY(bool showStickersAsImages READ showStickersAsImages WRITE setShowStickersAsImages NOTIFY showStickersAsImagesChanged) Q_PROPERTY(bool showStickersAsImages READ showStickersAsImages WRITE setShowStickersAsImages NOTIFY showStickersAsImagesChanged)
Q_PROPERTY(NotificationFeedback notificationFeedback READ notificationFeedback WRITE setNotificationFeedback NOTIFY notificationFeedbackChanged)
public:
enum NotificationFeedback {
NotificationFeedbackNone,
NotificationFeedbackNew,
NotificationFeedbackAll
};
Q_ENUM(NotificationFeedback)
public: public:
AppSettings(QObject *parent = Q_NULLPTR); AppSettings(QObject *parent = Q_NULLPTR);
@ -35,9 +44,13 @@ public:
bool showStickersAsImages() const; bool showStickersAsImages() const;
void setShowStickersAsImages(bool showAsImages); void setShowStickersAsImages(bool showAsImages);
NotificationFeedback notificationFeedback() const;
void setNotificationFeedback(NotificationFeedback feedback);
signals: signals:
void sendByEnterChanged(); void sendByEnterChanged();
void showStickersAsImagesChanged(); void showStickersAsImagesChanged();
void notificationFeedbackChanged();
private: private:
QSettings settings; QSettings settings;

View file

@ -47,10 +47,11 @@ int main(int argc, char *argv[])
AppSettings *appSettings = new AppSettings(view.data()); AppSettings *appSettings = new AppSettings(view.data());
context->setContextProperty("appSettings", appSettings); context->setContextProperty("appSettings", appSettings);
qmlRegisterUncreatableType<AppSettings>("WerkWolf.Fernschreiber", 1, 0, "AppSettings", QString());
TDLibWrapper *tdLibWrapper = new TDLibWrapper(view.data()); TDLibWrapper *tdLibWrapper = new TDLibWrapper(view.data());
context->setContextProperty("tdLibWrapper", tdLibWrapper); context->setContextProperty("tdLibWrapper", tdLibWrapper);
qmlRegisterType<TDLibWrapper>("WerkWolf.Fernschreiber", 1, 0, "TelegramAPI"); qmlRegisterUncreatableType<TDLibWrapper>("WerkWolf.Fernschreiber", 1, 0, "TelegramAPI", QString());
DBusAdaptor *dBusAdaptor = tdLibWrapper->getDBusAdaptor(); DBusAdaptor *dBusAdaptor = tdLibWrapper->getDBusAdaptor();
context->setContextProperty("dBusAdaptor", dBusAdaptor); context->setContextProperty("dBusAdaptor", dBusAdaptor);
@ -61,7 +62,7 @@ int main(int argc, char *argv[])
ChatModel chatModel(tdLibWrapper); ChatModel chatModel(tdLibWrapper);
context->setContextProperty("chatModel", &chatModel); context->setContextProperty("chatModel", &chatModel);
NotificationManager notificationManager(tdLibWrapper); NotificationManager notificationManager(tdLibWrapper, appSettings);
context->setContextProperty("notificationManager", &notificationManager); context->setContextProperty("notificationManager", &notificationManager);
ProcessLauncher processLauncher; ProcessLauncher processLauncher;

View file

@ -26,12 +26,15 @@
#include <QUrl> #include <QUrl>
#include <QDateTime> #include <QDateTime>
#include <QDBusConnection> #include <QDBusConnection>
#include <QDBusInterface>
NotificationManager::NotificationManager(TDLibWrapper *tdLibWrapper, QObject *parent) : QObject(parent) #define LOG(x) qDebug() << "[NotificationManager]" << x
NotificationManager::NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings) :
mceInterface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request", QDBusConnection::systemBus())
{ {
qDebug() << "[NotificationManager] Initializing..."; LOG("Initializing...");
this->tdLibWrapper = tdLibWrapper; this->tdLibWrapper = tdLibWrapper;
this->appSettings = appSettings;
this->ngfClient = new Ngf::Client(this); this->ngfClient = new Ngf::Client(this);
connect(this->tdLibWrapper, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SLOT(handleUpdateActiveNotifications(QVariantList))); connect(this->tdLibWrapper, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SLOT(handleUpdateActiveNotifications(QVariantList)));
@ -44,29 +47,28 @@ NotificationManager::NotificationManager(TDLibWrapper *tdLibWrapper, QObject *pa
connect(this->ngfClient, SIGNAL(eventPlaying(quint32)), this, SLOT(handleNgfEventPlaying(quint32))); connect(this->ngfClient, SIGNAL(eventPlaying(quint32)), this, SLOT(handleNgfEventPlaying(quint32)));
if (this->ngfClient->connect()) { if (this->ngfClient->connect()) {
qDebug() << "[NotificationManager] NGF Client successfully initialized..."; LOG("NGF Client successfully initialized...");
} else { } else {
qDebug() << "[NotificationManager] Failed to initialize NGF Client..."; LOG("Failed to initialize NGF Client...");
} }
this->controlLedNotification(false); this->controlLedNotification(false);
} }
NotificationManager::~NotificationManager() NotificationManager::~NotificationManager()
{ {
qDebug() << "[NotificationManager] Destroying myself..."; LOG("Destroying myself...");
} }
void NotificationManager::handleUpdateActiveNotifications(const QVariantList notificationGroups) void NotificationManager::handleUpdateActiveNotifications(const QVariantList notificationGroups)
{ {
qDebug() << "[NotificationManager] Received active notifications, number of groups:" << notificationGroups.size(); LOG("Received active notifications, number of groups:" << notificationGroups.size());
} }
void NotificationManager::handleUpdateNotificationGroup(const QVariantMap notificationGroupUpdate) void NotificationManager::handleUpdateNotificationGroup(const QVariantMap notificationGroupUpdate)
{ {
QString notificationGroupId = notificationGroupUpdate.value("notification_group_id").toString(); QString notificationGroupId = notificationGroupUpdate.value("notification_group_id").toString();
qDebug() << "[NotificationManager] Received notification group update, group ID:" << notificationGroupId; LOG("Received notification group update, group ID:" << notificationGroupId);
QVariantMap notificationGroup = this->notificationGroups.value(notificationGroupId).toMap(); QVariantMap notificationGroup = this->notificationGroups.value(notificationGroupId).toMap();
QString chatId = notificationGroupUpdate.value("chat_id").toString(); QString chatId = notificationGroupUpdate.value("chat_id").toString();
@ -92,7 +94,7 @@ void NotificationManager::handleUpdateNotificationGroup(const QVariantMap notifi
// If we have deleted notifications, we need to update possibly existing ones // If we have deleted notifications, we need to update possibly existing ones
if (!removedNotificationIds.isEmpty() && !activeNotifications.isEmpty()) { if (!removedNotificationIds.isEmpty() && !activeNotifications.isEmpty()) {
qDebug() << "[NotificationManager] Some removals happend, but we have " << activeNotifications.size() << "existing notifications."; LOG("Some removals happend, but we have" << activeNotifications.size() << "existing notifications.");
QVariantMap firstActiveNotification = activeNotifications.first().toMap(); QVariantMap firstActiveNotification = activeNotifications.first().toMap();
activeNotifications.remove(firstActiveNotification.value("id").toString()); activeNotifications.remove(firstActiveNotification.value("id").toString());
QVariantMap newFirstActiveNotification = this->sendNotification(chatId, firstActiveNotification, activeNotifications); QVariantMap newFirstActiveNotification = this->sendNotification(chatId, firstActiveNotification, activeNotifications);
@ -125,45 +127,43 @@ void NotificationManager::handleUpdateNotificationGroup(const QVariantMap notifi
void NotificationManager::handleUpdateNotification(const QVariantMap updatedNotification) void NotificationManager::handleUpdateNotification(const QVariantMap updatedNotification)
{ {
qDebug() << "[NotificationManager] Received notification update, group ID:" << updatedNotification.value("notification_group_id").toInt(); LOG("Received notification update, group ID:" << updatedNotification.value("notification_group_id").toInt());
} }
void NotificationManager::handleChatDiscovered(const QString &chatId, const QVariantMap &chatInformation) void NotificationManager::handleChatDiscovered(const QString &chatId, const QVariantMap &chatInformation)
{ {
this->chatListMutex.lock(); LOG("Adding chat to internal map" << chatId);
qDebug() << "[NotificationManager] Adding chat to internal map " << chatId;
this->chatMap.insert(chatId, chatInformation); this->chatMap.insert(chatId, chatInformation);
this->chatListMutex.unlock();
} }
void NotificationManager::handleNgfConnectionStatus(const bool &connected) void NotificationManager::handleNgfConnectionStatus(const bool &connected)
{ {
qDebug() << "[NotificationManager] NGF Daemon connection status changed " << connected; LOG("NGF Daemon connection status changed" << connected);
} }
void NotificationManager::handleNgfEventFailed(const quint32 &eventId) void NotificationManager::handleNgfEventFailed(const quint32 &eventId)
{ {
qDebug() << "[NotificationManager] NGF event failed, id: " << eventId; LOG("NGF event failed, id:" << eventId);
} }
void NotificationManager::handleNgfEventCompleted(const quint32 &eventId) void NotificationManager::handleNgfEventCompleted(const quint32 &eventId)
{ {
qDebug() << "[NotificationManager] NGF event completed, id: " << eventId; LOG("NGF event completed, id:" << eventId);
} }
void NotificationManager::handleNgfEventPlaying(const quint32 &eventId) void NotificationManager::handleNgfEventPlaying(const quint32 &eventId)
{ {
qDebug() << "[NotificationManager] NGF event playing, id: " << eventId; LOG("NGF event playing, id:" << eventId);
} }
void NotificationManager::handleNgfEventPaused(const quint32 &eventId) void NotificationManager::handleNgfEventPaused(const quint32 &eventId)
{ {
qDebug() << "[NotificationManager] NGF event paused, id: " << eventId; LOG("NGF event paused, id:" << eventId);
} }
QVariantMap NotificationManager::sendNotification(const QString &chatId, const QVariantMap &notificationInformation, const QVariantMap &activeNotifications) QVariantMap NotificationManager::sendNotification(const QString &chatId, const QVariantMap &notificationInformation, const QVariantMap &activeNotifications)
{ {
qDebug() << "[NotificationManager] Sending notification" << notificationInformation.value("id").toString(); LOG("Sending notification" << notificationInformation.value("id").toString());
QVariantMap chatInformation = this->chatMap.value(chatId).toMap(); QVariantMap chatInformation = this->chatMap.value(chatId).toMap();
QString chatType = chatInformation.value("type").toMap().value("@type").toString(); QString chatType = chatInformation.value("type").toMap().value("@type").toString();
@ -179,12 +179,15 @@ QVariantMap NotificationManager::sendNotification(const QString &chatId, const Q
nemoNotification.setAppName("Fernschreiber"); nemoNotification.setAppName("Fernschreiber");
nemoNotification.setAppIcon(appIconUrl.toLocalFile()); nemoNotification.setAppIcon(appIconUrl.toLocalFile());
nemoNotification.setSummary(chatInformation.value("title").toString()); nemoNotification.setSummary(chatInformation.value("title").toString());
nemoNotification.setCategory("x-nemo.messaging.im");
nemoNotification.setTimestamp(QDateTime::fromMSecsSinceEpoch(messageMap.value("date").toLongLong() * 1000)); nemoNotification.setTimestamp(QDateTime::fromMSecsSinceEpoch(messageMap.value("date").toLongLong() * 1000));
QVariantList remoteActionArguments; QVariantList remoteActionArguments;
remoteActionArguments.append(chatId); remoteActionArguments.append(chatId);
remoteActionArguments.append(messageMap.value("id").toString()); remoteActionArguments.append(messageMap.value("id").toString());
nemoNotification.setRemoteAction(Notification::remoteAction("default", "openMessage", "de.ygriega.fernschreiber", "/de/ygriega/fernschreiber", "de.ygriega.fernschreiber", "openMessage", remoteActionArguments)); nemoNotification.setRemoteAction(Notification::remoteAction("default", "openMessage", "de.ygriega.fernschreiber", "/de/ygriega/fernschreiber", "de.ygriega.fernschreiber", "openMessage", remoteActionArguments));
bool needFeedback;
const AppSettings::NotificationFeedback feedbackStyle = appSettings->notificationFeedback();
if (activeNotifications.isEmpty()) { if (activeNotifications.isEmpty()) {
QString notificationBody; QString notificationBody;
if (addAuthor) { if (addAuthor) {
@ -196,13 +199,19 @@ QVariantMap NotificationManager::sendNotification(const QString &chatId, const Q
} }
notificationBody = notificationBody + this->getNotificationText(messageMap.value("content").toMap()); notificationBody = notificationBody + this->getNotificationText(messageMap.value("content").toMap());
nemoNotification.setBody(notificationBody); nemoNotification.setBody(notificationBody);
needFeedback = (feedbackStyle != AppSettings::NotificationFeedbackNone);
} else { } else {
nemoNotification.setReplacesId(activeNotifications.first().toMap().value("replaces_id").toUInt()); nemoNotification.setReplacesId(activeNotifications.first().toMap().value("replaces_id").toUInt());
nemoNotification.setBody(tr("%1 unread messages").arg(activeNotifications.size() + 1)); nemoNotification.setBody(tr("%1 unread messages").arg(activeNotifications.size() + 1));
needFeedback = (feedbackStyle == AppSettings::NotificationFeedbackAll);
}
if (needFeedback) {
nemoNotification.setCategory("x-nemo.messaging.im");
ngfClient->play("chat");
} }
nemoNotification.publish(); nemoNotification.publish();
this->ngfClient->play("chat");
this->controlLedNotification(true); this->controlLedNotification(true);
updatedNotificationInformation.insert("replaces_id", nemoNotification.replacesId()); updatedNotificationInformation.insert("replaces_id", nemoNotification.replacesId());
return updatedNotificationInformation; return updatedNotificationInformation;
@ -210,7 +219,7 @@ QVariantMap NotificationManager::sendNotification(const QString &chatId, const Q
void NotificationManager::removeNotification(const QVariantMap &notificationInformation) void NotificationManager::removeNotification(const QVariantMap &notificationInformation)
{ {
qDebug() << "[NotificationManager] Removing notification" << notificationInformation.value("id").toString(); LOG("Removing notification" << notificationInformation.value("id").toString());
Notification nemoNotification; Notification nemoNotification;
nemoNotification.setReplacesId(notificationInformation.value("replaces_id").toUInt()); nemoNotification.setReplacesId(notificationInformation.value("replaces_id").toUInt());
nemoNotification.close(); nemoNotification.close();
@ -218,21 +227,17 @@ void NotificationManager::removeNotification(const QVariantMap &notificationInfo
QString NotificationManager::getNotificationText(const QVariantMap &notificationContent) QString NotificationManager::getNotificationText(const QVariantMap &notificationContent)
{ {
qDebug() << "[NotificationManager] Getting notification text from content" << notificationContent; LOG("Getting notification text from content" << notificationContent);
return FernschreiberUtils::getMessageShortText(notificationContent, false); return FernschreiberUtils::getMessageShortText(notificationContent, false);
} }
void NotificationManager::controlLedNotification(const bool &enabled) void NotificationManager::controlLedNotification(const bool &enabled)
{ {
qDebug() << "[NotificationManager] Controlling notification LED" << enabled; static const QString PATTERN("PatternCommunicationIM");
QDBusConnection dbusConnection = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "system"); static const QString ACTIVATE("req_led_pattern_activate");
QDBusInterface dbusInterface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request", dbusConnection); static const QString DEACTIVATE("req_led_pattern_deactivate");
if (enabled) {
dbusInterface.call("req_led_pattern_activate", "PatternCommunicationIM");
} else {
dbusInterface.call("req_led_pattern_deactivate", "PatternCommunicationIM");
}
LOG("Controlling notification LED" << enabled);
mceInterface.call(enabled ? ACTIVATE : DEACTIVATE, PATTERN);
} }

View file

@ -21,15 +21,16 @@
#define NOTIFICATIONMANAGER_H #define NOTIFICATIONMANAGER_H
#include <QObject> #include <QObject>
#include <QMutex> #include <QDBusInterface>
#include <ngf-qt5/NgfClient> #include <ngf-qt5/NgfClient>
#include "tdlibwrapper.h" #include "tdlibwrapper.h"
#include "appsettings.h"
class NotificationManager : public QObject class NotificationManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit NotificationManager(TDLibWrapper *tdLibWrapper, QObject *parent = nullptr); NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings);
~NotificationManager() override; ~NotificationManager() override;
signals: signals:
@ -48,17 +49,20 @@ public slots:
private: private:
TDLibWrapper *tdLibWrapper;
Ngf::Client *ngfClient;
QVariantMap chatMap;
QVariantMap notificationGroups;
QMutex chatListMutex;
QVariantMap sendNotification(const QString &chatId, const QVariantMap &notificationInformation, const QVariantMap &activeNotifications); QVariantMap sendNotification(const QString &chatId, const QVariantMap &notificationInformation, const QVariantMap &activeNotifications);
void removeNotification(const QVariantMap &notificationInformation); void removeNotification(const QVariantMap &notificationInformation);
QString getNotificationText(const QVariantMap &notificationContent); QString getNotificationText(const QVariantMap &notificationContent);
void controlLedNotification(const bool &enabled); void controlLedNotification(const bool &enabled);
private:
TDLibWrapper *tdLibWrapper;
AppSettings *appSettings;
Ngf::Client *ngfClient;
QVariantMap chatMap;
QVariantMap notificationGroups;
QDBusInterface mceInterface;
}; };
#endif // NOTIFICATIONMANAGER_H #endif // NOTIFICATIONMANAGER_H