aboutsummaryrefslogtreecommitdiff
path: root/lisp/mastodon-notifications.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/mastodon-notifications.el')
-rw-r--r--lisp/mastodon-notifications.el267
1 files changed, 150 insertions, 117 deletions
diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el
index 2091118..b758c6f 100644
--- a/lisp/mastodon-notifications.el
+++ b/lisp/mastodon-notifications.el
@@ -162,40 +162,6 @@ Can be called in notifications view or in follow-requests view."
(interactive)
(mastodon-notifications--follow-request-process :reject))
-(defun mastodon-notifications--mention (note)
- "Format for a `mention' NOTE."
- (mastodon-notifications--format-note note 'mention))
-
-(defun mastodon-notifications--follow (note)
- "Format for a `follow' NOTE."
- (mastodon-notifications--format-note note 'follow))
-
-(defun mastodon-notifications--follow-request (note)
- "Format for a `follow-request' NOTE."
- (mastodon-notifications--format-note note 'follow-request))
-
-(defun mastodon-notifications--favourite (note)
- "Format for a `favourite' NOTE."
- (mastodon-notifications--format-note note 'favourite))
-
-(defun mastodon-notifications--reblog (note)
- "Format for a `boost' NOTE."
- (mastodon-notifications--format-note note 'reblog))
-
-(defun mastodon-notifications--status (note)
- "Format for a `status' NOTE.
-Status notifications are given when
-`mastodon-tl--enable-notify-user-posts' has been set."
- (mastodon-notifications--format-note note 'status))
-
-(defun mastodon-notifications--poll (note)
- "Format for a `poll' NOTE."
- (mastodon-notifications--format-note note 'poll))
-
-(defun mastodon-notifications--edit (note)
- "Format for an `edit' NOTE."
- (mastodon-notifications--format-note note 'edit))
-
(defun mastodon-notifications--comment-note-text (str)
"Add comment face to all text in STR with `shr-text' face only."
(with-temp-buffer
@@ -208,106 +174,173 @@ Status notifications are given when
'(face (font-lock-comment-face shr-text)))))
(buffer-string)))
+(defvar mastodon-notifications-grouped-types
+ '(follow reblog favourite)
+ "List of notification types for which grouping is implemented.")
+
(defvar mastodon-notifications--action-alist
'((reblog . "Boosted")
(favourite . "Favourited")
- (follow-request . "Requested to follow")
+ (follow_request . "Requested to follow")
(follow . "Followed")
(mention . "Mentioned")
(status . "Posted")
(poll . "Posted a poll")
- (edit . "Edited")))
-
-(defun mastodon-notifications--format-note (note type)
- "Format for a NOTE of TYPE."
+ (update . "Edited"))
+ "Action strings keyed by notification type.
+Types are those of the Mastodon API.")
+
+(defun mastodon-notifications--alist-by-value (str field json)
+ "From JSON, return the alist whose FIELD value matches STR.
+JSON is a list of alists."
+ (cl-some (lambda (y)
+ (when (string= str (alist-get field y))
+ y))
+ json))
+
+(defun mastodon-notifications--group-accounts (ids json)
+ "For IDS, return account data in JSON."
+ (cl-loop
+ for x in ids
+ collect (mastodon-notifications--alist-by-value x 'id json)))
+
+(defun mastodon-notifications--format-note (group status accounts)
+ "Format for a GROUP notification.
+JSON is the full notifications JSON."
;; FIXME: apply/refactor filtering as per/with `mastodon-tl--toot'
- (let* ((id (alist-get 'id note))
- (profile-note
- (when (eq 'follow-request type)
- (let ((str (mastodon-tl--field
- 'note
- (mastodon-tl--field 'account note))))
- (if mastodon-notifications--profile-note-in-foll-reqs-max-length
- (string-limit str mastodon-notifications--profile-note-in-foll-reqs-max-length)
- str))))
- (status (mastodon-tl--field 'status note))
- (follower (alist-get 'username (alist-get 'account note)))
- (toot (alist-get 'status note))
- (filtered (mastodon-tl--field 'filtered toot))
- (filters (when filtered
- (mastodon-tl--current-filters filtered))))
- (if (and filtered (assoc "hide" filters))
- nil
- (mastodon-tl--insert-status
- ;; toot
- (cond ((member type '(follow follow-request))
- ;; Using reblog with an empty id will mark this as something
- ;; non-boostable/non-favable.
- (cons '(reblog (id . nil)) note))
- ;; reblogs/faves use 'note' to process their own json
- ;; not the toot's. this ensures following etc. work on such notifs
- ((member type '(favourite reblog))
- note)
- (t status))
- ;; body
- (let ((body (if-let ((match (assoc "warn" filters)))
- (mastodon-tl--spoiler toot (cadr match))
- (mastodon-tl--clean-tabs-and-nl
- (if (mastodon-tl--has-spoiler status)
- (mastodon-tl--spoiler status)
- (if (eq 'follow-request type)
- (mastodon-tl--render-text profile-note)
- (mastodon-tl--content status)))))))
- (cond ((eq type 'follow)
- (propertize "Congratulations, you have a new follower!"
- 'face 'default))
- ((eq type 'follow-request)
- (concat
- (propertize
- (format "You have a follow request from... %s"
- follower)
- 'face 'default)
- (if mastodon-notifications--profile-note-in-foll-reqs
+ (let-alist group
+ ;; .sample_account_ids .status_id .notifications_count
+ ;; .most_recent_notifiation_id
+ (let* ((type .type)
+ (type-sym (intern .type))
+ (profile-note
+ (when (eq type-sym 'follow_request)
+ (let ((str (mastodon-tl--field 'note (car accounts))))
+ (if mastodon-notifications--profile-note-in-foll-reqs-max-length
+ (string-limit str mastodon-notifications--profile-note-in-foll-reqs-max-length)
+ str))))
+ (follower (car .sample_account_ids))
+ (follower-name (mastodon-tl--field 'username (car accounts)))
+ (filtered (mastodon-tl--field 'filtered status)) ;;toot))
+ (filters (when filtered
+ (mastodon-tl--current-filters filtered))))
+ (if (and filtered (assoc "hide" filters))
+ nil
+ (mastodon-tl--insert-status
+ ;; toot
+ (if (member type-sym '(follow follow_request))
+ ;; Using reblog with an empty id will mark this as something
+ ;; non-boostable/non-favable.
+ ;; status
+ (cons '(reblog (id . nil)) status) ;;note))
+ ;; reblogs/faves use 'note' to process their own json not the
+ ;; toot's. this ensures following etc. work on such notifs
+ status) ;; FIXME: fix following on these notifs
+ ;; body
+ (let ((body (if-let ((match (assoc "warn" filters)))
+ (mastodon-tl--spoiler toot (cadr match))
+ (mastodon-tl--clean-tabs-and-nl
+ (if (mastodon-tl--has-spoiler status)
+ (mastodon-tl--spoiler status)
+ (if (eq type-sym 'follow_request)
+ (mastodon-tl--render-text profile-note)
+ (mastodon-tl--content status)))))))
+ (cond ((eq type-sym 'follow)
+ (propertize "Congratulations, you have a new follower!"
+ 'face 'default))
+ ((eq type-sym 'follow_request)
+ (concat
+ (propertize
+ (format "You have a follow request from... %s"
+ follower-name)
+ 'face 'default)
+ (when mastodon-notifications--profile-note-in-foll-reqs
(concat
":\n"
- (mastodon-notifications--comment-note-text body))
- "")))
- ((member type '(favourite reblog))
- (mastodon-notifications--comment-note-text body))
- (t body)))
- ;; author-byline
- (if (member type '(follow follow-request mention))
- 'mastodon-tl--byline-author
- (lambda (_status &rest _args) ; unbreak stuff
- (mastodon-tl--byline-author note)))
- ;; action-byline
- (lambda (_status)
- (mastodon-notifications--byline-concat
- (alist-get type mastodon-notifications--action-alist)))
- id
- ;; base toot
- (when (member type '(favourite reblog))
- status)))))
-
-(defun mastodon-notifications--by-type (note)
+ (mastodon-notifications--comment-note-text body)))))
+ ((member type-sym '(favourite reblog))
+ (mastodon-notifications--comment-note-text body))
+ (t body)))
+ ;; author-byline
+ (cond ((member type-sym '(favourite reblog mention))
+ (lambda (&rest _args)
+ (mastodon-notifications--byline-accounts accounts status group)))
+ ((eq type-sym 'follow_request)
+ (lambda (&rest _args)
+ (mastodon-tl--byline-uname-+-handle status nil (car accounts))))
+ (t #'mastodon-tl--byline-author))
+ ;; #'mastodon-tl--byline-author
+ ;; action-byline
+ (lambda (&rest _args)
+ (mastodon-notifications--byline-concat
+ (alist-get type-sym mastodon-notifications--action-alist)))
+ .status_id
+ ;; base toot
+ (when (member type-sym '(favourite reblog))
+ status)
+ nil nil nil nil
+ nil group accounts))))) ;; insert status still needs our group data
+
+;; FIXME: REFACTOR with -tl--byline:
+;; we provide account directly, rather than let-alisting toot
+;; almost everything is .account.field anyway
+;; but toot still needed also, for attachments, etc.
+(defun mastodon-notifications--byline-accounts
+ (accounts toot group &optional avatar domain)
+ "Propertize author byline ACCOUNT for TOOT, the item responded to.
+With arg AVATAR, include the account's avatar image.
+When DOMAIN, force inclusion of user's domain in their handle."
+ (let ((others-count (- (alist-get 'notifications_count group)
+ (length accounts))))
+ (concat
+ (cl-loop
+ for account in accounts
+ concat
+ (let-alist account
+ (concat
+ ;; avatar insertion moved up to `mastodon-tl--byline' by default to
+ ;; be outside 'byline propt.
+ (when (and avatar ; used by `mastodon-profile--format-user'
+ mastodon-tl--show-avatars
+ mastodon-tl--display-media-p
+ (mastodon-tl--image-trans-check))
+ (mastodon-media--get-avatar-rendering .avatar))
+ ;; username:
+ (mastodon-tl--byline-username toot account)
+ ;; handle:
+ " (" (mastodon-tl--byline-handle toot nil account) ")"
+ (if (< 1 (length accounts)) "\n" ""))))
+ (if (< 0 others-count)
+ (format "and %s others" others-count)))))
+
+(defun mastodon-notifications--by-type (groups json)
"Filter NOTE for those listed in `mastodon-notifications--types-alist'.
Call its function in that list on NOTE."
- (let* ((type (mastodon-tl--field 'type note))
- (fun (cdr (assoc type mastodon-notifications--types-alist)))
- (start-pos (point)))
- (when fun
- (funcall fun note)
- (when mastodon-tl--display-media-p
- ;; images-in-notifs custom is handeld in
- ;; `mastodon-tl--media-attachment', not here
- (mastodon-media--inline-images start-pos (point))))))
+ (setq masto-grouped-notifs json)
+ (cl-loop
+ for g in groups
+ for start-pos = (point)
+ for accounts = (mastodon-notifications--group-accounts
+ (alist-get 'sample_account_ids g)
+ (alist-get 'accounts json))
+ for status = (mastodon-notifications--alist-by-value
+ (alist-get 'status_id g) 'id
+ (alist-get 'statuses json))
+ do (mastodon-notifications--format-note g status accounts)
+ (when mastodon-tl--display-media-p
+ ;; images-in-notifs custom is handeld in
+ ;; `mastodon-tl--media-attachment', not here
+ (mastodon-media--inline-images start-pos (point)))))
(defun mastodon-notifications--timeline (json)
"Format JSON in Emacs buffer."
(if (seq-empty-p json)
(user-error "Looks like you have no (more) notifications for now")
- (mapc #'mastodon-notifications--by-type json)
- (goto-char (point-min))))
+ (let ((groups (alist-get 'notification_groups json)))
+ ;; (mapc (lambda (x)
+ (mastodon-notifications--by-type groups json)
+ ;; grouped)
+ (goto-char (point-min)))))
(defun mastodon-notifications--get-mentions ()
"Display mention notifications in buffer."