IF( APPLE )
list(APPEND client_SRCS cocoainitializer_mac.mm)
- list(APPEND client_SRCS systray.mm systray_mac_common.mm)
+ list(APPEND client_SRCS systray_mac_common.mm)
+
+ if (NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.14)
+ list(APPEND client_SRCS systray_mac_usernotifications.mm)
+ endif()
if (BUILD_FILE_PROVIDER_MODULE)
list(APPEND client_SRCS
Systray::Systray()
: QSystemTrayIcon(nullptr)
{
-#if defined(Q_OS_MACOS) && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
+#if defined(Q_OS_MACOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
setUserNotificationCenterDelegate();
checkNotificationAuth(MacNotificationAuthorizationOptions::Default); // No provisional auth, ask user explicitly first time
registerNotificationCategories(QString(tr("Download")));
QDBusConnection::sessionBus().asyncCall(method);
} else
#endif
-#if defined(Q_OS_MACOS) && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
+#if defined(Q_OS_MACOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
if (canOsXSendUserNotification()) {
sendOsXUserNotification(title, message);
} else
void Systray::showUpdateMessage(const QString &title, const QString &message, const QUrl &webUrl)
{
-#if defined(Q_OS_MACOS) && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
+#if defined(Q_OS_MACOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 && defined(BUILD_OWNCLOUD_OSX_BUNDLE)
sendOsXUpdateNotification(title, message, webUrl);
#else // TODO: Implement custom notifications (i.e. actionable) for other OSes
Q_UNUSED(webUrl);
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)
+#if defined(Q_OS_MACOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 && 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)
};
#ifdef Q_OS_MACOS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14
enum MacNotificationAuthorizationOptions {
Default = 0,
Provisional
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);
+#endif
void setTrayWindowLevelAndVisibleOnAllSpaces(QWindow *window);
double menuBarThickness();
#endif
+++ /dev/null
-#include <QLoggingCategory>
-#include <QString>
-#include <QUrl>
-
-#include "account.h"
-#include "accountstate.h"
-#include "accountmanager.h"
-#include "config.h"
-#include "systray.h"
-#include "tray/talkreply.h"
-
-#import <Cocoa/Cocoa.h>
-#import <UserNotifications/UserNotifications.h>
-
-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 * const textInputResponse = (UNTextInputNotificationResponse*)response;
-
- if (!textInputResponse) {
- qCWarning(lcMacSystray()) << "Notification response was not a text input response."
- << "Can't send talk reply.";
- return;
- }
-
- NSString * const reply = textInputResponse.userText;
- NSString * const token = [content.userInfo objectForKey:@"token"];
- NSString * const account = [content.userInfo objectForKey:@"account"];
- NSString * const 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;
-
- // OCC::TalkReply deletes itself once it's done, fire and forget
- const auto talkReply = new OCC::TalkReply(accountState.data(), OCC::Systray::instance());
- talkReply->sendReplyMessage(qToken, qReply, qReplyTo);
-}
-
-} // anonymous namespace
-
-/**************************** Objective-C classes ****************************/
-
-@interface NotificationCenterDelegate : NSObject
-@end
-@implementation NotificationCenterDelegate
-
-// Always show, even if app is active at the moment.
-- (void)userNotificationCenter:(UNUserNotificationCenter *)center
- willPresentNotification:(UNNotification *)notification
- withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
-{
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_11_0
- completionHandler(UNNotificationPresentationOptionSound + UNNotificationPresentationOptionBanner);
-#else
- completionHandler(UNNotificationPresentationOptionSound + UNNotificationPresentationOptionAlert);
-#endif
-}
-
-- (void)userNotificationCenter:(UNUserNotificationCenter *)center
-didReceiveNotificationResponse:(UNNotificationResponse *)response
- withCompletionHandler:(void (^)(void))completionHandler
-{
- qCDebug(lcMacSystray()) << "Received notification with category identifier:" << response.notification.request.content.categoryIdentifier
- << "and action identifier" << response.actionIdentifier;
- UNNotificationContent * const content = response.notification.request.content;
- if ([content.categoryIdentifier isEqualToString:@"UPDATE"]) {
-
- if ([response.actionIdentifier isEqualToString:@"DOWNLOAD_ACTION"] || [response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) {
- qCDebug(lcMacSystray()) << "Opening update download url in browser.";
- [[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();
-}
-@end
-
-/********************* Methods accessible to C++ Systray *********************/
-
-namespace OCC {
-
-// TODO: Get this to actually check for permissions
-bool canOsXSendUserNotification()
-{
- UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
- return center != nil;
-}
-
-void registerNotificationCategories(const QString &localisedDownloadString) {
- UNNotificationCategory * const generalCategory = [UNNotificationCategory
- categoryWithIdentifier:@"GENERAL"
- actions:@[]
- intentIdentifiers:@[]
- options:UNNotificationCategoryOptionCustomDismissAction];
-
- // Create the custom actions for update notifications.
- UNNotificationAction * const downloadAction = [UNNotificationAction
- actionWithIdentifier:@"DOWNLOAD_ACTION"
- title:localisedDownloadString.toNSString()
- options:UNNotificationActionOptionNone];
-
- // Create the category with the custom actions.
- UNNotificationCategory * const updateCategory = [UNNotificationCategory
- categoryWithIdentifier:@"UPDATE"
- actions:@[downloadAction]
- intentIdentifiers:@[]
- options:UNNotificationCategoryOptionNone];
-
- // Create the custom action for talk notifications
- UNTextInputNotificationAction * const 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 * const talkReplyCategory = [UNNotificationCategory
- categoryWithIdentifier:@"TALK_MESSAGE"
- actions:@[talkReplyAction]
- intentIdentifiers:@[]
- options:UNNotificationCategoryOptionNone];
-
- [UNUserNotificationCenter.currentNotificationCenter setNotificationCategories:[NSSet setWithObjects:generalCategory, updateCategory, talkReplyCategory, nil]];
-}
-
-void checkNotificationAuth(MacNotificationAuthorizationOptions additionalAuthOption)
-{
- UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
- UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert + UNAuthorizationOptionSound;
-
- if(additionalAuthOption == MacNotificationAuthorizationOptions::Provisional) {
- authOptions += UNAuthorizationOptionProvisional;
- }
-
- [center requestAuthorizationWithOptions:(authOptions) completionHandler:^(BOOL granted, NSError * _Nullable error) {
- // Enable or disable features based on authorization.
- if (granted) {
- qCDebug(lcMacSystray) << "Authorization for notifications has been granted, can display notifications.";
- } else {
- qCDebug(lcMacSystray) << "Authorization for notifications not granted.";
- if (error) {
- const auto errorDescription = QString::fromNSString(error.localizedDescription);
- qCDebug(lcMacSystray) << "Error from notification center: " << errorDescription;
- }
- }
- }];
-}
-
-void setUserNotificationCenterDelegate()
-{
- UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
-
- static dispatch_once_t once;
- dispatch_once(&once, ^{
- id delegate = [[NotificationCenterDelegate alloc] init];
- [center setDelegate:delegate];
- });
-}
-
-UNMutableNotificationContent* basicNotificationContent(const QString &title, const QString &message)
-{
- UNMutableNotificationContent * const content = [[UNMutableNotificationContent alloc] init];
- content.title = title.toNSString();
- content.body = message.toNSString();
- content.sound = [UNNotificationSound defaultSound];
-
- return content;
-}
-
-void sendOsXUserNotification(const QString &title, const QString &message)
-{
- UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
- checkNotificationAuth();
-
- UNMutableNotificationContent * const content = basicNotificationContent(title, message);
- content.categoryIdentifier = @"GENERAL";
-
- UNTimeIntervalNotificationTrigger * const trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];
- UNNotificationRequest * const request = [UNNotificationRequest requestWithIdentifier:@"NCUserNotification" content:content trigger:trigger];
-
- [center addNotificationRequest:request withCompletionHandler:nil];
-}
-
-void sendOsXUpdateNotification(const QString &title, const QString &message, const QUrl &webUrl)
-{
- UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
- checkNotificationAuth();
-
- UNMutableNotificationContent * const content = basicNotificationContent(title, message);
- content.categoryIdentifier = @"UPDATE";
- content.userInfo = [NSDictionary dictionaryWithObject:[webUrl.toNSURL() absoluteString] forKey:@"webUrl"];
-
- UNTimeIntervalNotificationTrigger * const trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];
- UNNotificationRequest * const request = [UNNotificationRequest requestWithIdentifier:@"NCUpdateNotification" content:content trigger:trigger];
-
- [center addNotificationRequest:request withCompletionHandler:nil];
-}
-
-void sendOsXTalkNotification(const QString &title, const QString &message, const QString &token, const QString &replyTo, const AccountStatePtr accountState)
-{
- UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
- checkNotificationAuth();
-
- if (!accountState || !accountState->account()) {
- sendOsXUserNotification(title, message);
- return;
- }
-
- NSString * const accountNS = accountState->account()->displayName().toNSString();
- NSString * const tokenNS = token.toNSString();
- NSString * const replyToNS = replyTo.toNSString();
-
- UNMutableNotificationContent * const content = basicNotificationContent(title, message);
- content.categoryIdentifier = @"TALK_MESSAGE";
- content.userInfo = [NSDictionary dictionaryWithObjects:@[accountNS, tokenNS, replyToNS] forKeys:@[@"account", @"token", @"replyTo"]];
-
- UNTimeIntervalNotificationTrigger * const trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];
- UNNotificationRequest * const request = [UNNotificationRequest requestWithIdentifier:@"NCTalkMessageNotification" content:content trigger:trigger];
-
- [center addNotificationRequest:request withCompletionHandler:nil];
-}
-
-} // OCC namespace
--- /dev/null
+/*
+ * Copyright (C) 2023 by Claudio Cambra <claudio.cambra@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <QLoggingCategory>
+#include <QString>
+#include <QUrl>
+
+#import <Cocoa/Cocoa.h>
+#import <UserNotifications/UserNotifications.h>
+
+#include "account.h"
+#include "accountstate.h"
+#include "accountmanager.h"
+#include "config.h"
+#include "systray.h"
+#include "tray/talkreply.h"
+
+Q_LOGGING_CATEGORY(lcMacSystrayUserNotifications, "nextcloud.gui.macsystrayusernotifications")
+
+/************************* Private utility functions *************************/
+
+namespace {
+
+void sendTalkReply(UNNotificationResponse *response, UNNotificationContent* content)
+{
+ if (!response || !content) {
+ qCWarning(lcMacSystrayUserNotifications) << "Invalid notification response or content."
+ << "Can't send talk reply.";
+ return;
+ }
+
+ UNTextInputNotificationResponse * const textInputResponse = (UNTextInputNotificationResponse*)response;
+
+ if (!textInputResponse) {
+ qCWarning(lcMacSystrayUserNotifications) << "Notification response was not a text input response."
+ << "Can't send talk reply.";
+ return;
+ }
+
+ NSString * const reply = textInputResponse.userText;
+ NSString * const token = [content.userInfo objectForKey:@"token"];
+ NSString * const account = [content.userInfo objectForKey:@"account"];
+ NSString * const 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(lcMacSystrayUserNotifications) << "Could not find account matching" << qAccount
+ << "Can't send talk reply.";
+ return;
+ }
+
+ qCDebug(lcMacSystrayUserNotifications) << "Sending talk reply from macOS notification."
+ << "Reply is:" << qReply
+ << "Replying to:" << qReplyTo
+ << "Token:" << qToken
+ << "Account:" << qAccount;
+
+ // OCC::TalkReply deletes itself once it's done, fire and forget
+ const auto talkReply = new OCC::TalkReply(accountState.data(), OCC::Systray::instance());
+ talkReply->sendReplyMessage(qToken, qReply, qReplyTo);
+}
+
+} // anonymous namespace
+
+/**************************** Objective-C classes ****************************/
+
+@interface NotificationCenterDelegate : NSObject
+@end
+@implementation NotificationCenterDelegate
+
+// Always show, even if app is active at the moment.
+- (void)userNotificationCenter:(UNUserNotificationCenter *)center
+ willPresentNotification:(UNNotification *)notification
+ withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_11_0
+ completionHandler(UNNotificationPresentationOptionSound + UNNotificationPresentationOptionBanner);
+#else
+ completionHandler(UNNotificationPresentationOptionSound + UNNotificationPresentationOptionAlert);
+#endif
+}
+
+- (void)userNotificationCenter:(UNUserNotificationCenter *)center
+didReceiveNotificationResponse:(UNNotificationResponse *)response
+ withCompletionHandler:(void (^)(void))completionHandler
+{
+ qCDebug(lcMacSystrayUserNotifications) << "Received notification with category identifier:"
+ << response.notification.request.content.categoryIdentifier
+ << "and action identifier"
+ << response.actionIdentifier;
+
+ UNNotificationContent * const content = response.notification.request.content;
+ if ([content.categoryIdentifier isEqualToString:@"UPDATE"]) {
+
+ if ([response.actionIdentifier isEqualToString:@"DOWNLOAD_ACTION"] || [response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) {
+ qCDebug(lcMacSystrayUserNotifications) << "Opening update download url in browser.";
+ [[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();
+}
+@end
+
+/********************* Methods accessible to C++ Systray *********************/
+
+namespace OCC {
+
+// TODO: Get this to actually check for permissions
+bool canOsXSendUserNotification()
+{
+ UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
+ return center != nil;
+}
+
+void registerNotificationCategories(const QString &localisedDownloadString) {
+ UNNotificationCategory * const generalCategory = [UNNotificationCategory
+ categoryWithIdentifier:@"GENERAL"
+ actions:@[]
+ intentIdentifiers:@[]
+ options:UNNotificationCategoryOptionCustomDismissAction];
+
+ // Create the custom actions for update notifications.
+ UNNotificationAction * const downloadAction = [UNNotificationAction
+ actionWithIdentifier:@"DOWNLOAD_ACTION"
+ title:localisedDownloadString.toNSString()
+ options:UNNotificationActionOptionNone];
+
+ // Create the category with the custom actions.
+ UNNotificationCategory * const updateCategory = [UNNotificationCategory
+ categoryWithIdentifier:@"UPDATE"
+ actions:@[downloadAction]
+ intentIdentifiers:@[]
+ options:UNNotificationCategoryOptionNone];
+
+ // Create the custom action for talk notifications
+ UNTextInputNotificationAction * const 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 * const talkReplyCategory = [UNNotificationCategory
+ categoryWithIdentifier:@"TALK_MESSAGE"
+ actions:@[talkReplyAction]
+ intentIdentifiers:@[]
+ options:UNNotificationCategoryOptionNone];
+
+ [UNUserNotificationCenter.currentNotificationCenter setNotificationCategories:[NSSet setWithObjects:generalCategory, updateCategory, talkReplyCategory, nil]];
+}
+
+void checkNotificationAuth(MacNotificationAuthorizationOptions additionalAuthOption)
+{
+ UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
+ UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert + UNAuthorizationOptionSound;
+
+ if(additionalAuthOption == MacNotificationAuthorizationOptions::Provisional) {
+ authOptions += UNAuthorizationOptionProvisional;
+ }
+
+ [center requestAuthorizationWithOptions:(authOptions) completionHandler:^(BOOL granted, NSError * _Nullable error) {
+ // Enable or disable features based on authorization.
+ if (granted) {
+ qCDebug(lcMacSystrayUserNotifications) << "Authorization for notifications has been granted, can display notifications.";
+ } else {
+ qCDebug(lcMacSystrayUserNotifications) << "Authorization for notifications not granted.";
+ if (error) {
+ const auto errorDescription = QString::fromNSString(error.localizedDescription);
+ qCDebug(lcMacSystrayUserNotifications) << "Error from notification center: " << errorDescription;
+ }
+ }
+ }];
+}
+
+void setUserNotificationCenterDelegate()
+{
+ UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
+
+ static dispatch_once_t once;
+ dispatch_once(&once, ^{
+ id delegate = [[NotificationCenterDelegate alloc] init];
+ [center setDelegate:delegate];
+ });
+}
+
+UNMutableNotificationContent* basicNotificationContent(const QString &title, const QString &message)
+{
+ UNMutableNotificationContent * const content = [[UNMutableNotificationContent alloc] init];
+ content.title = title.toNSString();
+ content.body = message.toNSString();
+ content.sound = [UNNotificationSound defaultSound];
+
+ return content;
+}
+
+void sendOsXUserNotification(const QString &title, const QString &message)
+{
+ UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
+ checkNotificationAuth();
+
+ UNMutableNotificationContent * const content = basicNotificationContent(title, message);
+ content.categoryIdentifier = @"GENERAL";
+
+ UNTimeIntervalNotificationTrigger * const trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];
+ UNNotificationRequest * const request = [UNNotificationRequest requestWithIdentifier:@"NCUserNotification" content:content trigger:trigger];
+
+ [center addNotificationRequest:request withCompletionHandler:nil];
+}
+
+void sendOsXUpdateNotification(const QString &title, const QString &message, const QUrl &webUrl)
+{
+ UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
+ checkNotificationAuth();
+
+ UNMutableNotificationContent * const content = basicNotificationContent(title, message);
+ content.categoryIdentifier = @"UPDATE";
+ content.userInfo = [NSDictionary dictionaryWithObject:[webUrl.toNSURL() absoluteString] forKey:@"webUrl"];
+
+ UNTimeIntervalNotificationTrigger * const trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];
+ UNNotificationRequest * const request = [UNNotificationRequest requestWithIdentifier:@"NCUpdateNotification" content:content trigger:trigger];
+
+ [center addNotificationRequest:request withCompletionHandler:nil];
+}
+
+void sendOsXTalkNotification(const QString &title, const QString &message, const QString &token, const QString &replyTo, const AccountStatePtr accountState)
+{
+ UNUserNotificationCenter * const center = UNUserNotificationCenter.currentNotificationCenter;
+ checkNotificationAuth();
+
+ if (!accountState || !accountState->account()) {
+ sendOsXUserNotification(title, message);
+ return;
+ }
+
+ NSString * const accountNS = accountState->account()->displayName().toNSString();
+ NSString * const tokenNS = token.toNSString();
+ NSString * const replyToNS = replyTo.toNSString();
+
+ UNMutableNotificationContent * const content = basicNotificationContent(title, message);
+ content.categoryIdentifier = @"TALK_MESSAGE";
+ content.userInfo = [NSDictionary dictionaryWithObjects:@[accountNS, tokenNS, replyToNS] forKeys:@[@"account", @"token", @"replyTo"]];
+
+ UNTimeIntervalNotificationTrigger * const trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];
+ UNNotificationRequest * const request = [UNNotificationRequest requestWithIdentifier:@"NCTalkMessageNotification" content:content trigger:trigger];
+
+ [center addNotificationRequest:request withCompletionHandler:nil];
+}
+
+} // OCC namespace