aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lisp/mastodon-notifications.el267
-rw-r--r--lisp/mastodon-tl.el195
-rw-r--r--lisp/mastodon-toot.el26
-rw-r--r--lisp/mastodon.el32
4 files changed, 306 insertions, 214 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."
diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el
index 0e61e29..3ebfa4e 100644
--- a/lisp/mastodon-tl.el
+++ b/lisp/mastodon-tl.el
@@ -598,51 +598,77 @@ Do so if type of status at poins is not follow_request/follow."
(string= type "follow")) ; no counts for these
(message "%s" echo)))))
-(defun mastodon-tl--byline-author (toot &optional avatar domain)
+;; FIXME: now that this can also be used for non byline rendering, let's remove
+;; the toot arg, and deal with attachments higher up (on real author
+;; byline only)
+;; removing toot arg makes it easier to render notifs that have no status
+;; (foll_reqs)
+(defun mastodon-tl--byline-username (toot &optional account)
+ "Format a byline username from account in TOOT."
+ (let-alist (or account (alist-get 'account toot))
+ (propertize (if (not (string-empty-p .display_name))
+ .display_name
+ .username)
+ 'face 'mastodon-display-name-face
+ ;; enable playing of videos when point is on byline:
+ 'attachments (mastodon-tl--get-attachments-for-byline toot)
+ 'keymap mastodon-tl--byline-link-keymap
+ ;; echo faves count when point on post author name:
+ ;; which is where --goto-next-toot puts point.
+ 'help-echo
+ ;; but don't add it to "following"/"follows" on
+ ;; profile views: we don't have a tl--buffer-spec
+ ;; yet:
+ (unless (or (string-suffix-p "-followers*" (buffer-name))
+ (string-suffix-p "-following*" (buffer-name)))
+ (mastodon-tl--format-byline-help-echo toot)))))
+
+(defun mastodon-tl--byline-handle (toot &optional domain account)
+ "Format a byline handle from account in TOOT.
+DOMAIN is optionally added to the handle."
+ (let-alist (or account (alist-get 'account toot))
+ (propertize (concat "@" .acct
+ (when domain
+ (concat "@"
+ (url-host
+ (url-generic-parse-url .url)))))
+ 'face 'mastodon-handle-face
+ 'mouse-face 'highlight
+ 'mastodon-tab-stop 'user-handle
+ 'account account
+ 'shr-url .url
+ 'keymap mastodon-tl--link-keymap
+ 'mastodon-handle (concat "@" .acct)
+ 'help-echo (concat "Browse user profile of @" .acct))))
+
+(defun mastodon-tl--byline-uname-+-handle (data &optional domain account)
+ ""
+ (concat (mastodon-tl--byline-username data account)
+ " (" (mastodon-tl--byline-handle data domain account) ")"))
+
+(defun mastodon-tl--byline-author (toot &optional avatar domain base)
"Propertize author of TOOT.
+If TOOT contains a reblog, return author of reblogged item.
With arg AVATAR, include the account's avatar image.
-When DOMAIN, force inclusion of user's domain in their handle."
- (let-alist toot
+When DOMAIN, force inclusion of user's domain in their handle.
+BASE means to use data from the base item (reblog slot) if possible.
+If BASE is nil, we are a boosted byline, so show less info."
+ (let* ((data (if base
+ (mastodon-tl--toot-or-base toot)
+ toot)))
(concat
- ;; avatar insertion moved up to `mastodon-tl--byline' by default to be
- ;; outside 'byline propt.
+ ;; 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 .account.avatar))
- ;; username:
- (propertize (if (not (string-empty-p .account.display_name))
- .account.display_name
- .account.username)
- 'face 'mastodon-display-name-face
- ;; enable playing of videos when point is on byline:
- 'attachments (mastodon-tl--get-attachments-for-byline toot)
- 'keymap mastodon-tl--byline-link-keymap
- ;; echo faves count when point on post author name:
- ;; which is where --goto-next-toot puts point.
- 'help-echo
- ;; but don't add it to "following"/"follows" on profile views:
- ;; we don't have a tl--buffer-spec yet:
- (unless (or (string-suffix-p "-followers*" (buffer-name))
- (string-suffix-p "-following*" (buffer-name)))
- (mastodon-tl--format-byline-help-echo toot)))
- ;; handle:
- " ("
- (propertize (concat "@" .account.acct
- (when domain
- (concat "@"
- (url-host
- (url-generic-parse-url .account.url)))))
- 'face 'mastodon-handle-face
- 'mouse-face 'highlight
- 'mastodon-tab-stop 'user-handle
- 'account .account
- 'shr-url .account.url
- 'keymap mastodon-tl--link-keymap
- 'mastodon-handle (concat "@" .account.acct)
- 'help-echo (concat "Browse user profile of @" .account.acct))
- ")")))
+ (mastodon-media--get-avatar-rendering
+ (alist-get 'avatar
+ (alist-get 'account data))))
+ (if (not base)
+ (mastodon-tl--byline-handle data domain)
+ (mastodon-tl--byline-uname-+-handle data domain)))))
(defun mastodon-tl--format-byline-help-echo (toot)
"Format a help-echo for byline of TOOT.
@@ -690,13 +716,28 @@ The result is added as an attachments property to author-byline."
:type .type)))
media)))
-(defun mastodon-tl--byline-boosted (toot)
- "Add byline for boosted data from TOOT."
+(defun mastodon-tl--byline-booster (toot)
+ "Add author byline for booster from TOOT.
+Only return something if TOOT contains a reblog."
(let ((reblog (alist-get 'reblog toot)))
- (when reblog
- (concat
- "\n " (propertize "Boosted" 'face 'mastodon-boosted-face)
- " " (mastodon-tl--byline-author reblog)))))
+ (if reblog
+ (concat
+ " " (mastodon-tl--byline-author toot))
+ "")))
+
+(defun mastodon-tl--byline-booster-str (toot)
+ "Format boosted string for action byline.
+Only return string if TOOT contains a reblog."
+ (let ((reblog (alist-get 'reblog toot)))
+ (if reblog
+ (concat
+ " " (propertize "boosted" 'face 'mastodon-boosted-face) "\n")
+ "")))
+
+(defun mastodon-tl--byline-boost (toot)
+ "Format a boost action-byline element for TOOT."
+ (concat (mastodon-tl--byline-booster toot)
+ (mastodon-tl--byline-booster-str toot)))
(defun mastodon-tl--format-faved-or-boosted-byline (letter)
"Format the byline marker for a boosted or favourited status.
@@ -719,8 +760,8 @@ LETTER is a string, F for favourited, B for boosted, or K for bookmarked."
(image-type-available-p 'imagemagick)
(image-transforms-p)))
-(defun mastodon-tl--byline (toot author-byline action-byline
- &optional detailed-p domain base-toot)
+(defun mastodon-tl--byline (toot author-byline &optional detailed-p
+ domain base-toot group)
"Generate byline for TOOT.
AUTHOR-BYLINE is a function for adding the author portion of
the byline that takes one variable.
@@ -732,23 +773,25 @@ this just means displaying toot client.
When DOMAIN, force inclusion of user's domain in their handle.
BASE-TOOT is JSON for the base toot, if any."
(let* ((created-time
- ;; bosts and faves in notifs view
- ;; (makes timestamps be for the original toot not the boost/fave):
- (or (mastodon-tl--field 'created_at
- (mastodon-tl--field 'status toot))
- ;; all other toots, inc. boosts/faves in timelines:
- ;; (mastodon-tl--field auto fetches from reblogs if needed):
- (mastodon-tl--field 'created_at toot)))
+ (if group
+ (mastodon-tl--field 'latest_page_notification_at group)
+ ;; bosts and faves in notifs view
+ ;; (makes timestamps be for the original toot not the boost/fave):
+ (or (mastodon-tl--field 'created_at
+ (mastodon-tl--field 'status toot))
+ ;; all other toots, inc. boosts/faves in timelines:
+ ;; (mastodon-tl--field auto fetches from reblogs if needed):
+ (mastodon-tl--field 'created_at toot))))
(parsed-time (date-to-time created-time))
(faved (eq t (mastodon-tl--field 'favourited toot)))
(boosted (eq t (mastodon-tl--field 'reblogged toot)))
(bookmarked (eq t (mastodon-tl--field 'bookmarked toot)))
(visibility (mastodon-tl--field 'visibility toot))
- (account (alist-get 'account toot))
- (avatar-url (alist-get 'avatar account))
(type (alist-get 'type toot))
(base-toot-maybe (or base-toot ;; show edits for notifs
(mastodon-tl--toot-or-base toot))) ;; for boosts
+ (account (alist-get 'account base-toot-maybe))
+ (avatar-url (alist-get 'avatar account))
(edited-time (alist-get 'edited_at base-toot-maybe))
(edited-parsed (when edited-time (date-to-time edited-time))))
(concat
@@ -768,17 +811,16 @@ BASE-TOOT is JSON for the base toot, if any."
(when bookmarked
(mastodon-tl--format-faved-or-boosted-byline
(mastodon-tl--symbol 'bookmark))))
- ;; we remove avatars from the byline also, so that they also do not mess
- ;; with `mastodon-tl--goto-next-item':
+ ;; we remove avatars from the byline also, so that they also do not
+ ;; mess with `mastodon-tl--goto-next-item':
(when (and mastodon-tl--show-avatars
mastodon-tl--display-media-p
(mastodon-tl--image-trans-check))
(mastodon-media--get-avatar-rendering avatar-url))
(propertize
(concat
- ;; we propertize help-echo format faves for author name
- ;; in `mastodon-tl--byline-author'
- (funcall author-byline toot nil domain)
+ ;; NB: action-byline (boost) is now added in insert-status, so no
+ ;; longer part of the byline.
;; visibility:
(cond ((string= visibility "direct")
(propertize (concat " " (mastodon-tl--symbol 'direct))
@@ -786,8 +828,8 @@ BASE-TOOT is JSON for the base toot, if any."
((string= visibility "private")
(propertize (concat " " (mastodon-tl--symbol 'private))
'help-echo visibility)))
- ;;action byline:
- (funcall action-byline toot)
+ ;; (base) author byline:
+ (funcall author-byline toot nil domain :base)
" "
;; timestamp:
(let ((ts (format-time-string
@@ -1164,7 +1206,7 @@ content should be hidden."
(save-excursion
(goto-char (point-min))
(while (not (string= "No more items" ; improve this hack test!
- (mastodon-tl--goto-next-item :no-refresh)))
+ (mastodon-tl--goto-next-item :no-refresh)))
(let* ((json (mastodon-tl--property 'item-json :no-move))
(cw (alist-get 'spoiler_text json)))
(when (not (string= "" cw))
@@ -1574,7 +1616,7 @@ Runs `mastodon-tl--render-text' and fetches poll or media."
(defun mastodon-tl--insert-status
(toot body author-byline action-byline &optional id base-toot
- detailed-p thread domain unfolded no-byline)
+ detailed-p thread domain unfolded no-byline group accounts)
"Display the content and byline of timeline element TOOT.
BODY will form the section of the toot above the byline.
AUTHOR-BYLINE is an optional function for adding the author
@@ -1594,11 +1636,14 @@ THREAD means the status will be displayed in a thread view.
When DOMAIN, force inclusion of user's domain in their handle.
UNFOLDED is a boolean meaning whether to unfold or fold item if foldable.
NO-BYLINE means just insert toot body, used for folding."
- (let* ((reply-to-id (alist-get 'in_reply_to_id toot))
+ (let* ((reply-to-id
+ (if group
+ (alist-get 'status_id group)
+ (alist-get 'in_reply_to_id toot)))
(after-reply-status-p
(when (and thread reply-to-id)
(mastodon-tl--after-reply-status reply-to-id)))
- (type (alist-get 'type toot))
+ (type (alist-get 'type (or group toot)))
(toot-foldable
(and mastodon-tl--fold-toots-at-length
(length> body mastodon-tl--fold-toots-at-length))))
@@ -1625,9 +1670,11 @@ NO-BYLINE means just insert toot body, used for folding."
'toot-body t) ;; includes newlines etc. for folding
;; byline:
"\n"
- (unless no-byline
- (mastodon-tl--byline toot author-byline action-byline
- detailed-p domain base-toot)))
+ (if no-byline
+ ""
+ (concat (funcall action-byline toot)
+ (mastodon-tl--byline toot author-byline detailed-p
+ domain base-toot group))))
'item-type 'toot
'item-id (or id ; notification's own id
(alist-get 'id toot)) ; toot id
@@ -1639,9 +1686,11 @@ NO-BYLINE means just insert toot body, used for folding."
'item-json toot
'base-toot base-toot
'cursor-face 'mastodon-cursor-highlight-face
- 'notification-type type
'toot-foldable toot-foldable
- 'toot-folded (and toot-foldable (not unfolded)))
+ 'toot-folded (and toot-foldable (not unfolded))
+ 'notification-type type
+ 'notification-group group
+ 'notification-accounts accounts)
(if no-byline "" "\n"))))
(defun mastodon-tl--is-reply (toot)
@@ -1712,7 +1761,7 @@ NO-BYLINE means just insert toot body, used for folding."
(mastodon-tl--insert-status
toot
(mastodon-tl--clean-tabs-and-nl spoiler-or-content)
- 'mastodon-tl--byline-author 'mastodon-tl--byline-boosted
+ #'mastodon-tl--byline-author #'mastodon-tl--byline-boost
nil nil detailed-p thread domain unfolded no-byline))))
(defun mastodon-tl--timeline (toots &optional thread domain)
@@ -2806,7 +2855,7 @@ Aims to respect any pagination in effect."
((eq type 'mentions)
(mastodon-notifications--get-mentions))
((eq type 'notifications)
- (mastodon-notifications-get nil nil :force max-id))
+ (mastodon-notifications-get nil nil max-id))
((eq type 'profile-statuses-no-boosts)
;; TODO: max-id arg needed here also
(mastodon-profile--open-statuses-no-reblogs))
diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el
index 9aeb790..386b720 100644
--- a/lisp/mastodon-toot.el
+++ b/lisp/mastodon-toot.el
@@ -522,21 +522,33 @@ SUBTRACT means we are un-favouriting or unboosting, so we decrement."
(defun mastodon-toot--list-boosters ()
"List the boosters of toot at point."
(interactive)
- (mastodon-toot--list-boosters-or-favers))
+ ;; use grouped notifs data if present:
+ ;; only send accounts as arg if type matches notif type we are acting
+ ;; on, to prevent showing accounts for a boost notif when asking for
+ ;; favers, and vice versa.
+ (let* ((type (mastodon-tl--property 'notification-type :no-move))
+ (accounts (when (string= type "reblog")
+ (mastodon-tl--property 'notification-accounts :no-move))))
+ (mastodon-toot--list-boosters-or-favers nil accounts)))
(defun mastodon-toot--list-favouriters ()
"List the favouriters of toot at point."
(interactive)
- (mastodon-toot--list-boosters-or-favers :favourite))
+ (let* ((type (mastodon-tl--property 'notification-type :no-move))
+ (accounts (when (string= type "favourite")
+ (mastodon-tl--property 'notification-accounts :no-move))))
+ (mastodon-toot--list-boosters-or-favers :favourite accounts)))
-(defun mastodon-toot--list-boosters-or-favers (&optional favourite)
+(defun mastodon-toot--list-boosters-or-favers (&optional favourite accounts)
"List the favouriters or boosters of toot at point.
With FAVOURITE, list favouriters, else list boosters."
(mastodon-toot--with-toot-item
- (let* ((endpoint (if favourite "favourited_by" "reblogged_by"))
- (url (mastodon-http--api (format "statuses/%s/%s" id endpoint)))
- (params '(("limit" . "80")))
- (json (mastodon-http--get-json url params)))
+ (let* ((endpoint (unless accounts
+ (if favourite "favourited_by" "reblogged_by")))
+ (url (unless accounts
+ (mastodon-http--api (format "statuses/%s/%s" id endpoint))))
+ (params (unless accounts '(("limit" . "80"))))
+ (json (or accounts (mastodon-http--get-json url params))))
(if (eq (caar json) 'error)
(user-error "%s (Status does not exist or is private)"
(alist-get 'error json))
diff --git a/lisp/mastodon.el b/lisp/mastodon.el
index a8714f3..80b6d8c 100644
--- a/lisp/mastodon.el
+++ b/lisp/mastodon.el
@@ -347,28 +347,25 @@ If REPLY-JSON is the json of the toot being replied to."
(mastodon-toot--compose-buffer user reply-to-id reply-json))
;;;###autoload
-(defun mastodon-notifications-get (&optional type buffer-name force max-id)
+(defun mastodon-notifications-get (&optional type buffer-name max-id)
"Display NOTIFICATIONS in buffer.
Optionally only print notifications of type TYPE, a string.
BUFFER-NAME is added to \"*mastodon-\" to create the buffer name.
-FORCE means do not try to update an existing buffer, but fetch
-from the server and load anew."
+MAX-ID is a request parameter for pagination."
(interactive)
(let* ((buffer-name (or buffer-name "notifications"))
(buffer (concat "*mastodon-" buffer-name "*")))
- (if (and (not force) (get-buffer buffer))
- (progn (pop-to-buffer buffer '(display-buffer-same-window))
- (mastodon-tl--update))
- (message "Loading your notifications...")
- (mastodon-tl--init-sync
- buffer-name
- "notifications"
- 'mastodon-notifications--timeline
- type
- (when max-id
- `(("max_id" . ,(mastodon-tl--buffer-property 'max-id)))))
- (with-current-buffer buffer
- (use-local-map mastodon-notifications--map)))))
+ (message "Loading your notifications...")
+ (mastodon-tl--init-sync
+ buffer-name
+ "notifications"
+ 'mastodon-notifications--timeline
+ type
+ (when max-id
+ `(("max_id" . ,(mastodon-tl--buffer-property 'max-id))))
+ nil nil nil "v2")
+ (with-current-buffer (get-buffer-create buffer)
+ (use-local-map mastodon-notifications--map))))
;; URL lookup: should be available even if `mastodon.el' not loaded:
@@ -378,7 +375,8 @@ from the server and load anew."
Does a WebFinger lookup on the server.
URL can be arg QUERY-URL, or URL at point, or provided by the user.
If a status or account is found, load it in `mastodon.el', if
-not, just browse the URL in the normal fashion."
+not, just browse the URL in the normal fashion.
+If FORCE, do a lookup regardless of the result of `mastodon--fedi-url-p'."
(interactive)
(let* ((query (or query-url
(mastodon-tl--property 'shr-url :no-move)