diff options
-rw-r--r-- | src/gui/systray.cpp | 12 | ||||
-rw-r--r-- | src/gui/systray.h | 2 | ||||
-rw-r--r-- | src/gui/tray/usermodel.cpp | 107 | ||||
-rw-r--r-- | src/gui/tray/usermodel.h | 13 |
4 files changed, 104 insertions, 30 deletions
diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp index d524b0dba..4d96ab1df 100644 --- a/src/gui/systray.cpp +++ b/src/gui/systray.cpp @@ -486,6 +486,18 @@ void Systray::showUpdateMessage(const QString &title, const QString &message, co #endif } +void Systray::showTalkMessage(const QString &title, const QString &message, const QString &token, const QString &replyTo, const AccountStatePtr &accountState) +{ +#if defined(Q_OS_MACOS) && defined(BUILD_OWNCLOUD_OSX_BUNDLE) + sendOsXTalkNotification(title, message, token, replyTo, accountState); +#else // TODO: Implement custom notifications (i.e. actionable) for other OSes + Q_UNUSED(replyTo); + Q_UNUSED(token); + Q_UNUSED(accountState); + showMessage(title, message); +#endif +} + void Systray::setToolTip(const QString &tip) { QSystemTrayIcon::setToolTip(tr("%1: %2").arg(Theme::instance()->appNameGUI(), tip)); diff --git a/src/gui/systray.h b/src/gui/systray.h index d28b66290..fc0e8341d 100644 --- a/src/gui/systray.h +++ b/src/gui/systray.h @@ -51,6 +51,7 @@ void registerNotificationCategories(const QString &localizedDownloadString); bool canOsXSendUserNotification(); void sendOsXUserNotification(const QString &title, const QString &message); void sendOsXUpdateNotification(const QString &title, const QString &message, const QUrl &webUrl); +void sendOsXTalkNotification(const QString &title, const QString &message, const QString &token, const QString &replyTo, const AccountStatePtr accountState); void setTrayWindowLevelAndVisibleOnAllSpaces(QWindow *window); double menuBarThickness(); #endif @@ -113,6 +114,7 @@ public slots: void showMessage(const QString &title, const QString &message, MessageIcon icon = Information); void showUpdateMessage(const QString &title, const QString &message, const QUrl &webUrl); + void showTalkMessage(const QString &title, const QString &message, const QString &replyTo, const QString &token, const AccountStatePtr &accountState); void setToolTip(const QString &tip); void createCallDialog(const Activity &callNotification, const AccountStatePtr accountState); diff --git a/src/gui/tray/usermodel.cpp b/src/gui/tray/usermodel.cpp index 3cee8809d..913804a3e 100644 --- a/src/gui/tray/usermodel.cpp +++ b/src/gui/tray/usermodel.cpp @@ -82,8 +82,60 @@ User::User(AccountStatePtr &account, const bool &isCurrent, QObject *parent) connect(this, &User::sendReplyMessage, this, &User::slotSendReplyMessage); } +void User::checkNotifiedNotifications() +{ + // after one hour, clear the gui log notification store + constexpr qint64 clearGuiLogInterval = 60 * 60 * 1000; + if (_guiLogTimer.elapsed() > clearGuiLogInterval) { + _notifiedNotifications.clear(); + } +} + +bool User::notificationAlreadyShown(const long notificationId) +{ + checkNotifiedNotifications(); + return _notifiedNotifications.contains(notificationId); +} + +bool User::canShowNotification(const long notificationId) +{ + ConfigFile cfg; + return cfg.optionalServerNotifications() && + isDesktopNotificationsAllowed() && + !notificationAlreadyShown(notificationId); +} + void User::showDesktopNotification(const QString &title, const QString &message, const long notificationId) { + if(!canShowNotification(notificationId)) { + return; + } + + _notifiedNotifications.insert(notificationId); + Logger::instance()->postGuiLog(title, message); + // restart the gui log timer now that we show a new notification + _guiLogTimer.start(); +} + +void User::showDesktopNotification(const Activity &activity) +{ + const auto notificationId = activity._id; + const auto message = AccountManager::instance()->accounts().count() == 1 ? "" : activity._accName; + showDesktopNotification(activity._subject, message, notificationId); +} + +void User::showDesktopNotification(const ActivityList &activityList) +{ + const auto subject = QStringLiteral("%1 notifications").arg(activityList.count()); + const auto notificationId = -static_cast<int>(qHash(subject)); + + if (!canShowNotification(notificationId)) { + return; + } + + const auto multipleAccounts = AccountManager::instance()->accounts().count() > 1; + const auto message = multipleAccounts ? activityList.constFirst()._accName : QString(); + // Notification ids are uints, which are 4 bytes. Error activities don't have ids, however, so we generate one. // To avoid possible collisions between the activity ids which are actually the notification ids received from // the server (which are always positive) and our "fake" error activity ids, we assign a negative id to the @@ -91,30 +143,40 @@ void User::showDesktopNotification(const QString &title, const QString &message, // // To ensure that we can still treat an unsigned int as normal, we use a long, which is 8 bytes. - ConfigFile cfg; - if (!cfg.optionalServerNotifications() || !isDesktopNotificationsAllowed()) { - return; + Logger::instance()->postGuiLog(subject, message); + + for(const auto &activity : activityList) { + _notifiedNotifications.insert(activity._id); + _activityModel->addNotificationToActivityList(activity); } +} - // after one hour, clear the gui log notification store - constexpr qint64 clearGuiLogInterval = 60 * 60 * 1000; - if (_guiLogTimer.elapsed() > clearGuiLogInterval) { - _notifiedNotifications.clear(); +void User::showDesktopTalkNotification(const Activity &activity) +{ + const auto notificationId = activity._id; + + if (!canShowNotification(notificationId)) { + return; } - if (_notifiedNotifications.contains(notificationId)) { + if (activity._talkNotificationData.messageId.isEmpty()) { + showDesktopNotification(activity._subject, activity._message, notificationId); return; } _notifiedNotifications.insert(notificationId); - Logger::instance()->postGuiLog(title, message); - // restart the gui log timer now that we show a new notification + _activityModel->addNotificationToActivityList(activity); + + Systray::instance()->showTalkMessage(activity._subject, + activity._message, + activity._talkNotificationData.conversationToken, + activity._talkNotificationData.messageId, + _account); _guiLogTimer.start(); } void User::slotBuildNotificationDisplay(const ActivityList &list) { - const auto multipleAccounts = AccountManager::instance()->accounts().count() > 1; ActivityList toNotifyList; std::copy_if(list.constBegin(), list.constEnd(), std::back_inserter(toNotifyList), [&](const Activity &activity) { @@ -131,25 +193,16 @@ void User::slotBuildNotificationDisplay(const ActivityList &list) }); if(toNotifyList.count() > 2) { - const auto subject = QStringLiteral("%1 notifications").arg(toNotifyList.count()); - const auto message = multipleAccounts ? toNotifyList.constFirst()._accName : QString(); - showDesktopNotification(subject, message, -static_cast<int>(qHash(subject))); - - // Set these activities as notified here, rather than in showDesktopNotification - for(const auto &activity : toNotifyList) { - _notifiedNotifications.insert(activity._id); - _activityModel->addNotificationToActivityList(activity); - } - + showDesktopNotification(toNotifyList); return; } for(const auto &activity : toNotifyList) { - const auto message = activity._objectType == QStringLiteral("chat") - ? activity._message : AccountManager::instance()->accounts().count() == 1 ? "" : activity._accName; - - showDesktopNotification(activity._subject, message, activity._id); // We assigned the notif. id to the activity id - _activityModel->addNotificationToActivityList(activity); + if (activity._objectType == QStringLiteral("chat")) { + showDesktopTalkNotification(activity); + } else { + showDesktopNotification(activity); + } } } @@ -547,7 +600,7 @@ void User::slotAddErrorToGui(const QString &folderAlias, SyncFileItem::Status st // add 'other errors' to activity list _activityModel->addErrorToActivityList(activity); - showDesktopNotification(activity._subject, activity._message, activity._id); + showDesktopNotification(activity); if (!_expiredActivitiesCheckTimer.isActive()) { _expiredActivitiesCheckTimer.start(expiredActivitiesCheckIntervalMsecs); diff --git a/src/gui/tray/usermodel.h b/src/gui/tray/usermodel.h index 08e23f0b3..8b6b47fe4 100644 --- a/src/gui/tray/usermodel.h +++ b/src/gui/tray/usermodel.h @@ -110,22 +110,29 @@ public slots: void slotSendReplyMessage(const int activityIndex, const QString &conversationToken, const QString &message, const QString &replyTo); void forceSyncNow() const; -private: +private slots: void slotPushNotificationsReady(); void slotDisconnectPushNotifications(); void slotReceivedPushNotification(Account *account); void slotReceivedPushActivity(Account *account); void slotCheckExpiredActivities(); + void checkNotifiedNotifications(); + void showDesktopNotification(const QString &title, const QString &message, const long notificationId); + void showDesktopNotification(const Activity &activity); + void showDesktopNotification(const ActivityList &activityList); + void showDesktopTalkNotification(const Activity &activity); + +private: void connectPushNotifications() const; [[nodiscard]] bool checkPushNotificationsAreReady() const; bool isActivityOfCurrentAccount(const Folder *folder) const; [[nodiscard]] bool isUnsolvableConflict(const SyncFileItemPtr &item) const; - void showDesktopNotification(const QString &title, const QString &message, const long notificationId); + bool notificationAlreadyShown(const long notificationId); + bool canShowNotification(const long notificationId); -private: AccountStatePtr _account; bool _isCurrentUser; ActivityListModel *_activityModel; |