From ce0535eacaaab96a855f204ba6c65a006cd948df Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Fri, 27 Dec 2024 12:19:12 +0100 Subject: [PATCH] update mastodon Signed-off-by: Andreas Gerler --- .../dir | 0 .../mastodon-async.el | 0 .../mastodon-auth.el | 0 .../mastodon-autoloads.el | 0 .../mastodon-client.el | 0 .../mastodon-discover.el | 2 +- .../mastodon-http.el | 0 .../mastodon-inspect.el | 0 .../mastodon-iso.el | 0 .../mastodon-media.el | 4 +- .../mastodon-notifications.el | 443 ++++++++++++------ .../mastodon-pkg.el | 6 +- .../mastodon-profile.el | 94 ++-- .../mastodon-search.el | 0 .../mastodon-tl.el | 217 ++++++--- .../mastodon-toot.el | 50 +- .../mastodon-transient.el | 0 .../mastodon-views.el | 0 .../mastodon-widget.el | 0 .../mastodon.el | 14 +- .../mastodon.info | 0 21 files changed, 531 insertions(+), 299 deletions(-) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/dir (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-async.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-auth.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-autoloads.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-client.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-discover.el (98%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-http.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-inspect.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-iso.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-media.el (99%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-notifications.el (70%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-pkg.el (77%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-profile.el (94%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-search.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-tl.el (96%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-toot.el (98%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-transient.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-views.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon-widget.el (100%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon.el (98%) rename elpa/{mastodon-20241202.1839 => mastodon-20241223.1040}/mastodon.info (100%) diff --git a/elpa/mastodon-20241202.1839/dir b/elpa/mastodon-20241223.1040/dir similarity index 100% rename from elpa/mastodon-20241202.1839/dir rename to elpa/mastodon-20241223.1040/dir diff --git a/elpa/mastodon-20241202.1839/mastodon-async.el b/elpa/mastodon-20241223.1040/mastodon-async.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-async.el rename to elpa/mastodon-20241223.1040/mastodon-async.el diff --git a/elpa/mastodon-20241202.1839/mastodon-auth.el b/elpa/mastodon-20241223.1040/mastodon-auth.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-auth.el rename to elpa/mastodon-20241223.1040/mastodon-auth.el diff --git a/elpa/mastodon-20241202.1839/mastodon-autoloads.el b/elpa/mastodon-20241223.1040/mastodon-autoloads.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-autoloads.el rename to elpa/mastodon-20241223.1040/mastodon-autoloads.el diff --git a/elpa/mastodon-20241202.1839/mastodon-client.el b/elpa/mastodon-20241223.1040/mastodon-client.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-client.el rename to elpa/mastodon-20241223.1040/mastodon-client.el diff --git a/elpa/mastodon-20241202.1839/mastodon-discover.el b/elpa/mastodon-20241223.1040/mastodon-discover.el similarity index 98% rename from elpa/mastodon-20241202.1839/mastodon-discover.el rename to elpa/mastodon-20241223.1040/mastodon-discover.el index 993cc275..53f1a926 100644 --- a/elpa/mastodon-20241202.1839/mastodon-discover.el +++ b/elpa/mastodon-20241223.1040/mastodon-discover.el @@ -65,7 +65,7 @@ ("t" "New toot" mastodon-toot) ("r" "Reply" mastodon-toot--reply) ("C" "Copy toot URL" mastodon-toot--copy-toot-url) - ("o" "Open toot URL" mastodon-toot--open-toot-url) + ("o" "Open toot URL" mastodon-toot--browse-toot-url) ("d" "Delete (your) toot" mastodon-toot--delete-toot) ("D" "Delete and redraft (your) toot" mastodon-toot--delete-toot) ("e" "Edit (your) toot" mastodon-toot--edit-toot-at-point) diff --git a/elpa/mastodon-20241202.1839/mastodon-http.el b/elpa/mastodon-20241223.1040/mastodon-http.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-http.el rename to elpa/mastodon-20241223.1040/mastodon-http.el diff --git a/elpa/mastodon-20241202.1839/mastodon-inspect.el b/elpa/mastodon-20241223.1040/mastodon-inspect.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-inspect.el rename to elpa/mastodon-20241223.1040/mastodon-inspect.el diff --git a/elpa/mastodon-20241202.1839/mastodon-iso.el b/elpa/mastodon-20241223.1040/mastodon-iso.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-iso.el rename to elpa/mastodon-20241223.1040/mastodon-iso.el diff --git a/elpa/mastodon-20241202.1839/mastodon-media.el b/elpa/mastodon-20241223.1040/mastodon-media.el similarity index 99% rename from elpa/mastodon-20241202.1839/mastodon-media.el rename to elpa/mastodon-20241223.1040/mastodon-media.el index 86014103..cfb20de0 100644 --- a/elpa/mastodon-20241202.1839/mastodon-media.el +++ b/elpa/mastodon-20241223.1040/mastodon-media.el @@ -286,8 +286,8 @@ with the image." (is-error-response-p (eq :error (car status-plist)))) (let* ((data (unless is-error-response-p (goto-char (point-min)) - (search-forward "\n\n") - (buffer-substring (point) (point-max)))) + (and (search-forward "\n\n" nil t) + (buffer-substring (point) (point-max))))) (image (when data (apply #'create-image data ;; inbuilt scaling in 27.1: (when (version< emacs-version "27.1") diff --git a/elpa/mastodon-20241202.1839/mastodon-notifications.el b/elpa/mastodon-20241223.1040/mastodon-notifications.el similarity index 70% rename from elpa/mastodon-20241202.1839/mastodon-notifications.el rename to elpa/mastodon-20241223.1040/mastodon-notifications.el index c3b71beb..5790757c 100644 --- a/elpa/mastodon-20241202.1839/mastodon-notifications.el +++ b/elpa/mastodon-20241223.1040/mastodon-notifications.el @@ -33,6 +33,7 @@ (require 'subr-x) (require 'cl-lib) (require 'mastodon-widget) +(require 'map) (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-params-async-json "mastodon-http") @@ -66,10 +67,15 @@ (autoload 'mastodon-tl--goto-next-item "mastodon-tl") (autoload 'mastodon-tl--buffer-type-eq "mastodon-tl") (autoload 'mastodon-tl--buffer-property "mastodon-tl") +(autoload 'mastodon-http--patch "mastodon-http") ;; notifications defcustoms moved into mastodon.el ;; as some need to be available without loading this file +(defvar mastodon-tl--shr-map-replacement) +(defvar mastodon-tl--horiz-bar) +(defvar mastodon-active-user) +(defvar mastodon-instance-url) (defvar mastodon-tl--buffer-spec) (defvar mastodon-tl--display-media-p) (defvar mastodon-mode-map) @@ -80,10 +86,22 @@ (defvar mastodon-group-notifications) (defvar mastodon-notifications-grouped-names-count) +;;; VARIABLES + +(defvar mastodon-notifications--map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map mastodon-mode-map) + (define-key map (kbd "a") #'mastodon-notifications--follow-request-accept) + (define-key map (kbd "j") #'mastodon-notifications--follow-request-reject) + (define-key map (kbd "C-k") #'mastodon-notifications--clear-current) + (define-key map (kbd "C-c C-c") #'mastodon-notifications--cycle-type) + map) + "Keymap for viewing notifications.") + (defvar mastodon-notifications--types '("all" "favourite" "reblog" "mention" "poll" - "follow_request" "follow" "status" "update") - ;; "severed_relationships" "moderation_warning") + "follow_request" "follow" "status" "update" + "severed_relationships" "moderation_warning") "A list of notification types according to their name on the server, plus \"all\".") (defvar mastodon-notifications--filter-types-alist @@ -110,22 +128,57 @@ Notification types are named according to their name on the server.") ("Edited" . "their post")) "Alist of subjects for notification types.") -(defvar mastodon-notifications--map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map mastodon-mode-map) - (define-key map (kbd "a") #'mastodon-notifications--follow-request-accept) - (define-key map (kbd "j") #'mastodon-notifications--follow-request-reject) - (define-key map (kbd "C-k") #'mastodon-notifications--clear-current) - (define-key map (kbd "C-c C-c") #'mastodon-notifications--cycle-type) - map) - "Keymap for viewing notifications.") +(defvar mastodon-notifications-grouped-types + '(follow reblog favourite) + "List of notification types for which grouping is implemented.") -(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)) - "\n")) +(defvar mastodon-notifications--action-alist + '((reblog . "Boosted") + (favourite . "Favourited") + (follow_request . "Requested to follow") + (follow . "Followed") + (mention . "Mentioned") + (status . "Posted") + (poll . "Posted a poll") + (update . "Edited") + (severed_relationships . "Relationships severed") + (moderation_warning . "Moderation warning")) + "Action strings keyed by notification type. +Types are those of the Mastodon API.") + +(defvar mastodon-notifications--no-status-notif-alist + '(("moderation_warning" . moderation_warning) + ("severed_relationships" . event) + ("follow" . follow) + ("follow_request" . follow_request))) + +;;; VAR FETCHERS + +(defun mastodon-notifications--action-alist-get (type) + "Return an action string for notification TYPE. +Fetch from `mastodon-notifications--action-alist'. +If no match, return empty string." + (or (alist-get type mastodon-notifications--action-alist) + "")) + +(defun mastodon-notifications--response-alist-get (message) + "Return a response string for MESSAGE. +Fetch from `mastodon-notifications--response-alist'. +If no match, return empty string." + (or (alist-get + message + mastodon-notifications--response-alist nil nil #'equal) + "")) + +;;; UTILS + +(defun mastodon-notifications--api (endpoint) + "Return a notifications API ENDPOINT. +If `mastodon-group-notifications' is non-nil, use API v2." + (mastodon-http--api endpoint + (when mastodon-group-notifications "v2"))) + +;;; FOLL REQS (defun mastodon-notifications--follow-request-process (&optional reject) "Process the follow request at point. @@ -173,66 +226,64 @@ Can be called in notifications view or in follow-requests view." (interactive) (mastodon-notifications--follow-request-process :reject)) -(defun mastodon-notifications--comment-note-text (str) - "Add comment face to all text in STR with `shr-text' face only." - (with-temp-buffer - (insert str) - (goto-char (point-min)) - (let (prop) - (while (setq prop (text-property-search-forward 'face 'shr-text t)) - (add-text-properties (prop-match-beginning prop) - (prop-match-end prop) - '(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 . "Followed") - (mention . "Mentioned") - (status . "Posted") - (poll . "Posted a poll") - (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))) +;;; FORMAT NON-STANDARD NOTIFS -(defun mastodon-notifications--severance-body (group) - "Return a body for a severance notification GROUP." - ;; FIXME: actually implement this when we encounter one in the wild! - (let-alist (alist-get 'event group) +(defun mastodon-notifications--severance-body (json) + "Return a body for a severance notification JSON." + ;; https://docs.joinmastodon.org/entities/RelationshipSeveranceEvent/ + (let-alist json (concat .type ": " .target_name "\nRelationships affected: " - .relationships_count))) - -(defun mastodon-notifications--mod-warning-body (group) - "Return a body for a moderation warning notification GROUP." - (let-alist (alist-get 'moderation_warning group) - (concat .action ": " - .text + "\nFollowers: " (number-to-string .followers_count) + "\nFollowing: " (number-to-string .following_count)))) + +(defun mastodon-notifications--mod-warning-body (json) + "Return a body for a moderation warning notification JSON." + ;; https://docs.joinmastodon.org/entities/AccountWarning/ + (let-alist json + (concat .action ": \"" (string-trim .text) "\"" "\nStatuses: " - .status_ids + (mastodon-notifications--render-mod-status-links .status_ids) "\nfor account: " - .target_account))) + .target_account.acct + (if .appeal + (concat "\nYour appeal: \"" + (alist-get 'text .appeal) + "\"") + "") + "\nMore info/appeal: " + (mastodon-notifications--render-mod-link .id)))) + +(defun mastodon-notifications--propertize-link (url help-echo) + "Render a plain URL link with HELP-ECHO." + (propertize + url + 'face 'shr-link ;; mastodon-display-name-face + 'keymap mastodon-tl--shr-map-replacement + 'mastodon-tab-stop 'shr-url + 'help-echo help-echo + 'follow-link t + 'mouse-face 'highlight + 'shr-url url + 'keymap mastodon-tl--shr-map-replacement)) + +(defun mastodon-notifications--render-mod-status-links (ids) + "Render moderation status IDS as URLs." + (mapconcat (lambda (id) + (let ((str (format "%s/@%s/%s" + mastodon-instance-url + mastodon-active-user id))) + (mastodon-notifications--propertize-link str "view toot"))) + ids ", ")) + +(defun mastodon-notifications--render-mod-link (id) + "Render a moderation link for item with ID." + (let ((str (format "%s/disputes/strikes/%s" + mastodon-instance-url id))) + (mastodon-notifications--propertize-link str "View mod warning"))) + +;;; FORMAT/INSERT SINGLE NOTIF (defun mastodon-notifications--format-note (note) "Format for a NOTE, a non-grouped notification." @@ -261,7 +312,7 @@ JSON is a list of alists." note ;; body (mastodon-notifications--body-arg - type filters status profile-note follower-name) + type filters status profile-note follower-name nil note) ;; action-byline (top) (mastodon-notifications--action-byline type nil nil note follower-name) @@ -307,35 +358,24 @@ ACCOUNTS is data of the accounts that have reacted to the notification." 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-notifications--comment-note-text (str) + "Add comment face to all text in STR with `shr-text' face only." + (with-temp-buffer + (insert str) + (goto-char (point-min)) + (let (prop) + (while (setq prop (text-property-search-forward 'face 'shr-text t)) + (add-text-properties (prop-match-beginning prop) + (prop-match-end prop) + '(face (font-lock-comment-face shr-text))))) + (buffer-string))) (defun mastodon-notifications--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." + (type &optional filters status profile-note follower-name group note) + "Prepare a notification body argument. +The string returned is passed to `mastodon-notifications--insert-note'. +TYPE is a symbol, a member of `mastodon-notifiations--types'. +FILTERS STATUS PROFILE-NOTE FOLLOWER-NAME GROUP NOTE." (let ((body (if-let ((match (assoc "warn" filters))) (mastodon-tl--spoiler status (cadr match)) @@ -346,22 +386,29 @@ FILTERS STATUS PROFILE-NOTE FOLLOWER-NAME GROUP." (mastodon-tl--render-text profile-note)) (t (mastodon-tl--content status))))))) (cond + ((not (member (symbol-name type) + mastodon-notifications--types)) + "Unknown notification type.") ((eq type 'follow) (propertize "Congratulations, you have a new follower!" - 'face 'default)) + 'face 'default + 'item-type 'follow-request)) ;; nav ((eq type 'follow_request) (concat (propertize (format "You have a follow request from %s" follower-name) - 'face 'default) + 'face 'default + 'item-type 'follow-request) ;; nav (when mastodon-profile-note-in-foll-reqs (concat ":\n" (mastodon-notifications--comment-note-text body))))) ((eq type 'severed_relationships) - (mastodon-notifications--severance-body group)) + (mastodon-notifications--severance-body + (alist-get 'event (or group note)))) ((eq type 'moderation_warning) - (mastodon-notifications--mod-warning-body group)) + (mastodon-notifications--mod-warning-body + (alist-get 'moderation_warning (or group note)))) ((member type '(favourite reblog)) (propertize (mastodon-notifications--comment-note-text body))) @@ -405,7 +452,11 @@ TYPE is notification type, used for non-group notifs." 'toot-body t) ;; includes newlines etc. for folding "\n" ;; actual byline: - (mastodon-tl--byline toot nil nil base-toot group ts)) + (if (member type '("severed_relationships" "moderation_warning")) + (propertize + (concat mastodon-tl--horiz-bar "\n") + 'byline t) + (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 @@ -429,12 +480,66 @@ TYPE is notification type, used for non-group notifs." 'notifications-max-id (alist-get 'page_max_id group)) "\n"))) +;;; BYLINES + +(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* ((str-prefix (mastodon-notifications--action-alist-get type)) + (action-str + (unless (member type '(follow follow_request mention)) + (downcase + (mastodon-notifications--byline-action-str + str-prefix)))) + (action-symbol (if (eq type 'mention) + "" + (mastodon-tl--symbol type))) + (action-authors + (cond + ((not (member (symbol-name type) + mastodon-notifications--types)) + "") + ((member type + '(follow follow_request mention + severed_relationships moderation_warning)) + "") ;; mentions are normal statuses + (group + (mastodon-notifications--byline-accounts accounts group)) + (t (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-notifications--byline-action-str (message) + "Return an action (top) byline string for TOOT with MESSAGE." + (let ((resp (mastodon-notifications--response-alist-get message))) + (concat " " + (propertize message 'face 'mastodon-boosted-face) + " " resp "\n"))) + +(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--byline-accounts (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." +When AVATAR, include the account's avatar image." (let ((total (alist-get 'notifications_count group)) (accts mastodon-notifications-grouped-names-count)) (concat @@ -467,6 +572,8 @@ When DOMAIN, force inclusion of user's domain in their handle." (cddr accounts) ;; not first two ", "))))))) +;;; LOAD TIMELINE + (defun mastodon-notifications--render (json no-group) "Display grouped notifications in JSON. NO-GROUP means don't render grouped notifications." @@ -481,40 +588,59 @@ NO-GROUP means don't render grouped notifications." for accounts = (mastodon-notifications--group-accounts (alist-get 'sample_account_ids g) (alist-get 'accounts json)) - for status = (mastodon-notifications--alist-by-value - (or (alist-get 'status_id g) - ;; if no status_id, just try the first item? - (alist-get 'id - (car - (alist-get 'statuses json)))) - 'id - (alist-get 'statuses json)) + for type = (alist-get 'type g) + for status = (mastodon-notifications--status-or-event g type 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 &optional type) +(defun mastodon-notifications--status-or-event (group type json) + "Return a notification's status or event data. +Using GROUP data, notification TYPE, and overall notifs JSON." + (if (member type (map-keys mastodon-notifications--no-status-notif-alist)) + ;; notifs w no status data: + (let ((key (alist-get type mastodon-notifications--no-status-notif-alist + nil nil #'equal))) + (alist-get key group)) + (mastodon-notifications--alist-by-value + (alist-get 'status_id group) + 'id + (alist-get 'statuses json)))) + +(defun mastodon-notifications--timeline (json &optional type update) "Format JSON in Emacs buffer. -Optionally specify TYPE." +Optionally specify TYPE. +UPDATE means we are updating, so skip some things." (if (seq-empty-p json) (user-error "Looks like you have no (more) notifications for now") - (mastodon-widget--create - "Filter" mastodon-notifications--types - (or type "all") - (lambda (widget &rest _ignore) - (let ((value (widget-value widget))) - (mastodon-notifications--get-type value))) - :newline) - (insert "\n") - (mastodon-notifications--render json (not mastodon-group-notifications)) + (unless update + (mastodon-widget--create + "Filter" mastodon-notifications--types + (or type "all") + (lambda (widget &rest _ignore) + (let ((value (widget-value widget))) + (mastodon-notifications--get-type value))) + :newline) + (insert "\n")) + (mastodon-notifications--render json + (not mastodon-group-notifications)) (goto-char (point-min)) - (mastodon-tl--goto-next-item))) + ;; set last read notif ID: + (save-excursion + (mastodon-tl--goto-next-item :no-refresh) + (let ((id (mastodon-tl--property 'item-id))) ;; notif not base + (mastodon-notifications--set-last-read id))) + (unless update ;; already in tl--update + (mastodon-tl--goto-next-item)))) + +;;; VIEW LOADING FUNCTIONS (defun mastodon-notifications--get-type (&optional type) "Read a notification type and load its timeline. Optionally specify TYPE." + (interactive) (let ((choice (or type (completing-read "View notifications: " @@ -540,12 +666,16 @@ With arg PREFIX, `completing-read' a type and load it." nil nil #'equal))) (funcall fun)))) +(defun mastodon-notifications--current-type () + "Return the current notification type or nil." + (let* ((update-params (mastodon-tl--buffer-property + 'update-params nil :no-error))) + (alist-get "types[]" update-params nil nil #'equal))) + (defun mastodon-notifications--get-next-type () "Return the next notif type based on current buffer spec." - (let* ((update-params (mastodon-tl--buffer-property - 'update-params nil :no-error)) - (type (alist-get "types[]" update-params nil nil #'equal))) - (if (not update-params) + (let* ((type (mastodon-notifications--current-type))) + (if (not type) (cadr mastodon-notifications--types) (or (cadr (member type mastodon-notifications--types)) (car mastodon-notifications--types))))) @@ -596,12 +726,15 @@ Status notifications are created when you call "Return a list of notification types with TYPE removed." (remove type mastodon-notifications--types)) +;;; CLEAR/DISMISS NOTIFS + (defun mastodon-notifications--clear-all () "Clear all notifications." (interactive) (when (y-or-n-p "Clear all notifications?") (let ((response - (mastodon-http--post (mastodon-http--api "notifications/clear")))) + (mastodon-http--post + (mastodon-notifications--api "notifications/clear")))) (mastodon-http--triage response (lambda (_) (when mastodon-tl--buffer-spec @@ -616,9 +749,8 @@ Status notifications are created when you call (mastodon-tl--field 'id (mastodon-tl--property 'item-json))))) - (endpoint (mastodon-http--api - (format "notifications/%s/dismiss" id) - "v2")) + (endpoint (mastodon-notifications--api + (format "notifications/%s/dismiss" id))) (response (mastodon-http--post endpoint))) (mastodon-http--triage response (lambda (_) @@ -626,6 +758,21 @@ Status notifications are created when you call (mastodon-tl--reload-timeline-or-profile)) (message "Notification dismissed!"))))) +;;; MISC + +(defun mastodon-notifications--set-last-read (id) + "Set the last read notification ID on the server." + (let ((endpoint (mastodon-http--api "markers")) + (params `(("notifications[last_read_id]" . ,id)))) + (mastodon-http--post endpoint params))) + +(defun mastodon-notifications--get-last-read () + "Return the last read notification ID from the server." + (let* ((params '(("timeline[]" . "notifications"))) + (endpoint (mastodon-http--api "markers")) + (resp (mastodon-http--get-json endpoint params))) + (map-nested-elt resp '(notifications last_read_id)))) + (defun mastodon-notifications--get-single-notif () "Return a single notification JSON for v2 notifs." (interactive) @@ -633,21 +780,39 @@ Status notifications are created when you call 'notification-id)) ;; grouped, doesn't work for ungrouped! ;; (key (format "ungrouped-%s" ;; (mastodon-tl--property 'item-id))) - (endpoint (mastodon-http--api - (format "notifications/%s" id) - "v2")) + (endpoint (mastodon-notifications--api + (format "notifications/%s" id))) (response (mastodon-http--get-json endpoint))) (mastodon-http--triage - response (lambda (_) + response (lambda (response) (message "%s" (prin1-to-string response)))))) (defun mastodon-notifications--get-unread-count () "Return the number of unread notifications for the current account." ;; params: limit - max 1000, default 100, types[], exclude_types[], account_id (let* ((endpoint "notifications/unread_count") - (url (mastodon-http--api endpoint)) + (url (mastodon-http--api endpoint + (when mastodon-group-notifications "v2"))) (resp (mastodon-http--get-json url))) (alist-get 'count resp))) +(defvar mastodon-notifications--policy-vals + '("accept" "filter" "drop")) + +(defun mastodon-notifications--get-policy () + "Return the notification filtering policy." + (interactive) + (let ((url + (mastodon-notifications--api "notifications/policy"))) + (mastodon-http--get-json url))) + +(defun mastodon-notifications--update-policy (&optional params) + "Update notifications filtering policy. +PARAMS is an alist of parameters." + ;; https://docs.joinmastodon.org/methods/notifications/#update-the-filtering-policy-for-notifications + (let ((url + (mastodon-notifications--api "notifications/policy"))) + (mastodon-http--patch url params))) + (provide 'mastodon-notifications) ;;; mastodon-notifications.el ends here diff --git a/elpa/mastodon-20241202.1839/mastodon-pkg.el b/elpa/mastodon-20241223.1040/mastodon-pkg.el similarity index 77% rename from elpa/mastodon-20241202.1839/mastodon-pkg.el rename to elpa/mastodon-20241223.1040/mastodon-pkg.el index d3d938d4..14d0de12 100644 --- a/elpa/mastodon-20241202.1839/mastodon-pkg.el +++ b/elpa/mastodon-20241223.1040/mastodon-pkg.el @@ -1,13 +1,13 @@ ;; -*- no-byte-compile: t; lexical-binding: nil -*- -(define-package "mastodon" "20241202.1839" +(define-package "mastodon" "20241223.1040" "Client for fediverse services using the Mastodon API." '((emacs "28.1") (request "0.3.0") (persist "0.4") (tp "0.6")) :url "https://codeberg.org/martianh/mastodon.el" - :commit "10be1f9c2845a6012cee84b68dc566ea92df40a6" - :revdesc "10be1f9c2845" + :commit "e2443f1cd425b31228e87739d1fc5035640bba06" + :revdesc "e2443f1cd425" :authors '(("Johnson Denen" . "johnson.denen@gmail.com") ("Marty Hiatt" . "mousebot@disroot.org")) :maintainers '(("Marty Hiatt" . "mousebot@disroot.org"))) diff --git a/elpa/mastodon-20241202.1839/mastodon-profile.el b/elpa/mastodon-20241223.1040/mastodon-profile.el similarity index 94% rename from elpa/mastodon-20241202.1839/mastodon-profile.el rename to elpa/mastodon-20241223.1040/mastodon-profile.el index ee3f3d23..417a7872 100644 --- a/elpa/mastodon-20241202.1839/mastodon-profile.el +++ b/elpa/mastodon-20241223.1040/mastodon-profile.el @@ -165,14 +165,18 @@ MAX-ID is a flag to include the max_id pagination parameter." ;;; PROFILE VIEW COMMANDS (defvar mastodon-profile--account-view-alist - '(("statuses" . mastodon-profile--open-statuses) - ("no boosts" . mastodon-profile--open-statuses-no-reblogs) - ("no replies" . mastodon-profile--open-statuses-no-replies) - ("only media" . mastodon-profile--open-statuses-only-media) - ("followers" . mastodon-profile--open-followers) - ("following" . mastodon-profile--open-following))) - -;; TODO: we shd just load all views' data then switch coz this is slow af: + '((statuses . mastodon-profile--open-statuses) + (no-boosts . mastodon-profile--open-statuses-no-reblogs) + (no-replies . mastodon-profile--open-statuses-no-replies) + (only-media . mastodon-profile--open-statuses-only-media) + (followers . mastodon-profile--open-followers) + (following . mastodon-profile--open-following) + (tag . mastodon-profile--open-statuses-tagged))) + +(defun mastodon-profile--view-types () + "Return the keys of `mastodon-profile--account-view-alist' as a list." + (map-keys mastodon-profile--account-view-alist)) + (defun mastodon-profile--account-view-cycle (&optional prefix) "Cycle through profile view: toots, toot sans boosts, followers, and following." (interactive "P") @@ -180,8 +184,7 @@ MAX-ID is a flag to include the max_id pagination parameter." (let* ((choice (completing-read "Profile view:" mastodon-profile--account-view-alist)) - (fun (alist-get choice mastodon-profile--account-view-alist - nil nil #'equal))) + (fun (alist-get choice mastodon-profile--account-view-alist))) (funcall fun)) (cond ((mastodon-tl--buffer-type-eq 'profile-statuses) (mastodon-profile--open-statuses-no-reblogs)) @@ -568,27 +571,6 @@ The endpoint only holds a few preferences. For others, see "\n\n")) (goto-char (point-min))))) - -;;; PROFILE WIDGET - -(defvar mastodon-profile--view-types - '(statuses no-boosts no-replies only-media followers following tag)) - -(defvar mastodon-profile--load-funs-alist - `((statuses . mastodon-profile--open-statuses) - (no-boosts . mastodon-profile--open-statuses-no-reblogs) - (no-replies . mastodon-profile--open-statuses-no-replies) - (only-media . mastodon-profile--open-statuses-only-media) - (followers . mastodon-profile--open-followers) - (following . mastodon-profile--open-following) - (tag . mastodon-profile--open-statuses-tagged))) - -(defun mastodon-profile--view-fun-call (type) - "Call the function associated with TYPE. -Fetched from `mastodon-profile--load-funs-alist'." - (funcall - (alist-get type mastodon-profile--load-funs-alist))) - ;;; PROFILE VIEW DETAILS @@ -743,35 +725,41 @@ MAX-ID is a flag to include the max_id pagination parameter." 'success) ;; insert relationship (follows) (let-alist relationships - (let* ((followsp (mastodon-profile--follows-p - (list .requested_by .following .followed_by))) - (rels (mastodon-profile--relationships-get .id)) - (langs-filtered (if-let ((langs (alist-get 'languages rels))) - (concat " (" - (mapconcat #'identity langs " ") - ")") - ""))) - (if followsp - (mastodon-tl--set-face - (concat (when (eq .following t) - (format " | FOLLOWED BY YOU%s" langs-filtered)) - (when (eq .followed_by t) - " | FOLLOWS YOU") - (when (eq .requested_by t) - " | REQUESTED TO FOLLOW YOU") - "\n\n") - 'success) - "")))) ; for insert call + (if (not .id) + ;; sharkey has no relationships endpoint, returns 500. + ;; or poss it has a different endpoint + "" + (let* ((followsp (mastodon-profile--follows-p + (list .requested_by .following .followed_by))) + (rels (mastodon-profile--relationships-get .id)) + (langs-filtered (if-let ((langs (alist-get 'languages rels))) + (concat " (" + (mapconcat #'identity langs " ") + ")") + ""))) + (if followsp + (mastodon-tl--set-face + (concat (when (eq .following t) + (format " | FOLLOWED BY YOU%s" langs-filtered)) + (when (eq .followed_by t) + " | FOLLOWS YOU") + (when (eq .requested_by t) + " | REQUESTED TO FOLLOW YOU") + "\n\n") + 'success) + ""))))) ; for insert call (mastodon-media--inline-images (point-min) (point)) ;; widget items description (mastodon-widget--create - "View" mastodon-profile--view-types + "View" (mastodon-profile--view-types) (or (mastodon-profile--current-view-type endpoint-type no-reblogs no-replies only-media tag) 'statuses) (lambda (widget &rest _ignore) (let ((value (widget-value widget))) - (mastodon-profile--view-fun-call value)))) + (funcall + (alist-get value + mastodon-profile--account-view-alist))))) (insert "\n") (setq mastodon-tl--update-point (point)))) ;; split insert of items from insert of profile: @@ -800,7 +788,7 @@ NO-REBLOGS, NO-REPLIES, ONLY-MEDIA and TAG." (no-replies 'no-replies) (only-media 'only-media) (tag 'tag) - (t (intern type)))) + (t (if (stringp type) (intern type) type)))) (defun mastodon-profile--format-joined-date-string (joined) "Format a human-readable Joined string from timestamp JOINED. diff --git a/elpa/mastodon-20241202.1839/mastodon-search.el b/elpa/mastodon-20241223.1040/mastodon-search.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-search.el rename to elpa/mastodon-20241223.1040/mastodon-search.el diff --git a/elpa/mastodon-20241202.1839/mastodon-tl.el b/elpa/mastodon-20241223.1040/mastodon-tl.el similarity index 96% rename from elpa/mastodon-20241202.1839/mastodon-tl.el rename to elpa/mastodon-20241223.1040/mastodon-tl.el index 763569bb..781c2736 100644 --- a/elpa/mastodon-20241202.1839/mastodon-tl.el +++ b/elpa/mastodon-20241223.1040/mastodon-tl.el @@ -92,6 +92,8 @@ (autoload 'mastodon-media--image-or-cached "mastodon-media") (autoload 'mastodon-toot--base-toot-or-item-json "mastodon-toot") (autoload 'mastodon-search--load-link-posts "mastodon-search") +(autoload 'mastodon-notifications--current-type "mastodon-notifications") +(autoload 'mastodon-notifications--timeline "mastodon-notifications") (defvar mastodon-toot--visibility) (defvar mastodon-toot-mode) @@ -153,25 +155,27 @@ nil." :type 'boolean) (defcustom mastodon-tl--symbols - '((reply . ("💬" . "R")) - (boost . ("🔁" . "B")) - (reblog . ("🔁" . "B")) ;; server compat - (favourite . ("⭐" . "F")) - (bookmark . ("🔖" . "K")) - (media . ("📹" . "[media]")) - (verified . ("✓" . "V")) - (locked . ("🔒" . "[locked]")) - (private . ("🔒" . "[followers]")) - (mention . ("@" . "[mention]")) - (direct . ("✉" . "[direct]")) - (edited . ("✍" . "[edited]")) - (update . ("✍" . "[edited]")) ;; server compat - (status . ("✍" . "[posted]")) - (replied . ("⬇" . "↓")) - (reply-bar . ("┃" . "|")) - (poll . ("📊" . "")) - (follow . ("👤" . "+")) - (follow_request . ("👤" . "+"))) + '((reply . ("💬" . "R")) + (boost . ("🔁" . "B")) + (reblog . ("🔁" . "B")) ;; server compat + (favourite . ("⭐" . "F")) + (bookmark . ("🔖" . "K")) + (media . ("📹" . "[media]")) + (verified . ("✓" . "V")) + (locked . ("🔒" . "[locked]")) + (private . ("🔒" . "[followers]")) + (mention . ("@" . "[mention]")) + (direct . ("✉" . "[direct]")) + (edited . ("✍" . "[edited]")) + (update . ("✍" . "[edited]")) ;; server compat + (status . ("✍" . "[posted]")) + (replied . ("⬇" . "↓")) + (reply-bar . ("┃" . "|")) + (poll . ("📊" . "")) + (follow . ("👤" . "+")) + (follow_request . ("👤" . "+")) + (severed_relationships . ("🔗" . "//")) + (moderation_warning . ("⚠" . "!!"))) "A set of symbols (and fallback strings) to be used in timeline. If a symbol does not look right (tofu), it means your font settings do not support it." @@ -437,13 +441,15 @@ found." (unless no-refresh 'mastodon-tl--more)) (t (error "No more items")))) -(defun mastodon-tl--goto-prev-item () +(defun mastodon-tl--goto-prev-item (&optional no-refresh) "Jump to previous item. -Update if no previous items" +Update if no previous items. +NO-REFRESH means do no not try to load more items if no next item +found." (interactive) (condition-case nil (mastodon-tl--goto-item-pos 'previous-single-property-change - 'mastodon-tl--update) + (unless no-refresh 'mastodon-tl--update)) (t (error "No more items")))) (defun mastodon-tl--goto-first-item () @@ -646,19 +652,18 @@ The last two args allow for display a username as a clickable handle." (let-alist (or (alist-get 'account toot) toot) ;; grouped notifs - (propertize (or string - (concat "@" .acct - (when domain - (concat "@" - (url-host - (url-generic-parse-url .url)))))) - 'face (or face 'mastodon-handle-face) - 'mouse-face 'highlight - 'mastodon-tab-stop 'user-handle - 'shr-url .url - 'keymap mastodon-tl--link-keymap - 'mastodon-handle (concat "@" .acct) - 'help-echo (concat "Browse user profile of @" .acct)))) + (mastodon-tl--buttonify-link + (or string + (concat "@" .acct + (when domain + (concat "@" + (url-host + (url-generic-parse-url .url)))))) + 'face (or face 'mastodon-handle-face) + 'mastodon-tab-stop 'user-handle + 'shr-url .url + 'mastodon-handle (concat "@" .acct) + 'help-echo (concat "Browse user profile of @" .acct)))) (defun mastodon-tl--byline-uname-+-handle (data &optional domain) "Concatenate a byline username and handle. @@ -968,8 +973,12 @@ links in the text. If TOOT is nil no parsing occurs." (shr-width (when mastodon-tl--enable-proportional-fonts (if mastodon-tl--no-fill-on-render 0 - (- (window-width) 3))))) - (shr-render-region (point-min) (point-max))) + (- (window-width) 3)))) + (cat (get 'mastodon-tl-link 'button-category-symbol))) + (shr-render-region (point-min) (point-max)) + (alter-text-property + (point-min) (point-max) 'category + (lambda (type) (when type cat)))) ;; Make all links a tab stop recognized by our own logic, make ;; things point to our own logic (e.g. hashtags), and update keymaps ;; where needed: @@ -1010,7 +1019,7 @@ links in the text. If TOOT is nil no parsing occurs." ;; FIXME: replace with refactored handle render fun ;; in byline refactor branch: (concat - (propertize .username + (propertize (or .display_name .username) 'face 'mastodon-display-name-face 'item-type 'user 'item-id .id) @@ -1137,6 +1146,23 @@ the toot)." ;;; HYPERLINKS +(define-button-type 'mastodon-tl-link + 'action #'mastodon-tl--push-button + 'keymap mastodon-tl--link-keymap + 'mouse-face 'highlight) + +(defun mastodon-tl--push-button (button) + "Do the appropriate action for BUTTON." + (mastodon-tl--do-link-action-at-point (button-start button))) + +(defun mastodon-tl--buttonify-link (string &rest properties) + "Make STRING a `mastodon-tl-link' type button. +PROPERTIES are additional properties to attach to string." + (apply #'propertize string + 'button t + 'category (get 'mastodon-tl-link 'button-category-symbol) + properties)) + (defun mastodon-tl--make-link (string link-type) "Return a propertized version of STRING that will act like link. LINK-TYPE is the type of link to produce." @@ -1147,11 +1173,9 @@ LINK-TYPE is the type of link to produce." "Toggle full post") (t (error "Unknown link type %s" link-type))))) - (propertize string - 'mastodon-tab-stop link-type - 'mouse-face 'highlight - 'keymap mastodon-tl--link-keymap - 'help-echo help-text))) + (mastodon-tl--buttonify-link string + 'mastodon-tab-stop link-type + 'help-echo help-text))) (defun mastodon-tl--do-link-action-at-point (pos) "Do the action of the link at POS. @@ -1185,6 +1209,8 @@ Used for hitting RET on a given link." (mastodon-url-lookup (get-text-property pos 'shr-url))) (t (error "Unable to find account")))))))) + ((eq link-type 'shr-url) + (mastodon-url-lookup (get-text-property pos 'shr-url))) ((eq link-type 'read-more) (mastodon-tl--unfold-post)) ((eq link-type 'read-less) @@ -1244,7 +1270,7 @@ content should be hidden." "Toggler content warning for all posts in current thread." (interactive) (let ((thread-p (eq (mastodon-tl--buffer-property 'update-function) - 'mastodon-tl--thread))) + 'mastodon-tl--thread-do))) (if (not thread-p) (user-error "Not in a thread") (save-excursion @@ -2308,7 +2334,9 @@ ID is that of the toot to view." (user-error "Error: %s" (cdar toot)) (with-mastodon-buffer buffer #'mastodon-mode nil (mastodon-tl--set-buffer-spec buffer (format "statuses/%s" id) - #'mastodon-tl--update-toot) + #'mastodon-tl--update-toot + ;; id for reload on reply: + nil nil nil nil id) (mastodon-tl--toot toot :detailed-p) (goto-char (point-min)) (when mastodon-tl--display-media-p @@ -2331,23 +2359,17 @@ view all branches of a thread." (user-error "You need to be viewing a thread to call this") (goto-char (point-min)) (let ((id (mastodon-tl--property 'base-item-id))) - (mastodon-tl--thread id)))) + (mastodon-tl--thread-do id)))) -(defun mastodon-tl--thread (&optional thread-id) - "Open thread buffer for toot at point or with THREAD-ID. -UNFOLDED STATE is a boolean of whether the thread (that we are -reloading) is fully unfolded or folded, i.e. via -`mastodon-tl--toggle-spoiler-in-thread'." +(defun mastodon-tl--thread () + "Open thread buffer for toot at point." (interactive) (if (not (eq 'toot (mastodon-tl--property 'item-type :no-move))) (user-error "Looks like there's no toot at point?") - (mastodon-tl--thread-do thread-id))) + (mastodon-tl--thread-do))) (defun mastodon-tl--thread-do (&optional thread-id) "Open thread buffer for toot at point or with THREAD-ID. -UNFOLDED STATE is a boolean of whether the thread (that we are -reloading) is fully unfolded or folded, i.e. via -`mastodon-tl--toggle-spoiler-in-thread'. This is the non-interactive version, so we can call it programmatically and not crash into `mastodon-toot--with-toot-item'." @@ -2387,12 +2409,13 @@ programmatically and not crash into (with-mastodon-buffer buffer #'mastodon-mode nil (let ((marker (make-marker))) (mastodon-tl--set-buffer-spec buffer endpoint - #'mastodon-tl--thread + #'mastodon-tl--thread-do nil nil nil nil id) (when unfolded-state (plist-put mastodon-tl--buffer-spec 'thread-unfolded unfolded-state)) - (mastodon-tl--timeline (alist-get 'ancestors context) :thread) + (when-let ((ancestors (alist-get 'ancestors context))) + (mastodon-tl--timeline ancestors :thread)) (goto-char (point-max)) (move-marker marker (point)) ;; print re-fetched toot: @@ -2402,11 +2425,11 @@ programmatically and not crash into (when mastodon-tl--display-media-p (mastodon-media--inline-images marker ;start-pos (point))) - (mastodon-tl--timeline (alist-get 'descendants context) - :thread) + (when-let ((descendants (alist-get 'descendants context))) + (mastodon-tl--timeline descendants :thread)) ;; put point at the toot: (goto-char (marker-position marker)) - (mastodon-tl--goto-next-item))))))))) + (mastodon-tl--goto-next-item :no-refresh))))))))) (defun mastodon-tl--mute-thread () "Mute the thread displayed in the current buffer. @@ -2740,6 +2763,39 @@ ARGS is an alist of any parameters to send with the request." (message "Follow requested for user %s (@%s)!" name user-handle) (message "User %s (@%s) %sed!" name user-handle action))))))))) +(defun mastodon-tl--get-domain-blocks () + "Return a list of current domain blocks." + (mastodon-http--get-json + (mastodon-http--api "domain_blocks"))) + +(defun mastodon-tl--block-domain () + "Read a domain and block it." + (interactive) + (let* ((domain (read-string "Block domain: ")) + (params `(("domain" . ,domain))) + (url (mastodon-http--api "domain_blocks")) + (resp (mastodon-http--post url params))) + (mastodon-http--triage + resp + (lambda (_) + (message "Domain blocked!"))))) + +(defun mastodon-tl--unblock-domain () + "Read a blocked domain and unblock it." + (interactive) + (let ((blocks (mastodon-tl--get-domain-blocks))) + (if (not blocks) + (user-error "No blocked domains?") + (let* ((domain (completing-read "Unblock domain: " + blocks)) + (params `(("domain" . ,domain))) + (url (mastodon-http--api "domain_blocks")) + (resp (mastodon-http--delete url params))) + (mastodon-http--triage + resp + (lambda (_) + (message "Domain unblocked!"))))))) + ;; FOLLOW TAGS @@ -2981,8 +3037,11 @@ Aims to respect any pagination in effect." ((eq type 'profile-statuses) (save-excursion (goto-char (point-min)) - (mastodon-profile--get-toot-author max-id))) - ((eq type 'thread) + (mastodon-profile--make-author-buffer + ;; (mastodon-profile--get-toot-author max-id))) + (mastodon-profile--profile-json)))) + ((or (eq type 'single-status) + (eq type 'thread)) (let ((id (mastodon-tl--buffer-property 'thread-item-id (current-buffer) :no-error))) (mastodon-tl--thread-do id)))) @@ -2991,7 +3050,7 @@ Aims to respect any pagination in effect." ;; end up past where we were, etc. (when pos (goto-char pos) - (mastodon-tl--goto-prev-item)))) + (mastodon-tl--goto-prev-item :no-refresh)))) (defun mastodon-tl--build-link-header-url (str) "Return a URL from STR, an http Link header." @@ -3078,19 +3137,26 @@ MAX-ID is the pagination parameter, a string." (alist-get 'accounts response)))))) (headers (when headers (cdr response))) (link-header - (mastodon-tl--get-link-header-from-response headers))) + (mastodon-tl--get-link-header-from-response headers)) + (buf-type (mastodon-tl--get-buffer-type)) + (notifs-p (or (eq buf-type 'notifications) + (eq buf-type 'mentions))) + (notif-type (when notifs-p + (mastodon-notifications--current-type)))) (goto-char (point-max)) - (if (eq 'thread (mastodon-tl--get-buffer-type)) + (if (eq 'thread buf-type) ;; if thread fully unfolded, respect it: - ;; if thread view, call --thread with parent ID + ;; if thread view, call --thread-do with parent ID (progn (goto-char (point-min)) (mastodon-tl--goto-next-item) - (mastodon-tl--thread) + (mastodon-tl--thread-do) (goto-char point-before) (message "Loaded full thread.")) (if (not json) (user-error "No more results") - (funcall (mastodon-tl--update-function) json) + (if notifs-p + (mastodon-notifications--timeline json notif-type :update) + (funcall (mastodon-tl--update-function) json)) (goto-char point-before) ;; update buffer spec to new link-header or max-id: ;; (other values should just remain as they were) @@ -3278,22 +3344,24 @@ This location is defined by a non-nil value of (user-error "Update not available in this view") ;; FIXME: handle update for search and trending buffers (let* ((endpoint (mastodon-tl--endpoint)) - (update-function (mastodon-tl--update-function))) + (update-function (mastodon-tl--update-function)) + (id (mastodon-tl--newest-id))) ;; update a thread, without calling `mastodon-tl--updated-json': (if (mastodon-tl--buffer-type-eq 'thread) ;; load whole thread: - (progn (mastodon-tl--thread) + (progn (mastodon-tl--thread-do id) (message "Loaded full thread.")) ;; update other timelines: - (let* ((id (mastodon-tl--newest-id)) - (params (mastodon-tl--update-params)) + (let* ((params (mastodon-tl--update-params)) (json (mastodon-tl--updated-json endpoint id params))) (if (not json) (user-error "Nothing to update") (let ((inhibit-read-only t)) (mastodon-tl--set-after-update-marker) (goto-char (or mastodon-tl--update-point (point-min))) - (funcall update-function json) + (if (eq update-function 'mastodon-notifications--timeline) + (funcall update-function json nil :update) + (funcall update-function json)) (if mastodon-tl--after-update-marker (goto-char mastodon-tl--after-update-marker) (mastodon-tl--goto-next-item))))))))) @@ -3404,7 +3472,8 @@ ENDPOINT-VERSION is a string, format Vx, e.g. V2." "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. -NO-BYLINE means just insert toot body, used for announcements." +NO-BYLINE means just insert toot body, used for announcements. +TYPE is a notification type." (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/elpa/mastodon-20241202.1839/mastodon-toot.el b/elpa/mastodon-20241223.1040/mastodon-toot.el similarity index 98% rename from elpa/mastodon-20241202.1839/mastodon-toot.el rename to elpa/mastodon-20241223.1040/mastodon-toot.el index 1bc48c8c..b80dc468 100644 --- a/elpa/mastodon-20241202.1839/mastodon-toot.el +++ b/elpa/mastodon-20241223.1040/mastodon-toot.el @@ -583,10 +583,12 @@ base toot." (kill-new url) (message "Toot URL copied to the clipboard."))) -(defun mastodon-toot--open-toot-url () - "Open URL of toot at point." +(defun mastodon-toot--browse-toot-url () + "Browse URL of toot at point. +Calls `browse-url'." (interactive) - (browse-url (mastodon-toot--toot-url))) + (browse-url + (mastodon-toot--toot-url))) (defun mastodon-toot--toot-url () "Return the URL of the base toot at point." @@ -791,7 +793,7 @@ TEXT-ONLY means don't check for attachments or polls." (interactive) (if mastodon-use-emojify (emojify-insert-emoji) - (emoji-search))) + (emoji-search))) ;; 29.1 (defun mastodon-toot--emoji-dir () "Return the file path for the mastodon custom emojis directory." @@ -974,12 +976,14 @@ instance to edit a toot." (mastodon-toot--restore-previous-window-config prev-window-config) ;; reload: - when we have been editing ;; - when we are in thread view - ;; (we don't reload in every case as it can be slow and we may - ;; lose our place in a timeline.) - (when (or edit-id - (eq 'thread (mastodon-tl--get-buffer-type))) - (let ((pos (marker-position (cadr prev-window-config)))) - (mastodon-tl--reload-timeline-or-profile pos)))))))))) + ;; (we don't reload in every case as it can be slow and we + ;; may lose our place in a timeline.) + (let ((type (mastodon-tl--get-buffer-type))) + (when (or edit-id + (eq 'single-status type) + (eq 'thread type)) + (let ((pos (marker-position (cadr prev-window-config)))) + (mastodon-tl--reload-timeline-or-profile pos))))))))))) ;;; EDITING TOOTS: @@ -1251,20 +1255,24 @@ prefixed by >." (message "NSFW flag is now %s" (if mastodon-toot--content-nsfw "on" "off")) (mastodon-toot--update-status-fields)) -(defun mastodon-toot--change-visibility () - "Change the current visibility to the next valid value." - (interactive) +(defun mastodon-toot--change-visibility (&optional arg) + "Change the current visibility to the next valid value. +With prefix ARG, read a visibility type in the minibuffer." + (interactive "P") (if (mastodon-tl--buffer-type-eq 'edit-toot) (user-error "You can't change visibility when editing toots") (setq mastodon-toot--visibility - (cond ((string= mastodon-toot--visibility "public") - "unlisted") - ((string= mastodon-toot--visibility "unlisted") - "private") - ((string= mastodon-toot--visibility "private") - "direct") - (t - "public"))) + (if arg + (completing-read "Visibility: " + mastodon-toot-visibility-list) + (cond ((string= mastodon-toot--visibility "public") + "unlisted") + ((string= mastodon-toot--visibility "unlisted") + "private") + ((string= mastodon-toot--visibility "private") + "direct") + (t + "public")))) (mastodon-toot--update-status-fields))) (defun mastodon-toot--set-toot-language () diff --git a/elpa/mastodon-20241202.1839/mastodon-transient.el b/elpa/mastodon-20241223.1040/mastodon-transient.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-transient.el rename to elpa/mastodon-20241223.1040/mastodon-transient.el diff --git a/elpa/mastodon-20241202.1839/mastodon-views.el b/elpa/mastodon-20241223.1040/mastodon-views.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-views.el rename to elpa/mastodon-20241223.1040/mastodon-views.el diff --git a/elpa/mastodon-20241202.1839/mastodon-widget.el b/elpa/mastodon-20241223.1040/mastodon-widget.el similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon-widget.el rename to elpa/mastodon-20241223.1040/mastodon-widget.el diff --git a/elpa/mastodon-20241202.1839/mastodon.el b/elpa/mastodon-20241223.1040/mastodon.el similarity index 98% rename from elpa/mastodon-20241202.1839/mastodon.el rename to elpa/mastodon-20241223.1040/mastodon.el index 808cc656..6f911f15 100644 --- a/elpa/mastodon-20241202.1839/mastodon.el +++ b/elpa/mastodon-20241223.1040/mastodon.el @@ -6,8 +6,8 @@ ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt -;; Package-Version: 20241202.1839 -;; Package-Revision: 10be1f9c2845 +;; Package-Version: 20241223.1040 +;; Package-Revision: e2443f1cd425 ;; Package-Requires: ((emacs "28.1") (request "0.3.0") (persist "0.4") (tp "0.6")) ;; Homepage: https://codeberg.org/martianh/mastodon.el @@ -37,7 +37,7 @@ ;; file at . ;;; Code: -(require 'cl-lib) ; for `cl-some' call in mastodon +(require 'cl-lib) ; for `cl-some' call in `mastodon' (eval-when-compile (require 'subr-x)) (require 'url) (require 'thingatpt) @@ -229,7 +229,7 @@ and X others...\"." (define-key map (kbd "k") #'mastodon-toot--toggle-bookmark) (define-key map (kbd "r") #'mastodon-toot--reply) (define-key map (kbd "C") #'mastodon-toot--copy-toot-url) - (define-key map (kbd "o") #'mastodon-toot--open-toot-url) + (define-key map (kbd "o") #'mastodon-toot--browse-toot-url) (define-key map (kbd "v") #'mastodon-tl--poll-vote) (define-key map (kbd "E") #'mastodon-toot--view-toot-edits) (define-key map (kbd "T") #'mastodon-tl--thread) @@ -418,7 +418,8 @@ MAX-ID is a request parameter for pagination." "v1" "v2")) (with-current-buffer (get-buffer-create buffer) - (use-local-map mastodon-notifications--map)))) + (use-local-map mastodon-notifications--map)) + (message "Loading your notifications... Done"))) ;; URL lookup: should be available even if `mastodon.el' not loaded: @@ -531,7 +532,8 @@ Calls `mastodon-tl--get-buffer-type', which see." (when mastodon-toot--enable-custom-instance-emoji (mastodon-toot--enable-custom-emoji))) (mastodon-profile--fetch-server-account-settings) - (when mastodon-tl--highlight-current-toot + (when (and mastodon-tl--highlight-current-toot + (fboundp #'cursor-face-highlight-mode)) (cursor-face-highlight-mode)) ; 29.1 ;; make `thing-at-point' functions work: (setq-local thing-at-point-provider-alist diff --git a/elpa/mastodon-20241202.1839/mastodon.info b/elpa/mastodon-20241223.1040/mastodon.info similarity index 100% rename from elpa/mastodon-20241202.1839/mastodon.info rename to elpa/mastodon-20241223.1040/mastodon.info -- 2.47.3