emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/mastodon 31557be472 50/50: Merge branch 'develop'


From: ELPA Syncer
Subject: [nongnu] elpa/mastodon 31557be472 50/50: Merge branch 'develop'
Date: Sat, 2 Nov 2024 13:00:58 -0400 (EDT)

branch: elpa/mastodon
commit 31557be472a94b48163a5651640d3e807a6cbdf2
Merge: 7623478121 6242db6028
Author: marty hiatt <martianhiatus@disroot.org>
Commit: marty hiatt <martianhiatus@disroot.org>

    Merge branch 'develop'
---
 Cask                           |   1 -
 README.org                     |  71 +++++-----
 lisp/mastodon-notifications.el | 291 +++++++++++++++++++++++------------------
 lisp/mastodon-profile.el       |   4 +-
 lisp/mastodon-tl.el            | 265 +++++++++++++++++++------------------
 lisp/mastodon-toot.el          |  49 +++----
 lisp/mastodon-transient.el     |  16 ++-
 lisp/mastodon.el               |  29 +++-
 mastodon-index.org             |  96 +++++++-------
 9 files changed, 452 insertions(+), 370 deletions(-)

diff --git a/Cask b/Cask
index 6d0179de7e..36f13dfb81 100644
--- a/Cask
+++ b/Cask
@@ -9,5 +9,4 @@
  (depends-on "el-mock")
  (depends-on "ecukes")
  (depends-on "package-lint")
- (depends-on "elsa")
  (depends-on "async"))
diff --git a/README.org b/README.org
index 90222c7e2a..b2f4964300 100644
--- a/README.org
+++ b/README.org
@@ -171,6 +171,7 @@ For a full list of commands and variables, see 
[[file:mastodon-index.org][mastod
 | =K=              | view bookmarked toots                                     
                      |
 | =X=              | view/edit/create/delete lists                             
                      |
 | =S=              | view your scheduled toots                                 
                      |
+| =S-:=            | view profile/account settings transient menu              
                      |
 
|----------------+---------------------------------------------------------------------------------|
 |                | *Toot actions*                                              
                      |
 | =t=              | Compose a new toot                                        
                      |
@@ -192,7 +193,7 @@ For a full list of commands and variables, see 
[[file:mastodon-index.org][mastod
 
|----------------+---------------------------------------------------------------------------------|
 |                | *Profile view*                                              
                      |
 | =C-c C-c=        | cycle between statuses, statuses without boosts, 
followers, and following       |
-|                | =mastodon-profile--account-account-to-list= (see lists 
view)                      |
+|                | =mastodon-profile--add-account-to-list= (see lists view)    
                         |
 
|----------------+---------------------------------------------------------------------------------|
 |                | *Notifications view*                                        
                      |
 | =a=, =j=           | accept/reject follow request                            
                        |
@@ -244,21 +245,22 @@ value of that hook is as follows:
 
 **** Keybindings
 
-|----------+-------------------------------|
-| Key      | Action                        |
-|----------+-------------------------------|
-| =C-c C-c=  | Send toot                     |
-| =C-c C-k=  | Cancel toot                   |
-| =C-c C-w=  | Add content warning           |
-| =C-c C-v=  | Change toot visibility        |
-| =C-c C-n=  | Add sensitive media/nsfw flag |
-| =C-c C-a=  | Upload attachment(s)          |
-| =C-c !=    | Remove all attachments        |
-| =C-c C-e=  | Insert emoji                  |
-| =C-c C-p=  | Create a poll                 |
-| =C-c C-l=  | Set toot language             |
-| =-C-c C-s= | Schedule toot                 |
-|----------+-------------------------------|
+|---------+-------------------------------|
+| Key     | Action                        |
+|---------+-------------------------------|
+| =C-c C-c= | Send toot                     |
+| =C-c C-k= | Cancel toot                   |
+| =C-c C-w= | Add content warning           |
+| =C-c C-v= | Change toot visibility        |
+| =C-c C-n= | Add sensitive media/nsfw flag |
+| =C-c C-a= | Upload attachment(s)          |
+| =C-c !=   | Remove all attachments        |
+| =C-c C-e= | Insert emoji                  |
+| =C-c C-p= | Create a poll                 |
+| =C-c C-o= | Cancel poll                   |
+| =C-c C-l= | Set toot language             |
+| =C-c C-s= | Schedule toot                 |
+|---------+-------------------------------|
 
 **** Autocompletion of mentions, tags and emoji
 
@@ -301,7 +303,7 @@ work without first loading a =mastodon.el= buffer:
 - =mastodon-search--trending-tags=: View a list of trending hashtags on your
   instance.
 - =mastodon-search--trending-statuses=: View a list of trending statuses on 
your instance.
-
+- =mastodon-search--trending-links=: View a list of trending links on your 
instance (+ click through to a timeline of posts featuring a given link)
 
 - =mastodon-tl--add-toot-account-at-point-to-list=: Add the account of the 
toot at point to a list.
 
@@ -330,21 +332,11 @@ work without first loading a =mastodon.el= buffer:
 - =mastodon-tl--remote-tag-timeline=: View a tag timeline on a remote instance.
 
 
-- =mastodon-profile--update-display-name=: Update the display name for your
-  account.
-- =mastodon-profile--update-user-profile-note=: Update your bio note.
-- =mastodon-profile--update-meta-fields=: Update your metadata fields.
-- =mastodon-profile--set-default-toot-visibility=: Set the default visibility
-  for your toots.
-- =mastodon-profile--account-locked-toggle=: Toggle the locked status of your
-  account. Locked accounts have to manually approve follow requests.
-- =mastodon-profile--account-discoverable-toggle=: Toggle the discoverable
-  status of your account. Non-discoverable accounts are not listed in the
-  profile directory.
-- =mastodon-profile--account-bot-toggle=: Toggle whether your account is 
flagged
-  as a bot.
-- =mastodon-profile--account-sensitive-toggle=: Toggle whether your posts are
-  marked as sensitive (nsfw) by default.
+- =mastodon-user-settings=: Launch a transient menu to update various account 
settings.
+
+*** Notifications
+
+Mastodon from 4.3 supports grouped notifications. These are implemented by 
=mastodon.el=. If you are on an instance that doesn't implement grouped 
notifications, set =mastodon-group-notifications= to nil.
 
 *** Customization
 
@@ -376,18 +368,24 @@ An index of all user-facing commands and custom variables 
is available here: [[f
 
 You can also hit =?= in any =mastodon.el= buffer to see the available 
bindings, or run =M-X= (upper-case =X=) to view all commands in the buffer with 
completion, and call one.
 
-*** Alternative timeline layout
+*** Packages related to =mastodon.el=
+
+**** Alternative timeline layout
 
 The incomparable Nicholas Rougier has written an alternative timeline layout
 for =mastodon.el=.
 
 The repo is at [[https://github.com/rougier/mastodon-alt][mastodon-alt]].
 
-*** mastodon hydra
+**** Mastodon hydra
 
-A user made a hydra for handling basic mastodon.el commands. It's available at
+A user made a hydra for handling basic =mastodon.el= commands. It's available 
at
 https://holgerschurig.github.io/en/emacs-mastodon-hydra/.
 
+**** Narrow to timeline item
+
+A simple code snippet to enable narrowing to current item in timelines: 
http://takeonrules.com/2024/10/31/hacking-on-mastodon-emacs-package-to-narrow-viewing/
+
 *** Live-updating timelines: =mastodon-async-mode=
 
 (code taken from 
[[https://github.com/alexjgriffith/mastodon-future.el][mastodon-future]].)
@@ -433,6 +431,7 @@ to your translator function as its text argument. Here's 
what
 Hard dependencies (should all install with =mastodon.el=):
 - =request= (for uploading attachments), 
[[https://github.com/tkf/emacs-request][emacs-request]]
 - =persist= for storing some settings across sessions
+- =tp.el= for transient menus
 
 Optional dependencies (install yourself, =mastodon.el= can use them):
 - =emojify= to use custom emoji (else we use builtin =emoji.el=)
@@ -506,7 +505,7 @@ Some significant contributors are:
 - https://github.com/hdurer
 - https://codeberg.org/Red_Starfish
 
-** screenshots
+** Screenshots
 
 Here's a (federated) timeline:
 
diff --git a/lisp/mastodon-notifications.el b/lisp/mastodon-notifications.el
index f4615fbcb6..238feacc1b 100644
--- a/lisp/mastodon-notifications.el
+++ b/lisp/mastodon-notifications.el
@@ -56,7 +56,6 @@
 (autoload 'mastodon-tl--render-text "mastodon-tl")
 (autoload 'mastodon-notifications-get "mastodon")
 (autoload 'mastodon-tl--byline-uname-+-handle "mastodon-tl")
-(autoload 'mastodon-tl--byline-username "mastodon-tl")
 (autoload 'mastodon-tl--byline-handle "mastodon-tl")
 (autoload 'mastodon-http--get-json "mastodon-http")
 (autoload 'mastodon-media--get-avatar-rendering "mastodon-media")
@@ -64,32 +63,17 @@
 (autoload 'mastodon-tl--symbol "mastodon-tl")
 (autoload 'mastodon-tl--display-or-uname "mastodon-tl")
 
-(defgroup mastodon-tl nil
-  "Nofications in mastodon.el."
-  :prefix "mastodon-notifications-"
-  :group 'mastodon)
-
-(defcustom mastodon-notifications--profile-note-in-foll-reqs t
-  "If non-nil, show a user's profile note in follow request notifications."
-  :type '(boolean))
-
-(defcustom mastodon-notifications--profile-note-in-foll-reqs-max-length nil
-  "The max character length for user profile note in follow requests.
-Profile notes are only displayed if
-`mastodon-notifications--profile-note-in-foll-reqs' is non-nil.
-If unset, profile notes of any size will be displayed, which may
-make them unweildy."
-  :type '(integer))
-
-(defcustom mastodon-notifications--images-in-notifs nil
-  "Whether to display attached images in notifications."
-  :type '(boolean))
+;; notifications defcustoms moved into mastodon.el
+;; as some need to be available without loading this file
 
 (defvar mastodon-tl--buffer-spec)
 (defvar mastodon-tl--display-media-p)
 (defvar mastodon-mode-map)
 (defvar mastodon-tl--fold-toots-at-length)
 (defvar mastodon-tl--show-avatars)
+(defvar mastodon-profile-note-in-foll-reqs)
+(defvar mastodon-profile-note-in-foll-reqs-max-length)
+(defvar mastodon-group-notifications)
 
 (defvar mastodon-notifications--types
   '("favourite" "reblog" "mention" "poll"
@@ -117,8 +101,8 @@ make them unweildy."
     map)
   "Keymap for viewing notifications.")
 
-(defun mastodon-notifications--byline-concat (message)
-  "Add byline for TOOT with MESSAGE."
+(defun mastodon-notifications--byline-action-str (message)
+  "Return an action (top) byline string for TOOT with MESSAGE."
   (concat " "
           (propertize message 'face 'mastodon-boosted-face)
           " " (cdr (assoc message mastodon-notifications--response-alist))
@@ -231,21 +215,56 @@ JSON is a list of alists."
             "\nfor account: "
             .target_account)))
 
-(defun mastodon-notifications--format-note (group status accounts)
+(defun mastodon-notifications--format-note (note)
+  "Format for a NOTE, a non-grouped notification."
+  (let* ((type (intern (alist-get 'type note)))
+         (profile-note
+          (when (eq 'follow_request type)
+            (let ((str (mastodon-tl--field
+                        'note
+                        (mastodon-tl--field 'account note))))
+              (if mastodon-profile-note-in-foll-reqs-max-length
+                  (string-limit str 
mastodon-profile-note-in-foll-reqs-max-length)
+                str))))
+         (status (mastodon-tl--field 'status note))
+         (follower (alist-get 'account note))
+         (follower-name (or (alist-get 'display_name follower)
+                            (alist-get 'username follower)))
+         (filtered (mastodon-tl--field 'filtered status))
+         (filters (when filtered
+                    (mastodon-tl--current-filters filtered))))
+    (if (and filtered (assoc "hide" filters))
+        nil
+      (mastodon-notifications--insert-note
+       ;; toot
+       ;; should always be note, otherwise notif data not avail
+       ;; later on:
+       note
+       ;; body
+       (mastodon-notifiations--body-arg
+        type filters status profile-note follower-name)
+       ;; action-byline (top)
+       (mastodon-notifications--action-byline
+        type nil nil note follower-name)
+       ;; base toot (always provide)
+       status
+       nil nil nil type))))
+
+(defun mastodon-notifications--format-group-note (group status accounts)
   "Format for a GROUP notification.
 STATUS is the status's JSON.
 ACCOUNTS is data of the accounts that have reacted to the notification."
   (let ((folded nil))
     ;; FIXME: apply/refactor filtering as per/with `mastodon-tl--toot'
     (let-alist group
-      (let* ((type-sym (intern .type))
+      (let* ((type (intern .type))
              (profile-note
-              (when (member type-sym '(follow_request))
+              (when (member type '(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)
+                  (if mastodon-profile-note-in-foll-reqs-max-length
+                      (string-limit str 
mastodon-profile-note-in-foll-reqs-max-length)
                     str))))
-             (follower (when (member type-sym '(follow follow_request))
+             (follower (when (member type '(follow follow_request))
                          (car accounts)))
              (follower-name (mastodon-tl--field 'username follower))
              (filtered (mastodon-tl--field 'filtered status))
@@ -254,107 +273,119 @@ ACCOUNTS is data of the accounts that have reacted to 
the notification."
         (unless (and filtered (assoc "hide" filters))
           (mastodon-notifications--insert-note
            ;; toot
-           (if (member type-sym '(follow follow_request))
+           (if (member type '(follow follow_request))
                follower
              status)
            ;; body
-           (let ((body (if-let ((match (assoc "warn" filters)))
-                           (mastodon-tl--spoiler status (cadr match))
-                         (mastodon-tl--clean-tabs-and-nl
-                          (cond ((mastodon-tl--has-spoiler status)
-                                 (mastodon-tl--spoiler status))
-                                ((eq type-sym 'follow_request)
-                                 (mastodon-tl--render-text profile-note))
-                                (t (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)))))
-              ((eq type-sym 'severed_relationships)
-               (mastodon-notifications--severance-body group))
-              ((eq type-sym 'moderation_warning)
-               (mastodon-notifications--mod-warning-body group))
-              ((member type-sym '(favourite reblog))
-               (propertize
-                (mastodon-notifications--comment-note-text body)))
-              (t body)))
-           ;; author-byline
-           #'mastodon-tl--byline-author
+           (mastodon-notifiations--body-arg
+            type filters status profile-note follower-name group)
            ;; action-byline
-           (unless (member type-sym '(follow follow_request mention))
-             (downcase
-              (mastodon-notifications--byline-concat
-               (alist-get type-sym mastodon-notifications--action-alist))))
-           ;; action authors
-           (cond ((member type-sym '(follow follow_request mention))
-                  "") ;; mentions are normal statuses
-                 (t (mastodon-notifications--byline-accounts
-                     accounts status group)))
-           ;; action symbol:
-           (unless (eq type-sym 'mention)
-             (mastodon-tl--symbol type-sym))
+           (mastodon-notifications--action-byline
+            type accounts group)
            ;; base toot (no need for update/poll/?)
-           (when (member type-sym '(favourite reblog))
+           (when (member type '(favourite reblog))
              status)
            folded group accounts))))))
 
+(defun mastodon-notifications--action-byline
+    (type &optional accounts group note follower-name)
+  "Return an action (top) byline for notification of TYPE.
+ACCOUNTS and GROUP group are used by grouped notifications.
+NOTE and FOLLOWER-NAME are used for non-grouped notifs."
+  (let ((action-str
+         (unless (member type '(follow follow_request mention))
+           (downcase
+            (mastodon-notifications--byline-action-str
+             (alist-get type mastodon-notifications--action-alist)))))
+        (action-symbol (if (eq type 'mention)
+                           ""
+                         (mastodon-tl--symbol type)))
+        (action-authors
+         (if (member type '(follow follow_request mention))
+             "" ;; mentions are normal statuses
+           (if group
+               (mastodon-notifications--byline-accounts accounts group)
+             (mastodon-tl--byline-handle note nil
+                                         follower-name
+                                         'mastodon-display-name-face)))))
+    (propertize
+     (concat action-symbol " " action-authors action-str)
+     'byline-top t)))
+
+(defun mastodon-notifiations--body-arg
+    (type &optional filters status profile-note follower-name group)
+  "TYPE is a symbol, a member of `mastodon-notifiations--types'.
+FILTERS STATUS PROFILE-NOTE FOLLOWER-NAME GROUP."
+  (let ((body
+         (if-let ((match (assoc "warn" filters)))
+             (mastodon-tl--spoiler status (cadr match))
+           (mastodon-tl--clean-tabs-and-nl
+            (cond ((mastodon-tl--has-spoiler status)
+                   (mastodon-tl--spoiler status))
+                  ((eq type 'follow_request)
+                   (mastodon-tl--render-text profile-note))
+                  (t (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-name)
+                   'face 'default)
+       (when mastodon-profile-note-in-foll-reqs
+         (concat
+          ":\n"
+          (mastodon-notifications--comment-note-text body)))))
+     ((eq type 'severed_relationships)
+      (mastodon-notifications--severance-body group))
+     ((eq type 'moderation_warning)
+      (mastodon-notifications--mod-warning-body group))
+     ((member type '(favourite reblog))
+      (propertize
+       (mastodon-notifications--comment-note-text body)))
+     (t body))))
+
 (defun mastodon-notifications--insert-note
-    (toot body author-byline action-byline action-authors action-symbol
-          &optional base-toot unfolded group accounts)
+    (toot body action-byline
+          &optional base-toot unfolded group accounts type)
   "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
 portion of the byline that takes one variable. By default it is
 `mastodon-tl--byline-author'.
 ACTION-BYLINE is a string, obtained by calling
-`mastodon-notifications--byline-concat'.
-ACTION-AUTHORS is a string of those who have responded to the
-current item, obtained by calling
-`mastodon-notifications--byline-accounts'.
-ACTION-SYMBOL is a symbol indicating a favourite, boost, or edit.
-ID is that of the status if it is a notification, which is
-attached as a `item-id' property if provided. If the
-status is a favourite or boost notification, BASE-TOOT is the
-JSON of the toot responded to.
+`mastodon-notifications--action-byline'.
+BASE-TOOT is the JSON of the toot responded to.
 UNFOLDED is a boolean meaning whether to unfold or fold item if
 foldable.
 GROUP is the notification group data.
-ACCOUNTS is the notification accounts data."
-  (let* ((type (alist-get 'type (or group toot)))
+ACCOUNTS is the notification accounts data.
+TYPE is notification type, used for non-group notifs."
+  (let* ((type (if type
+                   (symbol-name type) ;; non-group
+                 (alist-get 'type group)))
          (toot-foldable
           (and mastodon-tl--fold-toots-at-length
-               (length> body mastodon-tl--fold-toots-at-length))))
+               (length> body mastodon-tl--fold-toots-at-length)))
+         (ts ;; types listed here use base item timestamp, else we use
+          ;; group's latest timestamp:
+          (when (and group
+                     (not
+                      (member type '("favourite" "reblog" "edit" "poll"))))
+            (mastodon-tl--field 'latest_page_notification_at group))))
     (insert
      (propertize ;; top byline, body + byline:
       (concat
-       (propertize ;; top byline
-        (if (equal type "mention")
-            ""
-          (concat action-symbol " " action-authors
-                  action-byline))
-        'byline-top t)
-       (propertize ;; body only
-        body
-        'toot-body t) ;; includes newlines etc. for folding
+       (if (equal type "mention") ;; top (action) byline
+           ""
+         action-byline)
+       (propertize body ;; body only
+                   'toot-body t) ;; includes newlines etc. for folding
        "\n"
        ;; actual byline:
-       (mastodon-tl--byline
-        toot author-byline nil nil base-toot group
-        (when (member type '("follow" "follow_request"))
-          toot) ;; account data!
-        ;; types listed here use base item timestamp, else we use group's
-        ;; latest timestamp:
-        (when (not (member type '("favourite" "reblog" "edit" "poll")))
-          (mastodon-tl--field 'latest_page_notification_at group))))
+       (mastodon-tl--byline toot nil nil base-toot group ts))
       'item-type     'toot ;; for nav, actions, etc.
       'item-id       (or (alist-get 'page_max_id group) ;; newest notif
                          (alist-get 'id toot)) ; toot id
@@ -378,13 +409,9 @@ ACCOUNTS is the notification accounts data."
       'notifications-max-id (alist-get 'page_max_id group))
      "\n")))
 
-;; 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)
-  "Propertize author byline ACCOUNTS for TOOT, the item responded to.
+    (accounts group &optional avatar)
+  "Propertize author byline ACCOUNTS.
 GROUP is the group notification data.
 When AVATAR, include the account's avatar image.
 When DOMAIN, force inclusion of user's domain in their handle."
@@ -406,7 +433,7 @@ When DOMAIN, force inclusion of user's domain in their 
handle."
                      (mastodon-tl--image-trans-check))
             (mastodon-media--get-avatar-rendering .avatar))
           (let ((uname (mastodon-tl--display-or-uname account)))
-            (mastodon-tl--byline-handle toot nil account
+            (mastodon-tl--byline-handle account nil
                                         uname 'mastodon-display-name-face))
           ", ")))
       nil ", ")
@@ -420,30 +447,34 @@ When DOMAIN, force inclusion of user's domain in their 
handle."
                                   (cddr accounts) ;; not first two
                                   ", ")))))))
 
-(defun mastodon-notifications--render (json)
-  "Display grouped notifications in JSON."
+(defun mastodon-notifications--render (json no-group)
+  "Display grouped notifications in JSON.
+NO-GROUP means don't render grouped notifications."
   ;; (setq masto-grouped-notifs json)
-  (let ((groups (alist-get 'notification_groups 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))))))
+  (if no-group
+      (cl-loop for x in json
+               do (mastodon-notifications--format-note x))
+    (let ((groups (alist-get 'notification_groups 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-group-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")
-    (mastodon-notifications--render json)
+    (mastodon-notifications--render json (not mastodon-group-notifications))
     (goto-char (point-min))))
 
 (defun mastodon-notifications--get-mentions ()
diff --git a/lisp/mastodon-profile.el b/lisp/mastodon-profile.el
index c16d88dfd4..1ce87479e8 100644
--- a/lisp/mastodon-profile.el
+++ b/lisp/mastodon-profile.el
@@ -745,7 +745,6 @@ MAX-ID is a flag to include the max_id pagination 
parameter."
                             "\n\n")
                     'success)
                  "")))) ; for insert call
-          (setq mastodon-tl--update-point (point))
           (mastodon-media--inline-images (point-min) (point))
           ;; widget items description
           (mastodon-widget--create
@@ -756,7 +755,8 @@ MAX-ID is a flag to include the max_id pagination 
parameter."
            (lambda (widget &rest _ignore)
              (let ((value (widget-value widget)))
                (mastodon-profile--view-fun-call value))))
-          (insert "\n")))
+          (insert "\n")
+          (setq mastodon-tl--update-point (point))))
       ;; split insert of items from insert of profile:
       (with-current-buffer buffer
         (let* ((inhibit-read-only t))
diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el
index 5178a25721..51abb6eb40 100644
--- a/lisp/mastodon-tl.el
+++ b/lisp/mastodon-tl.el
@@ -97,7 +97,8 @@
 (defvar mastodon-toot--visibility)
 (defvar mastodon-toot-mode)
 (defvar mastodon-active-user)
-(defvar mastodon-notifications--images-in-notifs)
+(defvar mastodon-images-in-notifs)
+(defvar mastodon-group-notifications)
 
 (when (require 'mpv nil :no-error)
   (declare-function mpv-start "mpv"))
@@ -162,6 +163,7 @@ nil."
     (verified        . ("✓" . "V"))
     (locked          . ("🔒" . "[locked]"))
     (private         . ("🔒" . "[followers]"))
+    (mention         . ("@"  . "[mention]"))
     (direct          . ("✉" . "[direct]"))
     (edited          . ("✍" . "[edited]"))
     (update          . ("✍" . "[edited]")) ;; server compat
@@ -610,40 +612,41 @@ Do so if type of status at poins is not 
follow_request/follow."
                   (string= type "follow")) ; no counts for these
         (message "%s" echo)))))
 
-;; 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)
+(defun mastodon-tl--byline-username (toot)
   "Format a byline username from account in TOOT.
-ACCOUNT is optionally acccount data to use."
-  (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 string face)
+TOOT may be account data, or toot data, in which case acount data
+is extracted from it."
+  (let ((data (or (alist-get 'account toot)
+                  toot))) ;; grouped nofifs use account data directly
+    (let-alist data
+      (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 data))))))
+
+(defun mastodon-tl--byline-handle (toot &optional domain string face)
   "Format a byline handle from account in TOOT.
 DOMAIN is optionally added to the handle.
 ACCOUNT is optionally acccount data to use.
-STRING is optionally the string to propertize.
+STRING is optionally the string to propertize, it is used to make
+username rather than handle buttons.
 FACE is optionally the face to use.
 The last two args allow for display a username as a clickable
 handle."
-  (let-alist (or account (alist-get 'account toot))
+  (let-alist (or (alist-get 'account toot)
+                 toot) ;; grouped notifs
     (propertize (or string
                     (concat "@" .acct
                             (when domain
@@ -653,19 +656,18 @@ handle."
                 'face (or 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)
+(defun mastodon-tl--byline-uname-+-handle (data &optional domain)
   "Concatenate a byline username and handle.
 DATA is the (toot) data to use.
 DOMAIN is optionally a domain for the handle.
 ACCOUNT is optionally acccount data to use."
-  (concat (mastodon-tl--byline-username data account)
-          " (" (mastodon-tl--byline-handle data domain account) ")"))
+  (concat (mastodon-tl--byline-username data)
+          " (" (mastodon-tl--byline-handle data domain) ")"))
 
 (defun mastodon-tl--display-or-uname (account)
   "Return display name or username from ACCOUNT data."
@@ -673,9 +675,8 @@ ACCOUNT is optionally acccount data to use."
       (alist-get 'display_name account)
     (alist-get 'username account)))
 
-(defun mastodon-tl--byline-author (toot &optional avatar domain base 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.
 BASE means to use data from the base item (reblog slot) if possible.
@@ -684,7 +685,7 @@ ACCOUNT is optionally acccount data to use."
   (let* ((data (if base
                    (mastodon-tl--toot-or-base toot)
                  toot))
-         (account (or account (alist-get 'account data)))
+         (account (alist-get 'account data))
          (uname (mastodon-tl--display-or-uname account)))
     (concat
      ;; avatar insertion moved up to `mastodon-tl--byline' by default to
@@ -701,11 +702,11 @@ ACCOUNT is optionally acccount data to use."
                  " "
                  ;; username as button:
                  (mastodon-tl--byline-handle
-                  data domain account
+                  data domain
                   ;; display uname not handle (for boosts):
                   uname 'mastodon-display-name-face))
        ;; normal combo author byline:
-       (mastodon-tl--byline-uname-+-handle data domain account)))))
+       (mastodon-tl--byline-uname-+-handle data domain)))))
 
 (defun mastodon-tl--format-byline-help-echo (toot)
   "Format a help-echo for byline of TOOT.
@@ -796,14 +797,11 @@ 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 &optional detailed-p
-                                 domain base-toot group account ts)
-  "Generate byline for TOOT.
+(defun mastodon-tl--byline (toot &optional detailed-p
+                                 domain base-toot group ts)
+  "Generate (bottom) byline for TOOT.
 AUTHOR-BYLINE is a function for adding the author portion of
 the byline that takes one variable.
-ACTION-BYLINE is a function for adding an action, such as boosting,
-favouriting and following to the byline. It also takes a single function.
-By default it is `mastodon-tl--byline-author'
 DETAILED-P means display more detailed info. For now
 this just means displaying toot client.
 When DOMAIN, force inclusion of user's domain in their handle.
@@ -811,7 +809,7 @@ BASE-TOOT is JSON for the base toot, if any.
 GROUP is the notification group if any.
 ACCOUNT is the notification account if any.
 TS is a timestamp from the server, if any."
-  (let* ((type (alist-get 'type group))
+  (let* ((type (alist-get 'type (or group toot)))
          (created-time
           (or ts ;; mentions, statuses, folls/foll-reqs
               ;; bosts, faves, edits, polls in notifs view use base item
@@ -822,17 +820,17 @@ TS is a timestamp from the server, if any."
               ;; (mastodon-tl--field auto fetches from reblogs if needed):
               (mastodon-tl--field 'created_at toot)))
          (parsed-time (when created-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))
-         (type (alist-get 'type (or group toot)))
-         (base-toot-maybe (or base-toot ;; show edits for notifs
-                              (mastodon-tl--toot-or-base toot))) ;; for boosts
-         (account (or account
-                      (alist-get 'account base-toot-maybe)))
+         ;; non-grouped notifs now need to pull the following data from
+         ;; base toot:
+         (base-maybe (or base-toot ;; show edits for notifs
+                         (mastodon-tl--toot-or-base toot))) ;; for boosts
+         (faved (eq t (mastodon-tl--field 'favourited base-maybe)))
+         (boosted (eq t (mastodon-tl--field 'reblogged base-maybe)))
+         (bookmarked (eq t (mastodon-tl--field 'bookmarked base-maybe)))
+         (visibility (mastodon-tl--field 'visibility base-maybe))
+         (account (alist-get 'account base-maybe))
          (avatar-url (alist-get 'avatar account))
-         (edited-time (alist-get 'edited_at base-toot-maybe))
+         (edited-time (alist-get 'edited_at base-maybe))
          (edited-parsed (when edited-time (date-to-time edited-time))))
     (concat
      ;; Boosted/favourited markers are not technically part of the byline, so
@@ -862,7 +860,10 @@ TS is a timestamp from the server, if any."
        ;; NB: action-byline (boost) is now added in insert-status, so no
        ;; longer part of the byline.
        ;; (base) author byline:
-       (funcall author-byline toot nil domain :base account)
+       ;; we use base-toot if poss for fave/boost notifs that need to show
+       ;; base item in author byline
+       (mastodon-tl--byline-author (or base-toot toot)
+                                   nil domain :base)
        ;; visibility:
        (cond ((string= visibility "direct")
               (propertize (concat " " (mastodon-tl--symbol 'direct))
@@ -925,7 +926,7 @@ TS is a timestamp from the server, if any."
       'edited edited-time
       'edit-history (when edited-time
                       (mastodon-toot--get-toot-edits
-                       (alist-get 'id base-toot-maybe)))
+                       (alist-get 'id base-maybe)))
       'byline       t))))
 
 
@@ -1142,7 +1143,8 @@ the toot)."
 LINK-TYPE is the type of link to produce."
   (let ((help-text (cond ((eq link-type 'content-warning)
                           "Toggle hidden text")
-                         ((eq link-type 'read-more)
+                         ((or (eq link-type 'read-more)
+                              (eq link-type 'read-less))
                           "Toggle full post")
                          (t
                           (error "Unknown link type %s" link-type)))))
@@ -1186,6 +1188,8 @@ Used for hitting RET on a given link."
                         (error "Unable to find account"))))))))
           ((eq link-type 'read-more)
            (mastodon-tl--unfold-post))
+          ((eq link-type 'read-less)
+           (mastodon-tl--fold-post))
           (t
            (error "Unknown link type %s" link-type)))))
 
@@ -1275,25 +1279,22 @@ FILTER is a string to use as a filter warning spoiler 
instead."
          (cw (mastodon-tl--set-face message 'mastodon-cw-face)))
     (concat
      cw
-     (propertize (mastodon-tl--content toot)
-                 'invisible
-                 (if filter
-                     t
-                   (let ((cust mastodon-tl--expand-content-warnings))
-                     (cond ((eq t cust)
-                            nil)
-                           ((eq nil cust)
-                            t)
-                           ((eq 'server cust)
-                            (unless (eq t
-                                        ;; If something goes wrong reading 
prefs,
-                                        ;; just return nil so CWs show by 
default.
-                                        (condition-case nil
-                                            
(mastodon-profile--get-preferences-pref
-                                             'reading:expand:spoilers)
-                                          (error nil)))
-                              t)))))
-                 'mastodon-content-warning-body t))))
+     (propertize
+      (mastodon-tl--content toot)
+      'invisible
+      (or filter ;; filters = invis
+          (let ((cust mastodon-tl--expand-content-warnings))
+            (if (not (eq 'server cust))
+                (not cust) ;; opp to setting
+              ;; respect server setting:
+              (not
+               ;; If something goes wrong reading prefs,
+               ;; just return nil so CWs show by default.
+               (condition-case nil
+                   (mastodon-profile--get-preferences-pref
+                    'reading:expand:spoilers)
+                 (error nil))))))
+      'mastodon-content-warning-body t))))
 
 
 ;;; MEDIA
@@ -1327,7 +1328,7 @@ SENSITIVE is a flag from the item's JSON data."
                ;; if in notifs, also check notifs images custom:
                (if (or (mastodon-tl--buffer-type-eq 'notifications)
                        (mastodon-tl--buffer-type-eq 'mentions))
-                   mastodon-notifications--images-in-notifs
+                   mastodon-images-in-notifs
                  t))
           (mastodon-media--get-media-link-rendering ; placeholder: "[img]"
            .preview_url remote-url ; for shr-browse-url
@@ -1655,21 +1656,10 @@ Runs `mastodon-tl--render-text' and fetches poll or 
media."
     (string= reply-to-id prev-id)))
 
 (defun mastodon-tl--insert-status
-    (toot body author-byline action-byline &optional id base-toot
-          detailed-p thread domain unfolded no-byline)
+    (toot body &optional detailed-p thread domain unfolded no-byline
+          cw-expanded)
   "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
-portion of the byline that takes one variable. By default it is
-`mastodon-tl--byline-author'.
-ACTION-BYLINE is also an optional function for adding an action,
-such as boosting favouriting and following to the byline. It also
-takes a single function. By default it is
-`mastodon-tl--byline-boost'.
-ID is that of the status if it is a notification, which is
-attached as a `item-id' property if provided. If the
-status is a favourite or boost notification, BASE-TOOT is the
-JSON of the toot responded to.
 DETAILED-P means display more detailed info. For now
 this just means displaying toot client.
 THREAD means the status will be displayed in a thread view.
@@ -1683,14 +1673,17 @@ NO-BYLINE means just insert toot body, used for 
folding."
          ;; (type (alist-get 'type toot))
          (toot-foldable
           (and mastodon-tl--fold-toots-at-length
-               (length> body mastodon-tl--fold-toots-at-length))))
+               (length> body mastodon-tl--fold-toots-at-length)))
+         (cw-p (not
+                (string-empty-p
+                 (alist-get 'spoiler_text toot)))))
     (insert
      (propertize ;; body + byline:
       (concat
        (propertize ;; body only:
         (concat
          "\n"
-         (funcall action-byline toot)
+         (mastodon-tl--byline-boost toot) ;; top byline (boost)
          ;; relpy symbol:
          (when (and after-reply-status-p thread)
            (concat (mastodon-tl--symbol 'replied)
@@ -1704,24 +1697,21 @@ NO-BYLINE means just insert toot body, used for 
folding."
                (propertize body
                            'line-prefix bar
                            'wrap-prefix bar)
-             body)))
+             body))
+         (if (and toot-foldable unfolded cw-expanded)
+             (mastodon-tl--read-more-or-less
+              "LESS" cw-p (not cw-expanded))
+           ""))
         'toot-body t) ;; includes newlines etc. for folding
        ;; byline:
        "\n"
        (if no-byline
            ""
-         (mastodon-tl--byline toot author-byline detailed-p
-                              domain base-toot)))
+         (mastodon-tl--byline toot detailed-p domain)))
       'item-type    'toot
-      'item-id      (or id ; notification's own id
-                        (alist-get 'id toot)) ; toot id
-      'base-item-id (mastodon-tl--item-id
-                     ;; if status is a notif, get id from base-toot
-                     ;; (-tl--item-id toot) will not work here:
-                     (or base-toot
-                         toot)) ; else normal toot with reblog check
+      'item-id (alist-get 'id toot) ; toot id
+      'base-item-id (mastodon-tl--item-id toot) ; with reblog check
       'item-json    toot
-      'base-toot    base-toot
       'cursor-face 'mastodon-cursor-highlight-face
       'toot-foldable toot-foldable
       'toot-folded (and toot-foldable (not unfolded)))
@@ -1772,15 +1762,18 @@ title, and context."
     (mastodon-tl--filter-by-context context filters-no-context)))
 
 (defun mastodon-tl--toot (toot &optional detailed-p thread domain
-                               unfolded no-byline)
+                               unfolded no-byline cw-expanded)
   "Format TOOT and insert it into the buffer.
 DETAILED-P means display more detailed info. For now
 this just means displaying toot client.
 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* ((filtered (mastodon-tl--field 'filtered toot))
+NO-BYLINE means just insert toot body, used for folding.
+NO-CW means treat content warnings as unfolded."
+  (let* ((mastodon-tl--expand-content-warnings
+          (or cw-expanded mastodon-tl--expand-content-warnings))
+         (filtered (mastodon-tl--field 'filtered toot))
          (filters (when filtered
                     (mastodon-tl--current-filters filtered)))
          (spoiler-or-content (if-let ((match (assoc "warn" filters)))
@@ -1790,19 +1783,17 @@ NO-BYLINE means just insert toot body, used for 
folding."
                                  (mastodon-tl--content toot)))))
     ;; If any filters are "hide", then we hide,
     ;; even though item may also have a "warn" filter:
-    (if (and filtered (assoc "hide" filters))
-        nil ;; no insert
+    (unless (and filtered (assoc "hide" filters)) ;; no insert
       (mastodon-tl--insert-status
-       toot
-       (mastodon-tl--clean-tabs-and-nl spoiler-or-content)
-       #'mastodon-tl--byline-author #'mastodon-tl--byline-boost
-       nil nil detailed-p thread domain unfolded no-byline))))
+       toot (mastodon-tl--clean-tabs-and-nl spoiler-or-content)
+       detailed-p thread domain unfolded no-byline cw-expanded))))
 
 (defun mastodon-tl--timeline (toots &optional thread domain no-byline)
   "Display each toot in TOOTS.
 This function removes replies if user required.
 THREAD means the status will be displayed in a thread view.
-When DOMAIN, force inclusion of user's domain in their handle."
+When DOMAIN, force inclusion of user's domain in their handle.
+NO-BYLINE means just insert toot body, used for folding."
   (let ((start-pos (point))
         (toots ;; hack to *not* filter replies on profiles:
          (if (eq (mastodon-tl--get-buffer-type) 'profile-statuses)
@@ -1823,12 +1814,26 @@ When DOMAIN, force inclusion of user's domain in their 
handle."
 
 ;;; FOLDING
 
+(defun mastodon-tl--read-more-or-less (str cw invis)
+  "Return a read more or read less heading.
+The heading is a link to toggle the fold status of the toot.
+CW and INVIS are boolean values for the properties invisible and
+mastodon-content-warning-body."
+  (let ((type (if (string= str "MORE") 'read-more 'read-less)))
+    (propertize
+     (mastodon-search--format-heading
+      (mastodon-tl--make-link (format "READ %s" str) type)
+      nil :no-newline)
+     'mastodon-content-warning-body cw
+     'invisible invis)))
+
 (defun mastodon-tl--fold-body (body)
   "Fold toot BODY if it is very long.
 Folding decided by `mastodon-tl--fold-toots-at-length'."
-  (let* ((heading (mastodon-search--format-heading
-                   (mastodon-tl--make-link "READ MORE" 'read-more)
-                   nil :no-newline))
+  (let* ((invis (get-text-property (1- (length body)) 'invisible body))
+         (cw (get-text-property (1- (length body))
+                                'mastodon-content-warning-body body))
+         (heading (mastodon-tl--read-more-or-less "MORE" cw invis))
          (display (concat (substring body 0
                                      mastodon-tl--fold-toots-at-length)
                           heading)))
@@ -1848,6 +1853,10 @@ FOLD means to fold it instead."
       (let* ((inhibit-read-only t)
              (body-range (mastodon-tl--find-property-range 'toot-body
                                                            (point) :backward))
+             (cw-range (mastodon-tl--find-property-range
+                        'mastodon-content-warning-body
+                        (point) :backward))
+             (cw-invis (get-text-property (car cw-range) 'invisible))
              (toot (mastodon-tl--property 'item-json :no-move))
              ;; `replace-region-contents' is much too slow, our hack from
              ;; fedi.el is much simpler and much faster:
@@ -1863,7 +1872,8 @@ FOLD means to fold it instead."
         (delete-region beg end)
         (delete-char 1) ;; prevent newlines accumulating
         ;; insert toot body:
-        (mastodon-tl--toot toot nil nil nil (not fold) :no-byline)
+        (mastodon-tl--toot toot nil nil nil (not fold) :no-byline
+                           (unless cw-invis :cw-expanded)) ;; respect CW state
         ;; set toot-folded prop on entire toot (not just body):
         (let ((toot-range ;; post fold action range:
                (mastodon-tl--find-property-range 'item-json
@@ -2245,8 +2255,9 @@ If we are in a notifications view, return 
`notifications-min-id'."
   (save-excursion
     (goto-char (point-max))
     (mastodon-tl--property
-     (if (member (mastodon-tl--get-buffer-type)
-                 '(mentions notifications))
+     (if (and mastodon-group-notifications
+              (member (mastodon-tl--get-buffer-type)
+                      '(mentions notifications)))
          'notifications-min-id
        'item-id)
      nil :backward)))
@@ -2870,7 +2881,8 @@ the current view."
          (args (append args params))
          (url (mastodon-http--api
                endpoint
-               (when (or (string= endpoint "notifications")
+               (when (or (and mastodon-group-notifications
+                              (string= endpoint "notifications"))
                          (string-suffix-p "search" endpoint))
                  "v2"))))
     (apply #'mastodon-http--get-json-async url args callback cbargs)))
@@ -3028,7 +3040,7 @@ MAX-ID is the pagination parameter, a string."
                               (alist-get 'hashtags response))
                              ((string= "accounts" type)
                               (alist-get 'accounts response))))))
-             (headers (if headers (cdr response) nil))
+             (headers (when headers (cdr response)))
              (link-header
               (mastodon-tl--get-link-header-from-response headers)))
         (goto-char (point-max))
@@ -3263,7 +3275,8 @@ favourites and bookmarks.
 PARAMS is any parameters to send with the request.
 HIDE-REPLIES is a flag indicating if replies are hidden in the current buffer.
 INSTANCE is a string of another instance domain we are displaying
-a timeline from."
+a timeline from.
+NO-BYLINE means just insert toot body, used for announcements."
   (let ((url (if instance
                  (concat "https://"; instance "/api/v1/" endpoint)
                (mastodon-http--api endpoint)))
@@ -3283,7 +3296,8 @@ a timeline from."
 UPDATE-FUNCTION is used to recieve more toots.
 RESPONSE is the data returned from the server by
 `mastodon-http--process-json', with arg HEADERS a cons cell of
-JSON and http headers, without it just the JSON."
+JSON and http headers, without it just the JSON.
+NO-BYLINE means just insert toot body, used for announcements."
   (let ((json (if headers (car response) response)))
     (cond ((not json) ; praying this is right here, else try "\n[]"
            ;; this means that whatever tl was inited won't load, which is not
@@ -3300,7 +3314,7 @@ JSON and http headers, without it just the JSON."
           ((eq (caar json) 'error)
            (user-error "Looks like the server bugged out: \"%s\"" (cdar json)))
           (t
-           (let* ((headers (if headers (cdr response) nil))
+           (let* ((headers (when headers (cdr response)))
                   (link-header
                    (mastodon-tl--get-link-header-from-response headers)))
              (with-mastodon-buffer buffer #'mastodon-mode nil
@@ -3355,7 +3369,8 @@ ENDPOINT-VERSION is a string, format Vx, e.g. V2."
 (defun mastodon-tl--do-init (json update-fun &optional domain no-byline)
   "Utility function for `mastodon-tl--init*' and `mastodon-tl--init-sync'.
 JSON is the data to call UPDATE-FUN on.
-When DOMAIN, force inclusion of user's domain in their handle."
+When DOMAIN, force inclusion of user's domain in their handle.
+NO-BYLINE means just insert toot body, used for announcements."
   (remove-overlays) ; video overlays
   (cond (domain ;; maybe our update-fun doesn't always have 3 args...:
          (funcall update-fun json nil domain))
diff --git a/lisp/mastodon-toot.el b/lisp/mastodon-toot.el
index 82ebc90102..4ba5e5d342 100644
--- a/lisp/mastodon-toot.el
+++ b/lisp/mastodon-toot.el
@@ -36,8 +36,11 @@
 (require 'emojify nil :noerror)
 (declare-function emojify-insert-emoji "emojify")
 (declare-function emojify-set-emoji-data "emojify")
+(declare-function emojify-mode "emojify")
+(declare-function emojify-emojis-each "emojify")
 (defvar emojify-emojis-dir)
 (defvar emojify-user-emojis)
+(defvar emojify-emoji-styles)
 
 (require 'cl-lib)
 (require 'persist)
@@ -53,9 +56,9 @@
 (defvar mastodon-tl--enable-proportional-fonts)
 (defvar mastodon-profile-account-settings)
 (defvar mastodon-profile-acccount-preferences-data)
-(defvar tp-transient-settings)
 
 (autoload 'iso8601-parse "iso8601")
+(autoload 'ht-get "ht")
 (autoload 'mastodon-auth--user-acct "mastodon-auth")
 (autoload 'mastodon-http--api "mastodon-http")
 (autoload 'mastodon-http--build-array-params-alist "mastodon-http")
@@ -776,7 +779,7 @@ TEXT-ONLY means don't check for attachments or polls."
   (and (if text-only
            t
          (and (not mastodon-toot--media-attachments)
-              (not (mastodon-toot-poll-var))))
+              (not mastodon-toot-poll)))
        (string-empty-p (mastodon-tl--clean-tabs-and-nl
                         (mastodon-toot--remove-docs)))))
 
@@ -877,7 +880,7 @@ to `emojify-user-emojis', and the emoji data is updated."
 (defun mastodon-toot--build-poll-params ()
   "Return an alist of parameters for POSTing a poll status."
   (if mastodon-toot-poll-use-transient
-      (let-alist tp-transient-settings
+      (let-alist mastodon-toot-poll
         (append
          (mastodon-http--build-array-params-alist
           "poll[options][]"
@@ -926,13 +929,12 @@ instance to edit a toot."
                        (mastodon-http--build-array-params-alist
                         "media_ids[]"
                         mastodon-toot--media-attachment-ids)))
-         (poll-var (mastodon-toot-poll-var))
-         (args-poll (when poll-var
+         (args-poll (when mastodon-toot-poll
                       (mastodon-toot--build-poll-params)))
          ;; media || polls:
          (args (if mastodon-toot--media-attachment-ids
                    (append args-media args-no-media)
-                 (if poll-var
+                 (if mastodon-toot-poll
                      (append args-no-media args-poll)
                    args-no-media)))
          (prev-window-config mastodon-toot-previous-window-config))
@@ -947,7 +949,9 @@ instance to edit a toot."
                 (> (mastodon-toot--count-toot-chars toot 
mastodon-toot--content-warning)
                    mastodon-toot--max-toot-chars))
            (user-error "Looks like your toot (inc. CW) is longer than that 
maximum allowed length"))
-          ((mastodon-toot--empty-p)
+          ;; polls must have text, so we use poll as flag for text-only
+          ;; check here:
+          ((mastodon-toot--empty-p mastodon-toot-poll)
            (user-error "Empty toot. Cowardly refusing to post this"))
           (t
            (let ((response (funcall (if edit-id ; we are sending an edit:
@@ -960,7 +964,7 @@ instance to edit a toot."
                 ;; kill buffer:
                 (mastodon-toot--kill)
                 ;; nil our poll var:
-                (set poll-var nil)
+                (setq mastodon-toot-poll nil)
                 (message "Toot %s!" (if scheduled "scheduled" "toot"))
                 ;; cancel scheduled toot if we were editing it:
                 (when scheduled-id
@@ -1391,12 +1395,6 @@ which is used to attach it to a toot when posting."
 
 ;;; POLL
 
-(defun mastodon-toot-poll-var ()
-  "Return the correct poll var."
-  (if mastodon-toot-poll-use-transient
-      'tp-transient-settings
-    'mastodon-toot-poll))
-
 (defun mastodon-toot--fetch-max-poll-options (instance)
   "Return the maximum number of poll options from JSON data INSTANCE."
   (mastodon-toot--fetch-poll-field 'max_options instance))
@@ -1488,14 +1486,20 @@ Return a cons of a human readable string, and a 
seconds-from-now string."
     ("14 days" . ,(number-to-string (* 60 60 24 14)))
     ("30 days" . ,(number-to-string (* 60 60 24 30)))))
 
-(defun mastodon-toot--clear-poll ()
+(defun mastodon-toot--clear-poll (&optional transient)
   "Remove poll from toot compose buffer.
-Sets `mastodon-toot-poll' to nil."
+Sets `mastodon-toot-poll' to nil.
+If TRANSIENT, we are called from a transient, so nil
+`tp-transient-settings' too."
   (interactive)
-  (let ((var (mastodon-toot-poll-var)))
-    (if (not var)
+  (let ((var (if transient
+                 'tp-transient-settings
+               'mastodon-toot-poll)))
+    (if (not (symbol-value var))
         (user-error "No poll?")
       (set var nil)
+      (when transient
+        (setq mastodon-toot-poll nil))
       (mastodon-toot--update-status-fields))))
 
 (defun mastodon-toot--server-poll-to-local (json)
@@ -1513,7 +1517,7 @@ Sets `mastodon-toot-poll' to nil."
            (options (mastodon-tl--map-alist 'title .options))
            (multiple (if (eq :json-false .multiple) nil t)))
       (if mastodon-toot-poll-use-transient
-          (setq tp-transient-settings
+          (setq mastodon-toot-poll
                 `((multi . ,multiple)
                   (expiry . ,expiry-str)
                   ;; (hide . ,hide)
@@ -1801,8 +1805,7 @@ REPLY-REGION is a string to be injected into the buffer."
            (poll-region (mastodon-tl--find-property-range 'toot-post-poll-flag
                                                           (point-min)))
            (toot-string (buffer-substring-no-properties (cdr header-region)
-                                                        (point-max)))
-           (poll-var (mastodon-toot-poll-var)))
+                                                        (point-max))))
       (mastodon-toot--apply-fields-props
        count-region
        (format "%s/%s chars"
@@ -1836,11 +1839,11 @@ REPLY-REGION is a string to be injected into the 
buffer."
        'mastodon-cw-face)
       (mastodon-toot--apply-fields-props
        poll-region
-       (if (symbol-value poll-var)
+       (if mastodon-toot-poll
            "POLL"
          "")
        'mastodon-cw-face
-       (prin1-to-string (symbol-value poll-var)))
+       (prin1-to-string mastodon-toot-poll))
       (mastodon-toot--apply-fields-props
        cw-region
        (if (and mastodon-toot--content-warning
diff --git a/lisp/mastodon-transient.el b/lisp/mastodon-transient.el
index c96e1d5319..3e8ba5f820 100644
--- a/lisp/mastodon-transient.el
+++ b/lisp/mastodon-transient.el
@@ -268,8 +268,12 @@ Do not add more than the server's maximum setting."
 
 (transient-define-prefix mastodon-create-poll ()
   "A transient for creating a poll."
-  ;; FIXME: handle existing polls when editing a toot
-  :value (lambda () tp-transient-settings)
+  :value (lambda ()
+           ;; we set `tp-transient-settings' here to the poll value poss
+           ;; pulled from the server by
+           ;; `mastodon-toot--server-poll-to-local'. when we are done with
+           ;; the transient, we set `mastodon-toot-poll' again
+           (setq tp-transient-settings mastodon-toot-poll))
   ["Create poll"
    (:info (lambda ()
             (format "Max options: %s"
@@ -305,11 +309,11 @@ Do not add more than the server's maximum setting."
   "Clear current poll data."
   :transient 'transient--do-stay
   (interactive)
-  (mastodon-toot--clear-poll)
+  (mastodon-toot--clear-poll :transient)
   (transient-reset))
 
 (transient-define-suffix mastodon-create-poll-done (args)
-  "Update current user profile fields."
+  "Finish setting poll details."
   :transient 'transient--do-exit
   (interactive (list (transient-args 'mastodon-create-poll)))
   (let* ((options (cl-member-if (lambda (x)
@@ -335,7 +339,9 @@ Do not add more than the server's maximum setting."
         (call-interactively #'mastodon-create-poll)
       ;; if we are called with no poll data, do not set:
       (unless (not vals)
-        (setq tp-transient-settings
+        ;; we set `mastodon-toot-poll' here not `tp-transient-settings'
+        ;; as that is our var outside of our transient:
+        (setq mastodon-toot-poll
               (tp-bools-to-strs args)))
       (mastodon-toot--update-status-fields))))
 
diff --git a/lisp/mastodon.el b/lisp/mastodon.el
index 62772ea7a4..c13c3ba349 100644
--- a/lisp/mastodon.el
+++ b/lisp/mastodon.el
@@ -153,6 +153,30 @@ currently, it doesn't seem to have a way to handle custom 
emoji,
 while emojify,el has this feature and mastodon.el implements it."
   :type 'boolean)
 
+;; notifications customizes
+;; moved here because we can load notifs without first loading mastodon.el
+;; or mastodon-notifications.el
+
+(defcustom mastodon-profile-note-in-foll-reqs t
+  "If non-nil, show a user's profile note in follow request notifications."
+  :type '(boolean))
+
+(defcustom mastodon-profile-note-in-foll-reqs-max-length nil
+  "The max character length for user profile note in follow requests.
+Profile notes are only displayed if
+`mastodon-profile-note-in-foll-reqs' is non-nil.
+If unset, profile notes of any size will be displayed, which may
+make them unweildy."
+  :type '(integer))
+
+(defcustom mastodon-images-in-notifs nil
+  "Whether to display attached images in notifications."
+  :type '(boolean))
+
+(defcustom mastodon-group-notifications t
+  "Whether to use grouped notifications."
+  :type '(boolean))
+
 (defun mastodon-kill-window ()
   "Quit window and delete helper."
   (interactive)
@@ -372,7 +396,10 @@ MAX-ID is a request parameter for pagination."
      type
      (when max-id
        `(("max_id" . ,(mastodon-tl--buffer-property 'max-id))))
-     nil nil nil "v2")
+     nil nil nil
+     (if (not mastodon-group-notifications)
+         "v1"
+       "v2"))
     (with-current-buffer (get-buffer-create buffer)
       (use-local-map mastodon-notifications--map))))
 
diff --git a/mastodon-index.org b/mastodon-index.org
index b3d6af7599..7e5d2a7986 100644
--- a/mastodon-index.org
+++ b/mastodon-index.org
@@ -200,6 +200,7 @@
 | a                | mastodon-toot--translate-toot-text                | 
Translate text of toot at point.                                               |
 | E                | mastodon-toot--view-toot-edits                    | View 
editing history of the toot at point in a popup buffer.                   |
 |                  | mastodon-toot-mode                                | Minor 
mode for composing toots.                                                |
+|                  | mastodon-transient--choice-add                    | Add 
another poll choice if possible.                                           |
 |                  | mastodon-update-profile-note                      | 
Update current user profile note.                                              |
 |                  | mastodon-url-lookup                               | If a 
URL resembles a fediverse link, try to load in `mastodon.el'.             |
 |                  | mastodon-url-lookup-force                         | Call 
`mastodon-url-lookup' without checking if URL is fedi-like.               |
@@ -259,50 +260,51 @@
 #+end_src
 
 #+RESULTS:
-| Custom variable                                              | Description   
                                                                |
-|--------------------------------------------------------------+-------------------------------------------------------------------------------|
-| mastodon-active-user                                         | Username of 
the active user.                                                  |
-| mastodon-client--token-file                                  | File path 
where Mastodon access tokens are stored.                            |
-| mastodon-instance-url                                        | Base URL for 
the fediverse instance you want to be active.                    |
-| mastodon-media--avatar-height                                | Height of the 
user avatar images (if shown).                                  |
-| mastodon-media--enable-image-caching                         | Whether 
images should be cached.                                              |
-| mastodon-media--hide-sensitive-media                         | Whether media 
marked as sensitive should be hidden.                           |
-| mastodon-media--preview-max-height                           | Max height of 
any media attachment preview to be shown in timelines.          |
-| mastodon-mode-hook                                           | Hook run when 
entering Mastodon mode.                                         |
-| mastodon-notifications--images-in-notifs                     | Whether to 
display attached images in notifications.                          |
-| mastodon-notifications--profile-note-in-foll-reqs            | If non-nil, 
show a user's profile note in follow request notifications.       |
-| mastodon-notifications--profile-note-in-foll-reqs-max-length | The max 
character length for user profile note in follow requests.            |
-| mastodon-profile-mode-hook                                   | Hook run 
after entering or leaving `mastodon-profile-mode'.                   |
-| mastodon-profile-update-mode-hook                            | Hook run 
after entering or leaving `mastodon-profile-update-mode'.            |
-| mastodon-search-mode-hook                                    | Hook run 
after entering or leaving `mastodon-search-mode'.                    |
-| mastodon-tl--display-caption-not-url-when-no-media           | Display an 
image's caption rather than URL.                                   |
-| mastodon-tl--display-media-p                                 | A boolean 
value stating whether to show media in timelines.                   |
-| mastodon-tl--enable-proportional-fonts                       | Nonnil to 
enable using proportional fonts when rendering HTML.                |
-| mastodon-tl--enable-relative-timestamps                      | Whether to 
show relative (to the current time) timestamps.                    |
-| mastodon-tl--expand-content-warnings                         | Whether to 
expand content warnings by default.                                |
-| mastodon-tl--fold-toots-at-length                            | Length, in 
characters, to fold a toot at.                                     |
-| mastodon-tl--hide-replies                                    | Whether to 
hide replies from the timelines.                                   |
-| mastodon-tl--highlight-current-toot                          | Whether to 
highlight the toot at point. Uses `cursor-face' special property.  |
-| mastodon-tl--load-full-sized-images-in-emacs                 | Whether to 
load full-sized images inside Emacs.                               |
-| mastodon-tl--no-fill-on-render                               | Non-nil to 
disable filling by shr.el while rendering toot body.               |
-| mastodon-tl--remote-local-domains                            | A list of 
domains to view the local timelines of.                             |
-| mastodon-tl--show-avatars                                    | Whether to 
enable display of user avatars in timelines.                       |
-| mastodon-tl--show-stats                                      | Whether to 
show toot stats (faves, boosts, replies counts).                   |
-| mastodon-tl--symbols                                         | A set of 
symbols (and fallback strings) to be used in timeline.               |
-| mastodon-tl--tag-timeline-tags                               | A list of up 
to four tags for use with `mastodon-tl--followed-tags-timeline'. |
-| mastodon-tl--timeline-posts-count                            | Number of 
posts to display when loading a timeline.                           |
-| mastodon-tl-position-after-update                            | Defines where 
`point' should be located after a timeline update.              |
-| mastodon-toot--attachment-height                             | Height of the 
attached images preview in the toot draft buffer.               |
-| mastodon-toot--completion-style-for-mentions                 | The company 
completion style to use for mentions.                             |
-| mastodon-toot--default-media-directory                       | The default 
directory when prompting for a media file to upload.              |
-| mastodon-toot--default-reply-visibility                      | Default 
visibility settings when replying.                                    |
-| mastodon-toot--enable-completion                             | Whether to 
enable completion of mentions and hashtags.                        |
-| mastodon-toot--enable-custom-instance-emoji                  | Whether to 
enable your instance's custom emoji by default.                    |
-| mastodon-toot--proportional-fonts-compose                    | Nonnil to 
enable using proportional fonts in the compose buffer.              |
-| mastodon-toot--use-company-for-completion                    | Whether to 
enable company for completion.                                     |
-| mastodon-toot-display-orig-in-reply-buffer                   | Display a 
copy of the toot replied to in the compose buffer.                  |
-| mastodon-toot-mode-hook                                      | Hook run 
after entering or leaving `mastodon-toot-mode'.                      |
-| mastodon-toot-orig-in-reply-length                           | Length to 
crop toot replied to in the compose buffer to.                      |
-| mastodon-toot-poll-use-transient                             | Whether to 
use the transient menu to create a poll.                           |
-| mastodon-toot-timestamp-format                               | Format to use 
for timestamps.                                                 |
-| mastodon-use-emojify                                         | Whether to 
use emojify.el to display emojis.                                  |
+| Custom variable                                    | Description             
                                                      |
+|----------------------------------------------------+-------------------------------------------------------------------------------|
+| mastodon-active-user                               | Username of the active 
user.                                                  |
+| mastodon-client--token-file                        | File path where 
Mastodon access tokens are stored.                            |
+| mastodon-group-notifications                       | Whether to use grouped 
notifications.                                         |
+| mastodon-images-in-notifs                          | Whether to display 
attached images in notifications.                          |
+| mastodon-instance-url                              | Base URL for the 
fediverse instance you want to be active.                    |
+| mastodon-media--avatar-height                      | Height of the user 
avatar images (if shown).                                  |
+| mastodon-media--enable-image-caching               | Whether images should 
be cached.                                              |
+| mastodon-media--hide-sensitive-media               | Whether media marked as 
sensitive should be hidden.                           |
+| mastodon-media--preview-max-height                 | Max height of any media 
attachment preview to be shown in timelines.          |
+| mastodon-mode-hook                                 | Hook run when entering 
Mastodon mode.                                         |
+| mastodon-profile-mode-hook                         | Hook run after entering 
or leaving `mastodon-profile-mode'.                   |
+| mastodon-profile-note-in-foll-reqs                 | If non-nil, show a 
user's profile note in follow request notifications.       |
+| mastodon-profile-note-in-foll-reqs-max-length      | The max character 
length for user profile note in follow requests.            |
+| mastodon-profile-update-mode-hook                  | Hook run after entering 
or leaving `mastodon-profile-update-mode'.            |
+| mastodon-search-mode-hook                          | Hook run after entering 
or leaving `mastodon-search-mode'.                    |
+| mastodon-tl--display-caption-not-url-when-no-media | Display an image's 
caption rather than URL.                                   |
+| mastodon-tl--display-media-p                       | A boolean value stating 
whether to show media in timelines.                   |
+| mastodon-tl--enable-proportional-fonts             | Nonnil to enable using 
proportional fonts when rendering HTML.                |
+| mastodon-tl--enable-relative-timestamps            | Whether to show 
relative (to the current time) timestamps.                    |
+| mastodon-tl--expand-content-warnings               | Whether to expand 
content warnings by default.                                |
+| mastodon-tl--fold-toots-at-length                  | Length, in characters, 
to fold a toot at.                                     |
+| mastodon-tl--hide-replies                          | Whether to hide replies 
from the timelines.                                   |
+| mastodon-tl--highlight-current-toot                | Whether to highlight 
the toot at point. Uses `cursor-face' special property.  |
+| mastodon-tl--load-full-sized-images-in-emacs       | Whether to load 
full-sized images inside Emacs.                               |
+| mastodon-tl--no-fill-on-render                     | Non-nil to disable 
filling by shr.el while rendering toot body.               |
+| mastodon-tl--remote-local-domains                  | A list of domains to 
view the local timelines of.                             |
+| mastodon-tl--show-avatars                          | Whether to enable 
display of user avatars in timelines.                       |
+| mastodon-tl--show-stats                            | Whether to show toot 
stats (faves, boosts, replies counts).                   |
+| mastodon-tl--symbols                               | A set of symbols (and 
fallback strings) to be used in timeline.               |
+| mastodon-tl--tag-timeline-tags                     | A list of up to four 
tags for use with `mastodon-tl--followed-tags-timeline'. |
+| mastodon-tl--timeline-posts-count                  | Number of posts to 
display when loading a timeline.                           |
+| mastodon-tl-position-after-update                  | Defines where `point' 
should be located after a timeline update.              |
+| mastodon-toot--attachment-height                   | Height of the attached 
images preview in the toot draft buffer.               |
+| mastodon-toot--completion-style-for-mentions       | The company completion 
style to use for mentions.                             |
+| mastodon-toot--default-media-directory             | The default directory 
when prompting for a media file to upload.              |
+| mastodon-toot--default-reply-visibility            | Default visibility 
settings when replying.                                    |
+| mastodon-toot--enable-completion                   | Whether to enable 
completion of mentions and hashtags.                        |
+| mastodon-toot--enable-custom-instance-emoji        | Whether to enable your 
instance's custom emoji by default.                    |
+| mastodon-toot--proportional-fonts-compose          | Nonnil to enable using 
proportional fonts in the compose buffer.              |
+| mastodon-toot--use-company-for-completion          | Whether to enable 
company for completion.                                     |
+| mastodon-toot-display-orig-in-reply-buffer         | Display a copy of the 
toot replied to in the compose buffer.                  |
+| mastodon-toot-mode-hook                            | Hook run after entering 
or leaving `mastodon-toot-mode'.                      |
+| mastodon-toot-orig-in-reply-length                 | Length to crop toot 
replied to in the compose buffer to.                      |
+| mastodon-toot-poll-use-transient                   | Whether to use the 
transient menu to create a poll.                           |
+| mastodon-toot-timestamp-format                     | Format to use for 
timestamps.                                                 |
+| mastodon-use-emojify                               | Whether to use 
emojify.el to display emojis.                                  |



reply via email to

[Prev in Thread] Current Thread [Next in Thread]