Yu-Gi-Oh! Deck Building and Card Inventory Management web interface written in Common Lisp, utilizing HTMX.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

101 řádky
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))