mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-29 12:19:03 +03:00
Merge pull request #5143 from nextcloud/feature/interactive-talk-macos-notifications
Add interactive NC Talk notifications on macOS
This commit is contained in:
commit
5d7068a0f7
5 changed files with 214 additions and 45 deletions
|
@ -486,6 +486,18 @@ void Systray::showUpdateMessage(const QString &title, const QString &message, co
|
||||||
#endif
|
#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)
|
void Systray::setToolTip(const QString &tip)
|
||||||
{
|
{
|
||||||
QSystemTrayIcon::setToolTip(tr("%1: %2").arg(Theme::instance()->appNameGUI(), tip));
|
QSystemTrayIcon::setToolTip(tr("%1: %2").arg(Theme::instance()->appNameGUI(), tip));
|
||||||
|
|
|
@ -51,6 +51,7 @@ void registerNotificationCategories(const QString &localizedDownloadString);
|
||||||
bool canOsXSendUserNotification();
|
bool canOsXSendUserNotification();
|
||||||
void sendOsXUserNotification(const QString &title, const QString &message);
|
void sendOsXUserNotification(const QString &title, const QString &message);
|
||||||
void sendOsXUpdateNotification(const QString &title, const QString &message, const QUrl &webUrl);
|
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);
|
void setTrayWindowLevelAndVisibleOnAllSpaces(QWindow *window);
|
||||||
double menuBarThickness();
|
double menuBarThickness();
|
||||||
#endif
|
#endif
|
||||||
|
@ -113,6 +114,7 @@ public slots:
|
||||||
|
|
||||||
void showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon icon = Information);
|
void showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon icon = Information);
|
||||||
void showUpdateMessage(const QString &title, const QString &message, const QUrl &webUrl);
|
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 setToolTip(const QString &tip);
|
||||||
|
|
||||||
void createCallDialog(const OCC::Activity &callNotification, const OCC::AccountStatePtr accountState);
|
void createCallDialog(const OCC::Activity &callNotification, const OCC::AccountStatePtr accountState);
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
#include "QtCore/qurl.h"
|
#include "QtCore/qurl.h"
|
||||||
|
#include "account.h"
|
||||||
|
#include "accountstate.h"
|
||||||
|
#include "accountmanager.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "systray.h"
|
||||||
|
#include "tray/talkreply.h"
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
@ -9,6 +14,58 @@
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcMacSystray, "nextcloud.gui.macsystray")
|
Q_LOGGING_CATEGORY(lcMacSystray, "nextcloud.gui.macsystray")
|
||||||
|
|
||||||
|
/************************* Private utility functions *************************/
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void sendTalkReply(UNNotificationResponse *response, UNNotificationContent* content)
|
||||||
|
{
|
||||||
|
if (!response || !content) {
|
||||||
|
qCWarning(lcMacSystray()) << "Invalid notification response or content."
|
||||||
|
<< "Can't send talk reply.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNTextInputNotificationResponse *textInputResponse = (UNTextInputNotificationResponse*)response;
|
||||||
|
|
||||||
|
if (!textInputResponse) {
|
||||||
|
qCWarning(lcMacSystray()) << "Notification response was not a text input response."
|
||||||
|
<< "Can't send talk reply.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *reply = textInputResponse.userText;
|
||||||
|
NSString *token = [content.userInfo objectForKey:@"token"];
|
||||||
|
NSString *account = [content.userInfo objectForKey:@"account"];
|
||||||
|
NSString *replyTo = [content.userInfo objectForKey:@"replyTo"];
|
||||||
|
|
||||||
|
const auto qReply = QString::fromNSString(reply);
|
||||||
|
const auto qReplyTo = QString::fromNSString(replyTo);
|
||||||
|
const auto qToken = QString::fromNSString(token);
|
||||||
|
const auto qAccount = QString::fromNSString(account);
|
||||||
|
|
||||||
|
const auto accountState = OCC::AccountManager::instance()->accountFromUserId(qAccount);
|
||||||
|
|
||||||
|
if (!accountState) {
|
||||||
|
qCWarning(lcMacSystray()) << "Could not find account matching" << qAccount
|
||||||
|
<< "Can't send talk reply.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(lcMacSystray()) << "Sending talk reply from macOS notification."
|
||||||
|
<< "Reply is:" << qReply
|
||||||
|
<< "Replying to:" << qReplyTo
|
||||||
|
<< "Token:" << qToken
|
||||||
|
<< "Account:" << qAccount;
|
||||||
|
|
||||||
|
QPointer<OCC::TalkReply> talkReply = new OCC::TalkReply(accountState.data(), OCC::Systray::instance());
|
||||||
|
talkReply->sendReplyMessage(qToken, qReply, qReplyTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
/**************************** Objective-C classes ****************************/
|
||||||
|
|
||||||
@interface NotificationCenterDelegate : NSObject
|
@interface NotificationCenterDelegate : NSObject
|
||||||
@end
|
@end
|
||||||
@implementation NotificationCenterDelegate
|
@implementation NotificationCenterDelegate
|
||||||
|
@ -34,23 +91,24 @@ Q_LOGGING_CATEGORY(lcMacSystray, "nextcloud.gui.macsystray")
|
||||||
UNNotificationContent* content = response.notification.request.content;
|
UNNotificationContent* content = response.notification.request.content;
|
||||||
if ([content.categoryIdentifier isEqualToString:@"UPDATE"]) {
|
if ([content.categoryIdentifier isEqualToString:@"UPDATE"]) {
|
||||||
|
|
||||||
if ([response.actionIdentifier isEqualToString:@"DOWNLOAD_ACTION"] || [response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier])
|
if ([response.actionIdentifier isEqualToString:@"DOWNLOAD_ACTION"] || [response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) {
|
||||||
{
|
|
||||||
qCDebug(lcMacSystray()) << "Opening update download url in browser.";
|
qCDebug(lcMacSystray()) << "Opening update download url in browser.";
|
||||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[content.userInfo objectForKey:@"webUrl"]]];
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[content.userInfo objectForKey:@"webUrl"]]];
|
||||||
}
|
}
|
||||||
|
} else if ([content.categoryIdentifier isEqualToString:@"TALK_MESSAGE"]) {
|
||||||
|
|
||||||
|
if ([response.actionIdentifier isEqualToString:@"TALK_REPLY_ACTION"]) {
|
||||||
|
sendTalkReply(response, content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
completionHandler();
|
completionHandler();
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
namespace OCC {
|
/********************* Methods accessible to C++ Systray *********************/
|
||||||
|
|
||||||
enum MacNotificationAuthorizationOptions {
|
namespace OCC {
|
||||||
Default = 0,
|
|
||||||
Provisional
|
|
||||||
};
|
|
||||||
|
|
||||||
double menuBarThickness()
|
double menuBarThickness()
|
||||||
{
|
{
|
||||||
|
@ -93,10 +151,24 @@ void registerNotificationCategories(const QString &localisedDownloadString) {
|
||||||
intentIdentifiers:@[]
|
intentIdentifiers:@[]
|
||||||
options:UNNotificationCategoryOptionNone];
|
options:UNNotificationCategoryOptionNone];
|
||||||
|
|
||||||
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObjects:generalCategory, updateCategory, nil]];
|
// Create the custom action for talk notifications
|
||||||
|
UNTextInputNotificationAction* talkReplyAction = [UNTextInputNotificationAction
|
||||||
|
actionWithIdentifier:@"TALK_REPLY_ACTION"
|
||||||
|
title:QObject::tr("Reply").toNSString()
|
||||||
|
options:UNNotificationActionOptionNone
|
||||||
|
textInputButtonTitle:QObject::tr("Reply").toNSString()
|
||||||
|
textInputPlaceholder:QObject::tr("Send a Nextcloud Talk reply").toNSString()];
|
||||||
|
|
||||||
|
UNNotificationCategory* talkReplyCategory = [UNNotificationCategory
|
||||||
|
categoryWithIdentifier:@"TALK_MESSAGE"
|
||||||
|
actions:@[talkReplyAction]
|
||||||
|
intentIdentifiers:@[]
|
||||||
|
options:UNNotificationCategoryOptionNone];
|
||||||
|
|
||||||
|
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObjects:generalCategory, updateCategory, talkReplyCategory, nil]];
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkNotificationAuth(MacNotificationAuthorizationOptions additionalAuthOption = MacNotificationAuthorizationOptions::Provisional)
|
void checkNotificationAuth(MacNotificationAuthorizationOptions additionalAuthOption)
|
||||||
{
|
{
|
||||||
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
|
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
|
||||||
UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert + UNAuthorizationOptionSound;
|
UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert + UNAuthorizationOptionSound;
|
||||||
|
@ -170,6 +242,30 @@ void sendOsXUpdateNotification(const QString &title, const QString &message, con
|
||||||
[center addNotificationRequest:request withCompletionHandler:nil];
|
[center addNotificationRequest:request withCompletionHandler:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sendOsXTalkNotification(const QString &title, const QString &message, const QString &token, const QString &replyTo, const AccountStatePtr accountState)
|
||||||
|
{
|
||||||
|
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
|
||||||
|
checkNotificationAuth();
|
||||||
|
|
||||||
|
if (!accountState || !accountState->account()) {
|
||||||
|
sendOsXUserNotification(title, message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *accountNS = accountState->account()->displayName().toNSString();
|
||||||
|
NSString *tokenNS = token.toNSString();
|
||||||
|
NSString *replyToNS = replyTo.toNSString();
|
||||||
|
|
||||||
|
UNMutableNotificationContent* content = basicNotificationContent(title, message);
|
||||||
|
content.categoryIdentifier = @"TALK_MESSAGE";
|
||||||
|
content.userInfo = [NSDictionary dictionaryWithObjects:@[accountNS, tokenNS, replyToNS] forKeys:@[@"account", @"token", @"replyTo"]];
|
||||||
|
|
||||||
|
UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats: NO];
|
||||||
|
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"NCTalkMessageNotification" content:content trigger:trigger];
|
||||||
|
|
||||||
|
[center addNotificationRequest:request withCompletionHandler:nil];
|
||||||
|
}
|
||||||
|
|
||||||
void setTrayWindowLevelAndVisibleOnAllSpaces(QWindow *window)
|
void setTrayWindowLevelAndVisibleOnAllSpaces(QWindow *window)
|
||||||
{
|
{
|
||||||
NSView *nativeView = (NSView *)window->winId();
|
NSView *nativeView = (NSView *)window->winId();
|
||||||
|
@ -185,5 +281,4 @@ bool osXInDarkMode()
|
||||||
return [osxMode containsString:@"Dark"];
|
return [osxMode containsString:@"Dark"];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // OCC namespace
|
||||||
|
|
||||||
|
|
|
@ -82,27 +82,32 @@ User::User(AccountStatePtr &account, const bool &isCurrent, QObject *parent)
|
||||||
connect(this, &User::sendReplyMessage, this, &User::slotSendReplyMessage);
|
connect(this, &User::sendReplyMessage, this, &User::slotSendReplyMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void User::showDesktopNotification(const QString &title, const QString &message, const long notificationId)
|
void User::checkNotifiedNotifications()
|
||||||
{
|
{
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// after one hour, clear the gui log notification store
|
// after one hour, clear the gui log notification store
|
||||||
constexpr qint64 clearGuiLogInterval = 60 * 60 * 1000;
|
constexpr qint64 clearGuiLogInterval = 60 * 60 * 1000;
|
||||||
if (_guiLogTimer.elapsed() > clearGuiLogInterval) {
|
if (_guiLogTimer.elapsed() > clearGuiLogInterval) {
|
||||||
_notifiedNotifications.clear();
|
_notifiedNotifications.clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_notifiedNotifications.contains(notificationId)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,9 +117,66 @@ void User::showDesktopNotification(const QString &title, const QString &message,
|
||||||
_guiLogTimer.start();
|
_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.
|
||||||
|
|
||||||
|
Logger::instance()->postGuiLog(subject, message);
|
||||||
|
|
||||||
|
for(const auto &activity : activityList) {
|
||||||
|
_notifiedNotifications.insert(activity._id);
|
||||||
|
_activityModel->addNotificationToActivityList(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void User::showDesktopTalkNotification(const Activity &activity)
|
||||||
|
{
|
||||||
|
const auto notificationId = activity._id;
|
||||||
|
|
||||||
|
if (!canShowNotification(notificationId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activity._talkNotificationData.messageId.isEmpty()) {
|
||||||
|
showDesktopNotification(activity._subject, activity._message, notificationId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_notifiedNotifications.insert(notificationId);
|
||||||
|
_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)
|
void User::slotBuildNotificationDisplay(const ActivityList &list)
|
||||||
{
|
{
|
||||||
const auto multipleAccounts = AccountManager::instance()->accounts().count() > 1;
|
|
||||||
ActivityList toNotifyList;
|
ActivityList toNotifyList;
|
||||||
|
|
||||||
std::copy_if(list.constBegin(), list.constEnd(), std::back_inserter(toNotifyList), [&](const Activity &activity) {
|
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) {
|
if(toNotifyList.count() > 2) {
|
||||||
const auto subject = QStringLiteral("%1 notifications").arg(toNotifyList.count());
|
showDesktopNotification(toNotifyList);
|
||||||
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 : qAsConst(toNotifyList)) {
|
|
||||||
_notifiedNotifications.insert(activity._id);
|
|
||||||
_activityModel->addNotificationToActivityList(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const auto &activity : qAsConst(toNotifyList)) {
|
for(const auto &activity : qAsConst(toNotifyList)) {
|
||||||
const auto message = activity._objectType == QStringLiteral("chat")
|
if (activity._objectType == QStringLiteral("chat")) {
|
||||||
? activity._message : AccountManager::instance()->accounts().count() == 1 ? "" : activity._accName;
|
showDesktopTalkNotification(activity);
|
||||||
|
} else {
|
||||||
showDesktopNotification(activity._subject, message, activity._id); // We assigned the notif. id to the activity id
|
showDesktopNotification(activity);
|
||||||
_activityModel->addNotificationToActivityList(activity);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,7 +601,7 @@ void User::slotAddErrorToGui(const QString &folderAlias, SyncFileItem::Status st
|
||||||
// add 'other errors' to activity list
|
// add 'other errors' to activity list
|
||||||
_activityModel->addErrorToActivityList(activity);
|
_activityModel->addErrorToActivityList(activity);
|
||||||
|
|
||||||
showDesktopNotification(activity._subject, activity._message, activity._id);
|
showDesktopNotification(activity);
|
||||||
|
|
||||||
if (!_expiredActivitiesCheckTimer.isActive()) {
|
if (!_expiredActivitiesCheckTimer.isActive()) {
|
||||||
_expiredActivitiesCheckTimer.start(expiredActivitiesCheckIntervalMsecs);
|
_expiredActivitiesCheckTimer.start(expiredActivitiesCheckIntervalMsecs);
|
||||||
|
|
|
@ -110,22 +110,29 @@ public slots:
|
||||||
void slotSendReplyMessage(const int activityIndex, const QString &conversationToken, const QString &message, const QString &replyTo);
|
void slotSendReplyMessage(const int activityIndex, const QString &conversationToken, const QString &message, const QString &replyTo);
|
||||||
void forceSyncNow() const;
|
void forceSyncNow() const;
|
||||||
|
|
||||||
private:
|
private slots:
|
||||||
void slotPushNotificationsReady();
|
void slotPushNotificationsReady();
|
||||||
void slotDisconnectPushNotifications();
|
void slotDisconnectPushNotifications();
|
||||||
void slotReceivedPushNotification(Account *account);
|
void slotReceivedPushNotification(Account *account);
|
||||||
void slotReceivedPushActivity(Account *account);
|
void slotReceivedPushActivity(Account *account);
|
||||||
void slotCheckExpiredActivities();
|
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;
|
void connectPushNotifications() const;
|
||||||
[[nodiscard]] bool checkPushNotificationsAreReady() const;
|
[[nodiscard]] bool checkPushNotificationsAreReady() const;
|
||||||
|
|
||||||
bool isActivityOfCurrentAccount(const Folder *folder) const;
|
bool isActivityOfCurrentAccount(const Folder *folder) const;
|
||||||
[[nodiscard]] bool isUnsolvableConflict(const SyncFileItemPtr &item) 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;
|
AccountStatePtr _account;
|
||||||
bool _isCurrentUser;
|
bool _isCurrentUser;
|
||||||
ActivityListModel *_activityModel;
|
ActivityListModel *_activityModel;
|
||||||
|
|
Loading…
Reference in a new issue