diff options
Diffstat (limited to 'lisp/mastodon-transient.el')
| -rw-r--r-- | lisp/mastodon-transient.el | 213 | 
1 files changed, 205 insertions, 8 deletions
| diff --git a/lisp/mastodon-transient.el b/lisp/mastodon-transient.el index 526dfa4..bbfbfc9 100644 --- a/lisp/mastodon-transient.el +++ b/lisp/mastodon-transient.el @@ -25,9 +25,43 @@  ;;; Code:  (require 'tp) +(require 'transient) + +(defvar mastodon-active-user) +(defvar mastodon-toot-visibility-settings-list) +(defvar mastodon-iso-639-regional) +(defvar mastodon-toot-poll) + +(autoload 'mastodon-toot-visibility-settings-list "mastodon-toot") +(autoload 'mastodon-http--get-json "mastodon-http") +(autoload 'mastodon-http--api "mastodon-http") +(autoload 'mastodon-http--triage "mastodon-http") +(autoload 'mastodon-http--patch "mastodon-http") +(autoload 'mastodon-profile--update-user-profile-note "mastodon-profile") +(autoload 'mastodon-toot--fetch-max-poll-options "mastodon-toot") +(autoload 'mastodon-toot--fetch-max-poll-option-chars "mastodon-toot") +(autoload 'mastodon-instance-data "mastodon") +(autoload 'mastodon-toot--update-status-fields "mastodon-toot") +(autoload 'mastodon-toot--read-poll-expiry "mastodon-toot") +(autoload 'mastodon-toot--poll-expiry-options-alist "mastodon-toot") +(autoload 'mastodon-toot--clear-poll "mastodon-toot")  ;;; UTILS +(transient-define-suffix mastodon-transient--prefix-inspect () +  "Inspect a transient prefix's arguments and scope." +  (interactive) +  :transient 'transient--do-return +  (let ((args (transient-args (oref transient-current-prefix command))) +        (scope (oref transient-current-prefix scope))) +    (message "prefix's scope: %s \ntransient-args: %s\n last: %s" +             scope args +             (length +              (cl-member-if +               (lambda (x) +                 (equal (car x) 'one)) +               args))))) +  ;; some JSON fields that are returned under the "source" field need to be  ;; sent back in the format source[key], while some others are sent kust as  ;; key: @@ -163,13 +197,12 @@ the format fields.X.keyname."  (defun mastodon-transient-fetch-fields ()    "Fetch profile fields (metadata)."    (tp-return-data #'mastodon-transient-get-creds nil 'fields) -  (setq tp-server-settings -        (mastodon-transient--fields-alist tp-server-settings))) +  (setq tp-transient-settings +        (mastodon-transient--fields-alist tp-transient-settings)))  (transient-define-prefix mastodon-profile-fields ()    "A transient for setting profile fields." -  :value -  (lambda () (mastodon-transient-fetch-fields)) +  :value (lambda () (mastodon-transient-fetch-fields))    [:description     "Fields"     ["Name" @@ -190,6 +223,122 @@ the format fields.X.keyname."        (user-error "User not set")      (transient-setup 'mastodon-profile-fields))) +(defun mastodon-transient-max-poll-opts () +  "Return max poll options of user's instance." +  (let ((instance (mastodon-instance-data))) +    (mastodon-toot--fetch-max-poll-options instance))) + +(defun mastodon-transient-max-poll-opt-chars () +  "Return max poll option characters of user's instance." +  (let ((instance (mastodon-instance-data))) +    (mastodon-toot--fetch-max-poll-option-chars instance))) + +(transient-define-suffix mastodon-transient--choice-add () +  "Add another poll choice if possible. +Do not add more than 9 choices. +Do not add more than the server's maximum setting." +  (interactive) +  :transient 'transient--do-stay +  (let* ((args (transient-args (oref transient-current-prefix command))) +         (choice-count (length +                        (cl-member-if +                         (lambda (x) +                           (equal (car x) 'one)) +                         args))) +         (inc (1+ choice-count)) +         (next (number-to-string inc)) +         (next-symbol (pcase inc +                        (5 'five) +                        (6 'six) +                        (7 'seven) +                        (8 'eight) +                        (9 'nine)))) +    (if (or (>= choice-count (mastodon-transient-max-poll-opts)) +            (= choice-count 9)) +        ;; FIXME when we hit '10', we get a binding clash with '1'. :/ +        (message "Max choices reached") +      (transient-append-suffix +        'mastodon-create-poll +        '(2 -1) +        `(,next "" ,next +                :class mastodon-transient-poll-choice +                :alist-key ,next-symbol +                :transient t)))) +  (transient-setup 'mastodon-create-poll)) + +(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) +  ["Create poll" +   (:info (lambda () +            (format "Max options: %s" +                    (mastodon-transient-max-poll-opts)))) +   (:info (lambda () +            (format "Max option length: %s" +                    (mastodon-transient-max-poll-opt-chars))))] +  ["Options" +   ("m" "Multiple choice?" "multi" :alist-key multi +    :class mastodon-transient-poll-bool) +   ("h" "Hide vote count till expiry?" "hide" :alist-key hide +    :class mastodon-transient-poll-bool) +   ("e" "Expiry" "expiry" :alist-key expiry +    :class mastodon-transient-expiry)] +  ["Choices" +   ("1" "" "1" :alist-key one :class mastodon-transient-poll-choice) +   ("2" "" "2" :alist-key two :class mastodon-transient-poll-choice) +   ("3" "" "3" :alist-key three :class mastodon-transient-poll-choice) +   ("4" "" "4" :alist-key four :class mastodon-transient-poll-choice)] +  ;; TODO: display the max number of options or add options cmd +  ["Update" +   ("C-c C-s" "Add another poll choice" mastodon-transient--choice-add +    :if (lambda () (< 4 (mastodon-transient-max-poll-opts)))) +   ("C-c C-c" "Save and done" mastodon-create-poll-done) +   ("C-x C-k" :info "Revert all") +   ("C-c C-k" "Delete all" mastodon-clear-poll)] +  (interactive) +  (if (not mastodon-active-user) +      (user-error "User not set") +    (transient-setup 'mastodon-create-poll))) + +(transient-define-suffix mastodon-clear-poll () +  "Clear current poll data." +  :transient 'transient--do-stay +  (interactive) +  (mastodon-toot--clear-poll) +  (transient-reset)) + +(transient-define-suffix mastodon-create-poll-done (args) +  "Update current user profile fields." +  :transient 'transient--do-exit +  (interactive (list (transient-args 'mastodon-create-poll))) +  (let* ((options (cl-member-if (lambda (x) +                                  (eq (car x) 'one)) +                                args)) +         (opt-vals (cl-loop for x in options +                            collect (cdr x))) +         (lengths (mapcar #'length opt-vals)) +         (vals (cl-remove 'nil +                          (cl-loop for x in args +                                   collect (cdr x)))) +         (opts-count (length (cl-remove 'nil opt-vals)))) +    ;; this way of checking gets annoying if we want to just cancel out of +    ;; the poll (but to actually cancel user should C-g, not C-c C-c): +    (if (or (and (< 50 (apply #'max lengths)) +                 (not (y-or-n-p "Options longer than server max. Proceed? "))) +            (and (not (alist-get 'expiry args)) +                 (not (y-or-n-p "No expiry. Proceed? "))) +            (and (not (< 1 opts-count)) +                 (not (y-or-n-p "Need more than one option. Proceed? "))) +            (and (> opts-count (mastodon-transient-max-poll-opts)) +                 (not (y-or-n-p "More options than server max. Proceed? ")))) +        (mastodon-create-poll) +      ;; if we are called with no poll data, do not set: +      (unless (not vals) +        (setq tp-transient-settings +              (tp-bools-to-strs args))) +      (mastodon-toot--update-status-fields)))) +  ;;; CLASSES  (defclass mastodon-transient-field (tp-option-str) @@ -199,8 +348,8 @@ We always read.")  (cl-defmethod transient-init-value ((obj mastodon-transient-field))    "Initialize value of OBJ." -  (let* ((prefix-val (oref transient--prefix value)) -         (arg (oref obj alist-key))) +  (let* ((prefix-val (oref transient--prefix value))) +    ;; (arg (oref obj alist-key)))      (oset obj value            (tp-get-server-val obj prefix-val)))) @@ -219,12 +368,60 @@ only one level of nesting is supported."    "T if value of OBJ is changed from the server value.  CONS is a cons of the form \"(fields.1.name . val)\"."    (let* ((key-split (split-string -                     (symbol-to-string (car cons)) "\\.")) +                     (symbol-name (car cons)) "\\."))           (num (1- (string-to-number (nth 1 key-split))))           (server-key (symbol-name (car cons))) -         (server-elt (nth num tp-server-settings))) +         (server-elt (nth num tp-transient-settings)))      (not (equal (cdr cons)                  (alist-get server-key server-elt nil nil #'string=))))) +(defclass mastodon-transient-opt (tp-option tp-option-var) +  (())) + +(defclass mastodon-transient-poll-bool (tp-bool tp-option-var) +  ()) + +(defclass mastodon-transient-poll-choice (tp-option-str tp-option-var) +  ()) + +(cl-defmethod transient-infix-read ((obj mastodon-transient-poll-choice)) +  "Reader function for OBJ, a poll expiry." +  (let* ((value (transient-infix-value obj)) +         (prompt (transient-prompt obj)) +         (str (read-string prompt (cdr value))) +         (max (mastodon-transient-max-poll-opt-chars))) +    (if (not (> (length str) max)) +        str +      (if (not +           (y-or-n-p +            (format "Poll option too long for server (%s/%s chars), retry?" +                    (length str) max))) +          str +        (oset obj value str) +        (transient-infix-read obj))))) + +(defclass mastodon-transient-expiry (tp-option tp-option-var) +  ()) + +(cl-defmethod transient-infix-read ((_obj mastodon-transient-expiry)) +  "Reader function for OBJ, a poll expiry." +  (cdr (mastodon-toot--read-poll-expiry))) + +(cl-defmethod transient-format-value ((obj mastodon-transient-expiry)) +  "Format function for OBJ, a poll expiry." +  (let* ((cons (transient-infix-value obj)) +         (value (when cons (cdr cons)))) +    (if (not value) +        "" +      (let ((readable +             (or (car +                  (rassoc value +                          (mastodon-toot--poll-expiry-options-alist))) +                 (concat value " secs")))) ;; editing a poll wont match expiry list +        (propertize readable +                    'face (if (tp-arg-changed-p obj cons) +                              'transient-value +                            'transient-inactive-value)))))) +  (provide 'mastodon-transient)  ;;; mastodon-transient.el ends here | 
