Yu-Gi-Oh! Deck Building and Card Inventory Management web interface written in Common Lisp, utilizing HTMX.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

101 linhas
3.6KB

  1. #|
  2. QR Code Model
  3. Constantly fixing their user input was getting janky. DEFCLASS to the rescue!
  4. TODO This is still pretty clumbsy. I'm generating HTML in here??
  5. Originally I was using INITIALIZE-INSTANCE but that would clobber the
  6. object with the DEFAULT-INITARGS. Now we're overriding
  7. REINITIALIZE-INSTANCE, which seems to work exactly as you'd expect.
  8. |#
  9. (in-package #:cl-deck-builder2.models.qr-code)
  10. ;; XXX
  11. (defparameter *qr-public-file* #P"~/public/qr.png")
  12. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  13. (defclass qr-settings ()
  14. ((string :accessor qr-string
  15. :initarg :string)
  16. (min-version :accessor qr-min-version
  17. :initarg :min-version)
  18. (ec-level :accessor qr-ec-level
  19. :initarg :ec-level)
  20. (encoding-mode :accessor qr-encoding-mode
  21. :initarg :encoding-mode)
  22. (mask-number :accessor qr-mask-number
  23. :initarg :mask-number)
  24. (output-path :accessor qr-output-path
  25. :initarg :output))
  26. (:default-initargs
  27. :ec-level :L
  28. :encoding-mode :8-BIT-BYTE
  29. :mask-number -1
  30. :min-version 1
  31. :output #P"/tmp/qr.png"
  32. :string "Hello World"))
  33. (defmethod reinitialize-instance :after ((qr-settings qr-settings) &rest initargs &key content &allow-other-keys)
  34. (declare (ignore initargs))
  35. (when content
  36. (reinitialize-with-content qr-settings content)))
  37. ;; Overwrite existing slots even if they're SLOT-BOUNDP with SLOT-VALUE
  38. (defmethod reinitialize-with-content ((qr-settings qr-settings) content)
  39. ;; TODO ALIST-PARAMS-to-class? The idea is there...
  40. (alexandria:if-let ((string (query-param "string" content)))
  41. (setf (qr-string qr-settings) string))
  42. (alexandria:if-let ((min-version (query-param "min-version" content)))
  43. (setf (qr-min-version qr-settings) (parse-integer min-version)))
  44. (alexandria:if-let ((ec-level (query-param "ec-level" content)))
  45. (setf (qr-ec-level qr-settings) (alexandria:make-keyword ec-level)))
  46. (alexandria:if-let ((encoding-mode (query-param "encoding-mode" content)))
  47. (setf (qr-encoding-mode qr-settings) (alexandria:make-keyword encoding-mode)))
  48. (alexandria:if-let ((mask-number (query-param "mask-number" content)))
  49. (setf (qr-mask-number qr-settings) (parse-integer mask-number)))
  50. qr-settings)
  51. ;; TODO %from-plist
  52. ;; TODO %from-alist?
  53. (defmethod qr-to-plist ((qr-settings qr-settings) &optional html)
  54. (let ((params
  55. (list :ec-level (qr-ec-level qr-settings)
  56. :encoding-mode (qr-encoding-mode qr-settings)
  57. :mask-number (qr-mask-number qr-settings)
  58. :min-version (qr-min-version qr-settings))))
  59. (when html
  60. (setf (getf params :string) (qr-string qr-settings)
  61. (getf params :ec-level) (princ-to-string (getf params :ec-level))
  62. (getf params :encoding-mode) (princ-to-string (getf params :encoding-mode))))
  63. params))
  64. (defmethod qr-generate ((qr qr-settings))
  65. (v:info :qr "QR-STRING: ~a" (qr-string qr))
  66. (v:info :qr "UIOP:DELETE-FILE-IF-EXISTS: ~a"
  67. (ignore-errors
  68. (mapcar #'uiop:delete-file-if-exists '(#P"/tmp/qr.png" #P"~/public/qr.png"))))
  69. (v:info :qr "LISPQR:ENCODE->IMAGE: ~a"
  70. (ignore-errors
  71. (apply #'lispqr:encode->image (qr-string qr) (qr-output-path qr)
  72. (qr-to-plist qr))))
  73. (v:info :qr "UIOP:COPY-FILE: ~a"
  74. (ignore-errors
  75. (uiop:copy-file (qr-output-path qr) *qr-public-file*)))
  76. (if (probe-file *qr-public-file*)
  77. (qr-format-html (get-universal-time))))
  78. (defun qr-format-html (when)
  79. (format nil "<img class=\"card image\" src=\"/public/qr.png?~d\" alt=\"QR Code\">" when))