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