branch: elpa/jabber
commit 41d7be9b6a6117a34b4f5909c28cd2361d742826
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>

    notifications: Open chats from desktop notifications
---
 Makefile                           |  1 +
 lisp/jabber-notifications.el       | 30 +++++++++++--
 tests/jabber-test-notifications.el | 87 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile
index 4d6f7d6fe4..17eb10f816 100644
--- a/Makefile
+++ b/Makefile
@@ -39,6 +39,7 @@ TESTS ?= tests/jabber-test-activity.el \
          tests/jabber-test-modeline.el \
          tests/jabber-test-moderation.el \
          tests/jabber-test-muc.el \
+         tests/jabber-test-notifications.el \
          tests/jabber-test-omemo-message.el \
          tests/jabber-test-omemo-module.el \
          tests/jabber-test-omemo-protocol.el \
diff --git a/lisp/jabber-notifications.el b/lisp/jabber-notifications.el
index 655333cd16..d0486d676c 100644
--- a/lisp/jabber-notifications.el
+++ b/lisp/jabber-notifications.el
@@ -67,11 +67,30 @@ nil disables MUC notifications entirely."
 
 ;;
 
-(defun jabber-message-notifications (from _buffer text title)
+(defun jabber-notifications--remove-action-callback (callback)
+  "Remove CALLBACK from the pending notification actions."
+  (setq notifications-on-action-map
+        (cl-delete callback notifications-on-action-map
+                   :key #'cadr :test #'eq))
+  (when (and (null notifications-on-action-map)
+             notifications-on-action-object)
+    (dbus-unregister-object notifications-on-action-object)
+    (setq notifications-on-action-object nil)))
+
+(defun jabber-message-notifications (from buffer text title)
   "Show a message from FROM through the notifications.el interface.
-TEXT is the message body and TITLE the notification title."
-  (let ((body (or (jabber-escape-xml text) " "))
-        (avatar-hash (get (jabber-jid-symbol from) 'avatar-hash)))
+BUFFER is the associated chat buffer, TEXT is the message body, and
+TITLE is the notification title."
+  (letrec ((body (or (jabber-escape-xml text) " "))
+           (avatar-hash (get (jabber-jid-symbol from) 'avatar-hash))
+           (action-callback
+            (lambda (&rest _)
+              (when (buffer-live-p buffer)
+                (pop-to-buffer buffer))))
+           (close-callback
+            (lambda (&rest _)
+              (jabber-notifications--remove-action-callback
+               action-callback))))
     (condition-case err
         (notifications-notify
          :title title
@@ -80,6 +99,9 @@ TEXT is the message body and TITLE the notification title."
                        jabber-notifications-icon)
          :app-name jabber-notifications-app
          :category "jabber.message"
+         :actions '("default" "Switch to buffer")
+         :on-action action-callback
+         :on-close close-callback
          :timeout jabber-notifications-timeout)
       (dbus-error
        (message "jabber-notifications: D-Bus error: %s" (error-message-string 
err))))))
diff --git a/tests/jabber-test-notifications.el 
b/tests/jabber-test-notifications.el
new file mode 100644
index 0000000000..06b540a6b3
--- /dev/null
+++ b/tests/jabber-test-notifications.el
@@ -0,0 +1,87 @@
+;;; jabber-test-notifications.el --- Tests for jabber-notifications  -*- 
lexical-binding: t; -*-
+
+;;; Commentary:
+
+;; Desktop notification actions.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'jabber-notifications)
+
+(defun jabber-test-notifications--arguments (buffer)
+  "Return notification arguments produced for BUFFER."
+  (let (arguments)
+    (cl-letf (((symbol-function 'notifications-notify)
+               (lambda (&rest args)
+                 (setq arguments args))))
+      (jabber-message-notifications
+       "[email protected]" buffer "Hello" "Romeo"))
+    arguments))
+
+(ert-deftest jabber-test-notifications-default-action ()
+  (with-temp-buffer
+    (should (equal (plist-get (jabber-test-notifications--arguments
+                               (current-buffer))
+                              :actions)
+                   '("default" "Switch to buffer")))))
+
+(ert-deftest jabber-test-notifications-action-opens-chat-buffer ()
+  (with-temp-buffer
+    (let* ((buffer (current-buffer))
+           (callback (plist-get
+                      (jabber-test-notifications--arguments buffer)
+                      :on-action))
+           opened)
+      (cl-letf (((symbol-function 'pop-to-buffer)
+                 (lambda (target &rest _)
+                   (setq opened target))))
+        (funcall callback "notification-id" "default"))
+      (should (eq opened buffer)))))
+
+(ert-deftest jabber-test-notifications-action-ignores-killed-buffer ()
+  (let* ((buffer (generate-new-buffer " jabber-notification-test"))
+         (callback (plist-get
+                    (jabber-test-notifications--arguments buffer)
+                    :on-action)))
+    (kill-buffer buffer)
+    (cl-letf (((symbol-function 'pop-to-buffer)
+               (lambda (&rest _)
+                 (ert-fail "pop-to-buffer called for a killed buffer"))))
+      (should-not (funcall callback "notification-id" "default")))))
+
+(ert-deftest jabber-test-notifications-close-removes-only-own-action ()
+  (with-temp-buffer
+    (let* ((arguments (jabber-test-notifications--arguments
+                       (current-buffer)))
+           (action (plist-get arguments :on-action))
+           (on-close (plist-get arguments :on-close))
+           (other-action (lambda (&rest _)))
+           (notifications-on-action-map
+            `(((bus service 1) ,action)
+              ((bus service 2) ,other-action))))
+      (funcall on-close "notification-id" 'expired)
+      (should (equal notifications-on-action-map
+                     `(((bus service 2) ,other-action)))))))
+
+(ert-deftest jabber-test-notifications-close-unregisters-action-signal ()
+  (with-temp-buffer
+    (let* ((arguments (jabber-test-notifications--arguments
+                       (current-buffer)))
+           (action (plist-get arguments :on-action))
+           (on-close (plist-get arguments :on-close))
+           (notifications-on-action-map `(((bus service 1) ,action)))
+           (notifications-on-action-object 'action-signal)
+           unregistered)
+      (cl-letf (((symbol-function 'dbus-unregister-object)
+                 (lambda (object)
+                   (setq unregistered object))))
+        (funcall on-close "notification-id" 'expired))
+      (should (null notifications-on-action-map))
+      (should (eq unregistered 'action-signal))
+      (should (null notifications-on-action-object)))))
+
+(provide 'jabber-test-notifications)
+
+;;; jabber-test-notifications.el ends here

Reply via email to