Skip to content

Commit

Permalink
Differentiate between normal normal and Talk notifications, invoke ma…
Browse files Browse the repository at this point in the history
…cOS text reply notifications

Signed-off-by: Claudio Cambra <[email protected]>
  • Loading branch information
claucambra committed Nov 8, 2022
1 parent 1838547 commit 87478c2
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 30 deletions.
12 changes: 12 additions & 0 deletions src/gui/systray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
2 changes: 2 additions & 0 deletions src/gui/systray.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
107 changes: 80 additions & 27 deletions src/gui/tray/usermodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,39 +82,101 @@ 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
// error notification.
//
// 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) {
Expand All @@ -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);
}
}
}

Expand Down Expand Up @@ -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);
Expand Down
13 changes: 10 additions & 3 deletions src/gui/tray/usermodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 87478c2

Please sign in to comment.