Browse Source

Add Talk message type of notifications to native macOS notifications

Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
Claudio Cambra 3 years ago
parent
commit
d2e0afa070
1 changed files with 106 additions and 11 deletions
  1. 106 11
      src/gui/systray.mm

+ 106 - 11
src/gui/systray.mm

@@ -1,5 +1,10 @@
 #include "QtCore/qurl.h"
+#include "account.h"
+#include "accountstate.h"
+#include "accountmanager.h"
 #include "config.h"
+#include "systray.h"
+#include "tray/talkreply.h"
 #include <QString>
 #include <QWindow>
 #include <QLoggingCategory>
@@ -9,6 +14,58 @@
 
 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
 @end
 @implementation NotificationCenterDelegate
@@ -34,23 +91,24 @@ Q_LOGGING_CATEGORY(lcMacSystray, "nextcloud.gui.macsystray")
     UNNotificationContent* content = response.notification.request.content;
     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.";
             [[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
 
-namespace OCC {
+/********************* Methods accessible to C++ Systray *********************/
 
-enum MacNotificationAuthorizationOptions {
-    Default = 0,
-    Provisional
-};
+namespace OCC {
 
 double menuBarThickness()
 {
@@ -93,10 +151,24 @@ void registerNotificationCategories(const QString &localisedDownloadString) {
           intentIdentifiers:@[]
           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];
     UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert + UNAuthorizationOptionSound;
@@ -170,6 +242,30 @@ void sendOsXUpdateNotification(const QString &title, const QString &message, con
     [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)
 {
     NSView *nativeView = (NSView *)window->winId();
@@ -185,5 +281,4 @@ bool osXInDarkMode()
     return [osxMode containsString:@"Dark"];
 }
 
-}
-
+} // OCC namespace