/
NeoChapay
/
telegraf
Обзор
Документация
Войти
/
NeoChapay
/
telegraf
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
src/notificationmanager.cpp
389 строк
17 KB
mbarashkov
Исправлены ещё предупреждения по коду
28 дек 2024, 19:58
28 дек 2024, 19:58
aeaf2a9
Код
Авторство
О чём код?
#include "notificationmanager.h" #include "telegrafutils.h" #include "chatmodel.h" #include <auroraapp.h> #include <QListIterator> #include <QUrl> #include <QDateTime> #include <QDBusConnection> #include <QGuiApplication> #define DEBUG_MODULE NotificationManager #include "debuglog.h" namespace { const char _TYPE[] = "@type"; const char TYPE[] = "type"; const char ID[] = "id"; const char CHAT_ID[] = "chat_id"; const char IS_CHANNEL[] = "is_channel"; const char TOTAL_COUNT[] = "total_count"; const char DATE[] = "date"; const char TITLE[] = "title"; const char CONTENT[] = "content"; const char MESSAGE[] = "message"; //const char FIRST_NAME[] = "first_name"; //const char LAST_NAME[] = "last_name"; const char SENDER_ID[] = "sender_id"; const char USER_ID[] = "user_id"; const char NOTIFICATIONS[] = "notifications"; const char NOTIFICATION_GROUP_ID[] = "notification_group_id"; const char ADDED_NOTIFICATIONS[] = "added_notifications"; const char REMOVED_NOTIFICATION_IDS[] = "removed_notification_ids"; //const char CHAT_TYPE_BASIC_GROUP[] = "chatTypeBasicGroup"; //const char CHAT_TYPE_SUPERGROUP[] = "chatTypeSupergroup"; const char APP_NAME[] = "Telegraf"; // Notification hints const char HINT_GROUP_ID[] = "x-telegraf.group_id"; // int const char HINT_CHAT_ID[] = "x-telegraf.chat_id"; // qlonglong const char HINT_TOTAL_COUNT[] = "x-telegraf.total_count"; // int const char HINT_IMAGE_PATH[] = "image-path"; // QString const char HINT_VIBRA[] = "x-nemo-vibrate"; // bool const char HINT_SUPPRESS_SOUND[] = "suppress-sound"; // bool const char HINT_DISPLAY_ON[] = "x-nemo-display-on"; // bool const char HINT_VISIBILITY[] = "x-nemo-visibility"; // QString const char HINT_FEEDBACK[] = "x-nemo-feedback"; // QString const char HINT_PRIORITY[] = "x-nemo-priority"; // int const char VISIBILITY_PUBLIC[] = "public"; } class NotificationManager::ChatInfo { public: ChatInfo(const QVariantMap &info); void setChatInfo(const QVariantMap &info); public: TDLibWrapper::ChatType type; bool isChannel; QString title; }; NotificationManager::ChatInfo::ChatInfo(const QVariantMap &chatInfo) { setChatInfo(chatInfo); } void NotificationManager::ChatInfo::setChatInfo(const QVariantMap &chatInfo) { const QVariantMap chatTypeInformation = chatInfo.value(TYPE).toMap(); type = TDLibWrapper::chatTypeFromString(chatTypeInformation.value(_TYPE).toString()); isChannel = chatTypeInformation.value(IS_CHANNEL).toBool(); title = chatInfo.value(TITLE).toString(); } class NotificationManager::NotificationGroup { public: NotificationGroup(int groupId, qlonglong chatId, int count, Notification *notification); NotificationGroup(Notification *notification); ~NotificationGroup(); public: int notificationGroupId; qlonglong chatId; int totalCount; Notification *nemoNotification; QMap<int,QVariantMap> activeNotifications; QList<int> notificationOrder; }; NotificationManager::NotificationGroup::NotificationGroup(int group, qlonglong chat, int count, Notification *notification) : notificationGroupId(group), chatId(chat), totalCount(count), nemoNotification(notification) { } NotificationManager::NotificationGroup::~NotificationGroup() { delete nemoNotification; } NotificationManager::NotificationManager(TDLibWrapper *tdLibWrapper, AppSettings *appSettings, MceInterface *mceInterface, ChatModel *chatModel) : appIconFile(Aurora::Application::pathTo("images/telegraf-notification.png").toLocalFile()) { LOG("Initializing..."); this->tdLibWrapper = tdLibWrapper; this->appSettings = appSettings; this->mceInterface = mceInterface; 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))); this->controlLedNotification(false); // Restore notifications QList<QObject*> notifications = Notification::notifications(); const int n = notifications.count(); LOG("Found" << n << "existing notifications"); for (int i = 0; i < n; i++) { QObject *notificationObject = notifications.at(i); Notification *notification = qobject_cast<Notification *>(notificationObject); if (notification) { bool groupOk, chatOk, countOk; const int groupId = notification->hintValue(HINT_GROUP_ID).toInt(&groupOk); const qlonglong chatId = notification->hintValue(HINT_CHAT_ID).toLongLong(&chatOk); const int totalCount = notification->hintValue(HINT_TOTAL_COUNT).toInt(&countOk); if (groupOk && chatOk && countOk && !notificationGroups.contains(groupId)) { LOG("Restoring notification group" << groupId << "chatId" << chatId << "count" << totalCount); notificationGroups.insert(groupId, new NotificationGroup(groupId, chatId, totalCount, notification)); continue; } } delete notificationObject; } } NotificationManager::~NotificationManager() { LOG("Destroying myself..."); qDeleteAll(chatMap); qDeleteAll(notificationGroups); } void NotificationManager::handleUpdateActiveNotifications(const QVariantList ¬ificationGroups) { const int n = notificationGroups.size(); LOG("Received active notifications, number of groups:" << n); for (int i = 0; i < n; i++) { const QVariantMap notificationGroupInfo(notificationGroups.at(i).toMap()); updateNotificationGroup(notificationGroupInfo.value(ID).toInt(), notificationGroupInfo.value(CHAT_ID).toLongLong(), notificationGroupInfo.value(TOTAL_COUNT).toInt(), notificationGroupInfo.value(NOTIFICATIONS).toList()); } } void NotificationManager::handleUpdateNotificationGroup(const QVariantMap ¬ificationGroupUpdate) { const int notificationGroupId = notificationGroupUpdate.value(NOTIFICATION_GROUP_ID).toInt(); const int totalCount = notificationGroupUpdate.value(TOTAL_COUNT).toInt(); LOG("Received notification group update, group ID:" << notificationGroupId << "total count" << totalCount); updateNotificationGroup(notificationGroupId, notificationGroupUpdate.value(CHAT_ID).toLongLong(), totalCount, notificationGroupUpdate.value(ADDED_NOTIFICATIONS).toList(), notificationGroupUpdate.value(REMOVED_NOTIFICATION_IDS).toList(), appSettings->notificationFeedback()); } void NotificationManager::updateNotificationGroup(int groupId, qlonglong chatId, int totalCount, const QVariantList &addedNotifications, const QVariantList & removedNotificationIds, AppSettings::NotificationFeedback feedback) { bool needFeedback = false; NotificationGroup* notificationGroup = notificationGroups.value(groupId); LOG("Received notification group update, group ID:" << groupId << "total count" << totalCount); if (totalCount) { if (notificationGroup) { // Notification group already exists notificationGroup->totalCount = totalCount; } else { // New notification Notification *notification = new Notification(this); notification->setCategory("x-nemo.messaging.im"); notification->setAppName(APP_NAME); notification->setAppIcon(appIconFile); notification->setIcon(appIconFile); notification->setHintValue(HINT_GROUP_ID, groupId); notification->setHintValue(HINT_CHAT_ID, chatId); notification->setHintValue(HINT_TOTAL_COUNT, totalCount); notification->setHintValue(HINT_FEEDBACK, "chat_exists"); notification->setHintValue(HINT_PRIORITY, 120); notificationGroups.insert(groupId, notificationGroup = new NotificationGroup(groupId, chatId, totalCount, notification)); } QListIterator<QVariant> addedNotificationIterator(addedNotifications); while (addedNotificationIterator.hasNext()) { const QVariantMap addedNotification = addedNotificationIterator.next().toMap(); const int addedId = addedNotification.value(ID).toInt(); notificationGroup->activeNotifications.insert(addedId, addedNotification); notificationGroup->notificationOrder.append(addedId); } QListIterator<QVariant> removedNotificationIdsIterator(removedNotificationIds); while (removedNotificationIdsIterator.hasNext()) { const int removedId = removedNotificationIdsIterator.next().toInt(); notificationGroup->activeNotifications.remove(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 switch (feedback) { case AppSettings::NotificationFeedbackNone: break; case AppSettings::NotificationFeedbackNew: // Non-zero replacesId means that notification has already been published needFeedback = !notificationGroup->nemoNotification->replacesId(); break; case AppSettings::NotificationFeedbackAll: // Even in this case don't alert the user just about removals needFeedback = !addedNotifications.isEmpty(); break; } // Publish new or update the existing notification LOG("Feedback" << needFeedback); publishNotification(notificationGroup, needFeedback); } else if (notificationGroup) { // No active notifications left in this group notificationGroup->nemoNotification->close(); notificationGroups.remove(groupId); delete notificationGroup; } if (notificationGroups.isEmpty()) { // No active notifications left at all controlLedNotification(false); } else if (needFeedback) { controlLedNotification(true); } } void NotificationManager::handleUpdateNotification(const QVariantMap&) { LOG("Received notification update, group ID:" << updatedNotification.value(NOTIFICATION_GROUP_ID).toInt()); } void NotificationManager::handleChatDiscovered(const QString &chatId, const QVariantMap &chatInformation) { const qlonglong id = chatId.toLongLong(); ChatInfo *chat = chatMap.value(id); if (chat) { chat->setChatInfo(chatInformation); LOG("Updated chat information" << id << chat->title); } else { chat = new ChatInfo(chatInformation); chatMap.insert(id, chat); LOG("New chat" << id << chat->title); } } void NotificationManager::handleChatTitleUpdated(const QString &chatId, const QString &title) { const qlonglong id = chatId.toLongLong(); ChatInfo *chat = chatMap.value(id); if (chat) { LOG("Chat" << id << "title changed to" << title); chat->title = title; // Silently update notification summary QListIterator<NotificationGroup*> groupsIterator(notificationGroups.values()); while (groupsIterator.hasNext()) { const NotificationGroup *group = groupsIterator.next(); if (group->chatId == id) { LOG("Updating summary for group ID" << group->notificationGroupId); publishNotification(group, false); break; } } } } void NotificationManager::publishNotification(const NotificationGroup *notificationGroup, bool needFeedback) { QVariantMap messageMap; const ChatInfo *chatInformation = chatMap.value(notificationGroup->chatId); if (!notificationGroup->notificationOrder.isEmpty()) { const int lastNotificationId = notificationGroup->notificationOrder.last(); const QVariantMap lastNotification(notificationGroup->activeNotifications.value(lastNotificationId)); messageMap = lastNotification.value(TYPE).toMap().value(MESSAGE).toMap(); } Notification *nemoNotification = notificationGroup->nemoNotification; if (!messageMap.isEmpty()) { nemoNotification->setTimestamp(QDateTime::fromMSecsSinceEpoch(messageMap.value(DATE).toLongLong() * 1000)); QVariantList remoteActionArguments; remoteActionArguments.append(QString::number(notificationGroup->chatId)); remoteActionArguments.append(messageMap.value(ID).toString()); nemoNotification->setRemoteAction(Notification::remoteAction("default", "openMessage", "ru.telegrafaurora.telegraf", "/ru/telegrafaurora/telegraf", "ru.telegrafaurora.telegraf", "openMessage", remoteActionArguments)); } QString notificationBody; const QVariantMap senderInformation = messageMap.value(SENDER_ID).toMap(); bool outputMessageCount = notificationGroup->totalCount > 1; bool messageIsEmpty = messageMap.isEmpty(); if (outputMessageCount || messageIsEmpty) { // Either we have more than one notification or we have no content to display LOG("Group" << notificationGroup->notificationGroupId << "has" << notificationGroup->totalCount << "notifications"); notificationBody = tr("%Ln unread messages", "", notificationGroup->totalCount); } if ((!outputMessageCount || appSettings->notificationAlwaysShowPreview()) && !messageIsEmpty) { LOG("Group" << notificationGroup->notificationGroupId << "has 1 notification"); if (outputMessageCount) { notificationBody += "; "; } if (chatInformation && (chatInformation->type == TDLibWrapper::ChatTypeBasicGroup || (chatInformation->type == TDLibWrapper::ChatTypeSuperGroup && !chatInformation->isChannel))) { // Add author QString fullName; if (senderInformation.value(_TYPE).toString() == "messageSenderChat") { fullName = tdLibWrapper->getChat(senderInformation.value(CHAT_ID).toString()).value(TITLE).toString(); } else { fullName = TelegrafUtils::getUserName(tdLibWrapper->getUserInformation(senderInformation.value(USER_ID).toLongLong())); } notificationBody += fullName.trimmed() + ": "; } notificationBody += TelegrafUtils::getMessageShortText(tdLibWrapper, messageMap.value(CONTENT).toMap(), (chatInformation ? chatInformation->isChannel : false), tdLibWrapper->getMyUserId(), senderInformation ); } const QString summary(chatInformation ? chatInformation->title : QString()); nemoNotification->setBody(notificationBody); nemoNotification->setSummary(summary); nemoNotification->setHintValue(HINT_VIBRA, needFeedback); nemoNotification->setHintValue(HINT_IMAGE_PATH, QString()); // Don't show popup for the currently open chat if (!needFeedback || (chatModel->getChatId() == notificationGroup->chatId && qGuiApp->applicationState() == Qt::ApplicationActive)) { nemoNotification->setHintValue(HINT_SUPPRESS_SOUND, true); nemoNotification->setHintValue(HINT_DISPLAY_ON, false); nemoNotification->setHintValue(HINT_VISIBILITY, QString()); nemoNotification->setUrgency(Notification::Low); } else { if (!appSettings->notificationSuppressContent()) { nemoNotification->setPreviewBody(notificationBody); } else { nemoNotification->setPreviewBody(tr("%Ln unread messages", "", notificationGroup->totalCount)); } nemoNotification->setPreviewSummary(summary); nemoNotification->setHintValue(HINT_SUPPRESS_SOUND, !appSettings->notificationSoundsEnabled()); nemoNotification->setHintValue(HINT_DISPLAY_ON, appSettings->notificationTurnsDisplayOn()); nemoNotification->setHintValue(HINT_VISIBILITY, VISIBILITY_PUBLIC); nemoNotification->setUrgency(Notification::Normal); } nemoNotification->publish(); } void NotificationManager::controlLedNotification(bool enabled) { static const QString PATTERN("PatternCommunicationIM"); if (enabled) { mceInterface->ledPatternActivate(PATTERN); } else { mceInterface->ledPatternDeactivate(PATTERN); } }