branch: elpa/mastodon
commit a8baf9bbcba4a108e9e1a51552b9df1c4be06e60
Author: marty hiatt <martianhia...@disroot.org>
Commit: marty hiatt <martianhia...@disroot.org>

    implement full sized image cycling. #666.
    
    - adds mastodon-image-mode inheriting image-mode
    - keymap for cycling on `.`/`>`/`<right>`
    - modifies toot attachments text property order
    - adds mastodon-media--attachments local variable in image buffer
    - media.el: full sized image response now requires attachments arg, and
    - optional prev-buf arg.
---
 lisp/mastodon-media.el | 22 ++++++++----
 lisp/mastodon-tl.el    | 92 ++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 98 insertions(+), 16 deletions(-)

diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el
index 841d30397c..85e341c5a1 100644
--- a/lisp/mastodon-media.el
+++ b/lisp/mastodon-media.el
@@ -332,7 +332,12 @@ image-data prop so it can be toggled."
                              mastodon-media--sensitive-image-data nil t)
                            sensitive-state hidden image-data ,image))))
 
-(defun mastodon-media--process-full-sized-image-response (status-plist url)
+(defvar mastodon-media--attachments nil
+  "A list attachment details for full sized image view buffer.
+The first element is the URL of the image displayed, followed by plists of 
details of all of a toot's attachments.")
+
+(defun mastodon-media--process-full-sized-image-response
+    (status-plist url attachments &optional prev-buf)
   ;; FIXME: refactor this with but not into
   ;; `mastodon-media--process-image-response'.
   "Callback function processing the `url-retrieve' response for URL.
@@ -347,16 +352,21 @@ STATUS-PLIST is a plist of status events as per 
`url-retrieve'."
     ;; https://codeberg.org/martianh/mastodon.el/issues/540
     (let* ((handle (mm-dissect-buffer t))
            (image (mm-get-image handle))
-           (str (image-property image :data)))
-      (with-current-buffer (get-buffer-create "*masto-image*")
+           (str (image-property image :data))
+           (buf "*masto-image*"))
+      (with-current-buffer (get-buffer-create buf)
         (let ((inhibit-read-only t))
           (erase-buffer)
           (insert-image image str)
           (special-mode) ; prevent image-mode loop bug
-          (image-mode)
+          (mastodon-image-mode) ;; for our keymap
           (goto-char (point-min))
-          (switch-to-buffer-other-window (current-buffer))
-          (image-transform-fit-both))))))
+          (image-transform-fit-both)
+          ;; set image metadata for view cycling:
+          (setq-local mastodon-media--attachments (cons url attachments))))
+      ;; switch to buf if not already viewing it:
+      (unless (equal buf prev-buf)
+        (switch-to-buffer-other-window buf)))))
 
 (defun mastodon-media--image-or-cached (url process-fun args)
   "Fetch URL from cache or fro host.
diff --git a/lisp/mastodon-tl.el b/lisp/mastodon-tl.el
index 33913d8b66..230962e515 100644
--- a/lisp/mastodon-tl.el
+++ b/lisp/mastodon-tl.el
@@ -333,6 +333,14 @@ types of mastodon links and not just shr.el-generated 
ones.")
   "The keymap to be set for the author byline.
 It is active where point is placed by `mastodon-tl-goto-next-item.'")
 
+(defvar mastodon-image-mode-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map image-mode-map)
+    (define-key map (kbd ">") #'mastodon-tl-next-full-image)
+    (define-key map (kbd ".") #'mastodon-tl-next-full-image)
+    (define-key map (kbd "<right>") #'mastodon-tl-next-full-image)
+    map))
+
 
 ;;; MACROS
 
@@ -750,8 +758,10 @@ The result is added as an attachments property to 
author-byline."
   (let ((media (mastodon-tl--field 'media_attachments toot)))
     (mapcar (lambda (attachment)
               (let-alist attachment
-                (list :url (or .remote_url .url) ; fallback for notifications
-                      :type .type)))
+                (list :id .id
+                      :type .type
+                      ;; fallback for notifications:
+                      :url (or .remote_url .url))))
             media)))
 
 (defun mastodon-tl--byline-booster (toot)
@@ -1405,18 +1415,80 @@ SENSITIVE is a flag from the item's JSON data."
                              help-echo
                            (concat help-echo "\nC-RET: play " type " with 
mpv"))))
 
-(defun mastodon-tl-view-full-image ()
+;;; FULL IMAGE VIEW
+
+(define-derived-mode mastodon-image-mode image-mode
+  "mastodon-image"
+  :group 'mastodon)
+
+;; patch `shr-browse-image' to accept url arg:
+(defun mastodon-tl-shr-browse-image (&optional image-url copy-url)
+  "Browse the image under point.
+If COPY-URL (the prefix if called interactively) is non-nil, copy
+the URL of the image to the kill buffer instead."
+  (interactive "sP")
+  (let ((url (or image-url (get-text-property (point) 'image-url))))
+    (cond
+     ((not url)
+      (message "No image under point"))
+     (copy-url
+      (with-temp-buffer
+        (insert url)
+        (copy-region-as-kill (point-min) (point-max))
+        (message "Copied %s" url)))
+     (t
+      (message "Browsing %s..." url)
+      (browse-url url)))))
+
+(defun mastodon-tl--view-image-url (url attachments)
+  "View image URL. Set ATTACHMENTS metadata in image buffer."
+  (if (not url)
+      (user-error "No url found")
+    (if (not mastodon-tl--load-full-sized-images-in-emacs)
+        (mastodon-tl-shr-browse-image url)
+      (mastodon-media--image-or-cached
+       url #'mastodon-media--process-full-sized-image-response
+       `(nil ,url ,attachments ,(buffer-name))))))
+
+(defun mastodon-tl-view-full-image-at-point ()
   "Browse full-sized version of image at point in a new window."
   (interactive)
   (if (not (eq (mastodon-tl--property 'mastodon-tab-stop) 'image))
       (user-error "No image at point?")
-    (let* ((url (mastodon-tl--property 'image-url)))
-      (if (not mastodon-tl--load-full-sized-images-in-emacs)
-          (shr-browse-image)
-        (mastodon-media--image-or-cached
-         url
-         #'mastodon-media--process-full-sized-image-response
-         `(nil ,url))))))
+    (let* ((url (mastodon-tl--property 'image-url))
+           (attachments (mastodon-tl--property 'attachments)))
+      (mastodon-tl--view-image-url url attachments))))
+
+(defun mastodon-tl-view-first-full-image ()
+  "From item byline, fetch load its first full image."
+  (interactive)
+  (let* ((attachments (mastodon-tl--property 'attachments))
+         (url (plist-get (car attachments) :url)))
+    (mastodon-tl--view-image-url url attachments)))
+
+(defun mastodon-tl--get-next-image-url ()
+  "Return the url for the next image to load.
+Cycles through values in `mastodon-media--attachments'."
+  (cl-loop for attachment in (cdr mastodon-media--attachments)
+           for url = (car mastodon-media--attachments)
+           ;; match url against our plists:
+           for current = (cl-member-if
+                          (lambda (attachment)
+                            (equal url (plist-get attachment :url)))
+                          (cdr mastodon-media--attachments))
+           ;; fetch from next item in current or use first item if current
+           ;; has only 1 item:
+           return (plist-get (if (= 1 (length current))
+                                 (cadr mastodon-media--attachments)
+                               (cadr current))
+                             :url)))
+
+(defun mastodon-tl-next-full-image ()
+  "From full image view buffer, load the toot's next image."
+  (interactive)
+  (let* ((next-url (mastodon-tl--get-next-image-url)))
+    (mastodon-tl--view-image-url next-url
+                                 (cdr mastodon-media--attachments))))
 
 (defun mastodon-tl-toggle-sensitive-image ()
   "Toggle dislay of sensitive image at point."

Reply via email to