mirror of
https://github.com/unclebob/more-speech.git
synced 2024-09-30 10:30:56 +00:00
Added string encoders to bech32 and can receive zap reciepts.
This commit is contained in:
parent
00857e8398
commit
f538ab26c0
@ -1,7 +1,7 @@
|
|||||||
(ns more-speech.bech32-spec
|
(ns more-speech.bech32-spec
|
||||||
(:require [speclj.core :refer :all]
|
(:require [more-speech.bech32 :refer :all]
|
||||||
[more-speech.bech32 :refer :all]
|
[more-speech.nostr.util :as util]
|
||||||
[more-speech.nostr.util :as util]))
|
[speclj.core :refer :all]))
|
||||||
|
|
||||||
(describe "bech32"
|
(describe "bech32"
|
||||||
(context "charset translations"
|
(context "charset translations"
|
||||||
@ -87,4 +87,33 @@
|
|||||||
(should= pubkey (address->number "npub19mun7qwdyjf7qs3456u8kyxncjn5u2n7klpu4utgy68k4aenzj6synjnft")))
|
(should= pubkey (address->number "npub19mun7qwdyjf7qs3456u8kyxncjn5u2n7klpu4utgy68k4aenzj6synjnft")))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(context "decoding into strings"
|
||||||
|
(it "decodes into a string"
|
||||||
|
(let [lnurl (encode-str "lnurl" "this is the string")]
|
||||||
|
(should= "this is the string" (address->str lnurl))))
|
||||||
|
|
||||||
|
(it "decodes a long string"
|
||||||
|
(let [long-string "https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df"
|
||||||
|
lnurl (encode-str "lnurl" long-string)]
|
||||||
|
(should= long-string (address->str lnurl))))
|
||||||
|
|
||||||
|
(it "encodes and decodes a one byte string"
|
||||||
|
(let [known-string "t"
|
||||||
|
known-lnurl "lnurl1ws4pqzkn"]
|
||||||
|
(should= known-lnurl (encode-str "lnurl" known-string))
|
||||||
|
(should= known-string (address->str known-lnurl))))
|
||||||
|
|
||||||
|
(it "encodes and decodes a known short string"
|
||||||
|
(let [known-string "this is the string"
|
||||||
|
known-lnurl "lnurl1w35xjueqd9ejqargv5s8xarjd9hxw9sar9p"]
|
||||||
|
(should= known-lnurl (encode-str "lnurl" known-string))
|
||||||
|
(should= known-string (address->str known-lnurl))))
|
||||||
|
|
||||||
|
(it "encodes and decodes a known long string"
|
||||||
|
(let [known-string "https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df"
|
||||||
|
known-lnurl "lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns"]
|
||||||
|
(should= known-string (address->str known-lnurl))
|
||||||
|
(should= known-lnurl (encode-str "lnurl" known-string))))
|
||||||
|
)
|
||||||
)
|
)
|
@ -7,7 +7,7 @@
|
|||||||
[more-speech.nostr.elliptic-signature :refer :all]
|
[more-speech.nostr.elliptic-signature :refer :all]
|
||||||
[more-speech.nostr.event-composers :refer :all]
|
[more-speech.nostr.event-composers :refer :all]
|
||||||
[more-speech.nostr.event-composers :refer :all]
|
[more-speech.nostr.event-composers :refer :all]
|
||||||
[more-speech.nostr.event-handlers :refer :all]
|
[more-speech.nostr.event-dispatcher :refer :all]
|
||||||
[more-speech.nostr.events :refer :all]
|
[more-speech.nostr.events :refer :all]
|
||||||
[more-speech.nostr.util :as util]
|
[more-speech.nostr.util :as util]
|
||||||
[more-speech.nostr.util :refer :all]
|
[more-speech.nostr.util :refer :all]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(ns more-speech.nostr.event-handlers-spec
|
(ns more-speech.nostr.event-handlers-spec
|
||||||
(:require [speclj.core :refer :all]
|
(:require [speclj.core :refer :all]
|
||||||
[more-speech.nostr.event-handlers :as handlers]
|
[more-speech.nostr.event-dispatcher :as handlers]
|
||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
[more-speech.db.in-memory :as in-memory]
|
[more-speech.db.in-memory :as in-memory]
|
||||||
[more-speech.config :as config]
|
[more-speech.config :as config]
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
[more-speech.db.in-memory :as in-memory]
|
[more-speech.db.in-memory :as in-memory]
|
||||||
[more-speech.nostr.events :refer :all]
|
[more-speech.nostr.events :refer :all]
|
||||||
[more-speech.nostr.event-handlers :refer :all]
|
[more-speech.nostr.event-dispatcher :refer :all]
|
||||||
[more-speech.nostr.elliptic-signature :refer :all]
|
[more-speech.nostr.elliptic-signature :refer :all]
|
||||||
[more-speech.nostr.util :refer :all]
|
[more-speech.nostr.util :refer :all]
|
||||||
[more-speech.mem :refer :all]
|
[more-speech.mem :refer :all]
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
(ns more-speech.nostr.zaps-spec
|
(ns more-speech.nostr.zaps-spec
|
||||||
(:require
|
(:require
|
||||||
|
[more-speech.bech32 :as bech32]
|
||||||
[more-speech.config :as config]
|
[more-speech.config :as config]
|
||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
[more-speech.db.in-memory :as in-memory]
|
[more-speech.db.in-memory :as in-memory]
|
||||||
@ -102,6 +103,7 @@
|
|||||||
amount 100
|
amount 100
|
||||||
comment "comment"
|
comment "comment"
|
||||||
lnurl "lnurl"
|
lnurl "lnurl"
|
||||||
|
b32-lnurl (bech32/encode-str "lnurl" lnurl)
|
||||||
my-privkey 0xb0b
|
my-privkey 0xb0b
|
||||||
my-pubkey (util/bytes->num (es/get-pub-key (util/num->bytes 32 my-privkey)))
|
my-pubkey (util/bytes->num (es/get-pub-key (util/num->bytes 32 my-privkey)))
|
||||||
_ (set-mem :pubkey my-pubkey)
|
_ (set-mem :pubkey my-pubkey)
|
||||||
@ -120,7 +122,7 @@
|
|||||||
(should= (util/get-now) created_at)
|
(should= (util/get-now) created_at)
|
||||||
(should (contains? tags ["relays" "relay-r1" "relay-r2"]))
|
(should (contains? tags ["relays" "relay-r1" "relay-r2"]))
|
||||||
(should (contains? tags ["amount" "100"]))
|
(should (contains? tags ["amount" "100"]))
|
||||||
(should (contains? tags ["lnurl" "lnurl1qqqxcmn4wfkqzejtan"]))
|
(should (contains? tags ["lnurl" b32-lnurl]))
|
||||||
(should (contains? tags ["p" (util/hexify recipient-id)]))
|
(should (contains? tags ["p" (util/hexify recipient-id)]))
|
||||||
(should (contains? tags ["e" (util/hexify event-id)])))))
|
(should (contains? tags ["e" (util/hexify event-id)])))))
|
||||||
|
|
||||||
|
@ -46,8 +46,14 @@
|
|||||||
:else
|
:else
|
||||||
cksum))
|
cksum))
|
||||||
|
|
||||||
(defn parse-address [address]
|
(defn parse-address
|
||||||
(let [address (validate-address-length (.toLowerCase address))
|
([address]
|
||||||
|
(parse-address address #{}))
|
||||||
|
|
||||||
|
([address options]
|
||||||
|
(let [address (.toLowerCase address)
|
||||||
|
_ (when-not (contains? options :no-length-restriction)
|
||||||
|
(validate-address-length address))
|
||||||
hrp-end (find-separator-char address)
|
hrp-end (find-separator-char address)
|
||||||
hrp (validate-hrp (subs address 0 hrp-end))
|
hrp (validate-hrp (subs address 0 hrp-end))
|
||||||
data-and-cksum (subs address (inc hrp-end))
|
data-and-cksum (subs address (inc hrp-end))
|
||||||
@ -55,7 +61,7 @@
|
|||||||
cksum (validate-cksum cksum)
|
cksum (validate-cksum cksum)
|
||||||
data (apply str (drop-last 6 data-and-cksum))
|
data (apply str (drop-last 6 data-and-cksum))
|
||||||
data (validate-data data)]
|
data (validate-data data)]
|
||||||
[hrp data cksum]))
|
[hrp data cksum])))
|
||||||
|
|
||||||
(def generator [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3])
|
(def generator [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3])
|
||||||
|
|
||||||
@ -120,8 +126,64 @@
|
|||||||
(recur (quot id 32) (conj data (int (rem id 32))) (dec chars))))
|
(recur (quot id 32) (conj data (int (rem id 32))) (dec chars))))
|
||||||
cksum-data (create-checksum hrp data)
|
cksum-data (create-checksum hrp data)
|
||||||
]
|
]
|
||||||
(str hrp "1" (apply str (map to-char (concat data cksum-data))))
|
(str hrp "1" (apply str (map to-char (concat data cksum-data))))))
|
||||||
))
|
|
||||||
|
; The bech32 coding converts streams of bytes into streams of 5-bit integers.
|
||||||
|
; The numbers 5 and 8 are mutually prime so there will usually be a remainder.
|
||||||
|
; That remainder is the number of zero bits on the end of the encoded stream.
|
||||||
|
; Thus, a single byte abcdefgh gets encoded as two five bit integer
|
||||||
|
; as abcde fgh00.
|
||||||
|
|
||||||
|
(defn- align-num [n the-string]
|
||||||
|
(let [n-bits (* 8 (count the-string))
|
||||||
|
r (rem n-bits 5)]
|
||||||
|
(if (zero? r)
|
||||||
|
n
|
||||||
|
(let [shift-n (- 5 r)
|
||||||
|
shift-factor (reduce * (repeat shift-n 2))]
|
||||||
|
(* n shift-factor)))))
|
||||||
|
|
||||||
|
(defn- str->num [the-string]
|
||||||
|
(loop [s the-string
|
||||||
|
n 0N]
|
||||||
|
(if (empty? s)
|
||||||
|
(align-num n the-string)
|
||||||
|
(recur (rest s) (+ (* 256 n) (int (first s)))))))
|
||||||
|
|
||||||
|
(defn- num->32bit-data [n]
|
||||||
|
(loop [n n
|
||||||
|
data (list)]
|
||||||
|
(if (zero? n)
|
||||||
|
data
|
||||||
|
(recur (quot n 32) (conj data (int (rem n 32)))))))
|
||||||
|
|
||||||
|
(defn encode-str
|
||||||
|
"create a bech32 representation of a string"
|
||||||
|
[hrp s]
|
||||||
|
(let [big-number (str->num s)
|
||||||
|
data (num->32bit-data big-number)
|
||||||
|
cksum-data (create-checksum hrp data)]
|
||||||
|
(str hrp "1" (apply str (map to-char (concat data cksum-data))))))
|
||||||
|
|
||||||
|
(defn address->str [address]
|
||||||
|
(let [[hrp data cksum] (parse-address address #{:no-length-restriction})
|
||||||
|
valid? (verify-checksum? [hrp data cksum])]
|
||||||
|
(if valid?
|
||||||
|
(let [values (map to-n data)
|
||||||
|
accumulator (reduce (fn [n value]
|
||||||
|
(+ value (* n 32)))
|
||||||
|
0N values)
|
||||||
|
n-bits (* 5 (count data))
|
||||||
|
shift-n (rem n-bits 8)
|
||||||
|
aligned-accumulator (quot accumulator (reduce * (repeat shift-n 2)))]
|
||||||
|
(loop [n aligned-accumulator
|
||||||
|
chars (list)]
|
||||||
|
(if (zero? n)
|
||||||
|
(apply str chars)
|
||||||
|
(recur (quot n 256) (conj chars (char (rem n 256)))))))
|
||||||
|
(throw (Exception. "bech32/address->str: invalid checksum")))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
(defn address->number [address]
|
(defn address->number [address]
|
||||||
(let [[hrp data cksum] (parse-address address)
|
(let [[hrp data cksum] (parse-address address)
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
(log-pr 1 'main arg 'start)
|
(log-pr 1 'main arg 'start)
|
||||||
(when (= "test" arg)
|
(when (= "test" arg)
|
||||||
(config/test-run!))
|
(config/test-run!))
|
||||||
(when (re-matches #"hours:\d+" arg)
|
(when (and (some? arg) (re-matches #"hours:\d+" arg))
|
||||||
(let [hours (Integer/parseInt (subs arg 6))]
|
(let [hours (Integer/parseInt (subs arg 6))]
|
||||||
(set-mem :request-hours-ago hours))
|
(set-mem :request-hours-ago hours))
|
||||||
)
|
)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
[more-speech.db.xtdb :as xtdb]
|
[more-speech.db.xtdb :as xtdb]
|
||||||
[more-speech.logger.default :refer [log-pr]]
|
[more-speech.logger.default :refer [log-pr]]
|
||||||
[more-speech.mem :refer :all]
|
[more-speech.mem :refer :all]
|
||||||
[more-speech.nostr.event-handlers :as handlers]
|
[more-speech.nostr.event-dispatcher :as handlers]
|
||||||
[more-speech.nostr.relays :as relays]
|
[more-speech.nostr.relays :as relays]
|
||||||
[more-speech.nostr.util :as util]
|
[more-speech.nostr.util :as util]
|
||||||
[more-speech.ui.formatter-util :as fu]
|
[more-speech.ui.formatter-util :as fu]
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
[more-speech.nostr
|
[more-speech.nostr
|
||||||
[util :as util]
|
[util :as util]
|
||||||
[elliptic-signature :as ecc]
|
[elliptic-signature :as ecc]
|
||||||
[event-handlers :as handlers]]
|
[event-dispatcher :as handlers]]
|
||||||
[more-speech.data-storage :as data-storage]
|
[more-speech.data-storage :as data-storage]
|
||||||
[more-speech.user-configuration :as user-configuration]
|
[more-speech.user-configuration :as user-configuration]
|
||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(ns more-speech.nostr.event-handlers
|
(ns more-speech.nostr.event-dispatcher
|
||||||
(:require [clojure.data.json :as json]
|
(:require [clojure.data.json :as json]
|
||||||
[more-speech.config :as config :refer [get-db]]
|
[more-speech.config :as config :refer [get-db]]
|
||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
@ -8,9 +8,8 @@
|
|||||||
[more-speech.nostr.elliptic-signature :as ecc]
|
[more-speech.nostr.elliptic-signature :as ecc]
|
||||||
[more-speech.nostr.events :as events]
|
[more-speech.nostr.events :as events]
|
||||||
[more-speech.nostr.relays :as relays]
|
[more-speech.nostr.relays :as relays]
|
||||||
[more-speech.nostr.util :refer :all]
|
[more-speech.nostr.zaps :as zaps]
|
||||||
[more-speech.nostr.util :refer [unhexify]]
|
[more-speech.nostr.util :refer :all :as util])
|
||||||
[more-speech.nostr.util :as util])
|
|
||||||
(:import (ecdhJava SECP256K1)))
|
(:import (ecdhJava SECP256K1)))
|
||||||
|
|
||||||
(defprotocol event-handler
|
(defprotocol event-handler
|
||||||
@ -126,6 +125,7 @@
|
|||||||
3 (contact-list/process-contact-list db event)
|
3 (contact-list/process-contact-list db event)
|
||||||
4 (process-text-event db event url)
|
4 (process-text-event db event url)
|
||||||
7 (process-reaction db event)
|
7 (process-reaction db event)
|
||||||
|
9735 (zaps/process-zap-receipt event)
|
||||||
nil))))
|
nil))))
|
||||||
|
|
||||||
(defn decrypt-his-dm [event]
|
(defn decrypt-his-dm [event]
|
@ -4,7 +4,7 @@
|
|||||||
[more-speech.mem :refer :all]
|
[more-speech.mem :refer :all]
|
||||||
[more-speech.mem :refer :all]
|
[more-speech.mem :refer :all]
|
||||||
[more-speech.nostr.contact-list :as contact-list]
|
[more-speech.nostr.contact-list :as contact-list]
|
||||||
[more-speech.nostr.event-handlers :as handlers]
|
[more-speech.nostr.event-dispatcher :as handlers]
|
||||||
[more-speech.nostr.events :as events]
|
[more-speech.nostr.events :as events]
|
||||||
[more-speech.nostr.util :as util]
|
[more-speech.nostr.util :as util]
|
||||||
[more-speech.relay :as relay]
|
[more-speech.relay :as relay]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
(ns more-speech.nostr.util
|
(ns more-speech.nostr.util
|
||||||
(:import (java.security MessageDigest SecureRandom)))
|
(:import (java.awt Toolkit)
|
||||||
|
(java.awt.datatransfer StringSelection)
|
||||||
|
(java.security MessageDigest SecureRandom)))
|
||||||
|
|
||||||
(defn num->bytes
|
(defn num->bytes
|
||||||
"Returns the byte-array representation of n.
|
"Returns the byte-array representation of n.
|
||||||
@ -87,3 +89,10 @@
|
|||||||
|
|
||||||
(defn get-now []
|
(defn get-now []
|
||||||
(quot (get-now-ms) 1000))
|
(quot (get-now-ms) 1000))
|
||||||
|
|
||||||
|
(defn get-clipboard []
|
||||||
|
(.getSystemClipboard (Toolkit/getDefaultToolkit)))
|
||||||
|
|
||||||
|
(defn copy-to-clipboard [text]
|
||||||
|
(let [selection (StringSelection. text)]
|
||||||
|
(.setContents (get-clipboard) selection selection)))
|
||||||
|
@ -7,10 +7,12 @@
|
|||||||
[more-speech.config :refer [get-db]]
|
[more-speech.config :refer [get-db]]
|
||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
[more-speech.logger.default :refer [log-pr]]
|
[more-speech.logger.default :refer [log-pr]]
|
||||||
|
[more-speech.mem :refer :all]
|
||||||
[more-speech.nostr.event-composers :as composers]
|
[more-speech.nostr.event-composers :as composers]
|
||||||
[more-speech.nostr.events :as events]
|
[more-speech.nostr.events :as events]
|
||||||
[more-speech.nostr.relays :as relays]
|
[more-speech.nostr.relays :as relays]
|
||||||
[more-speech.nostr.util :as util])
|
[more-speech.nostr.util :as util]
|
||||||
|
[more-speech.ui.formatter-util :as formatter-util])
|
||||||
(:use (seesaw [core]))
|
(:use (seesaw [core]))
|
||||||
(:import (java.net URLEncoder)))
|
(:import (java.net URLEncoder)))
|
||||||
|
|
||||||
@ -52,7 +54,8 @@
|
|||||||
(get-zap-address-from-profile event))))
|
(get-zap-address-from-profile event))))
|
||||||
|
|
||||||
(defn parse-lud16 [lud16]
|
(defn parse-lud16 [lud16]
|
||||||
(let [match (re-matches config/lud16-pattern lud16)]
|
(let [lud16 (.toLowerCase lud16)
|
||||||
|
match (re-matches config/lud16-pattern lud16)]
|
||||||
(if (some? match)
|
(if (some? match)
|
||||||
[(nth match 1) (nth match 2)]
|
[(nth match 1) (nth match 2)]
|
||||||
(throw (Exception. (str "bad lud16 format " lud16)))))
|
(throw (Exception. (str "bad lud16 format " lud16)))))
|
||||||
@ -80,7 +83,7 @@
|
|||||||
:content comment
|
:content comment
|
||||||
:tags [(concat ["relays"] (relays/relays-for-reading))
|
:tags [(concat ["relays"] (relays/relays-for-reading))
|
||||||
["amount" (str amount)]
|
["amount" (str amount)]
|
||||||
["lnurl" (bech32/encode "lnurl" (util/bytes->num (.getBytes lnurl)))]
|
["lnurl" (bech32/encode-str "lnurl" lnurl)]
|
||||||
["p" (util/hexify recipient)]
|
["p" (util/hexify recipient)]
|
||||||
["e" (util/hexify (:id event))]]}
|
["e" (util/hexify (:id event))]]}
|
||||||
[_ request] (composers/body->event body)]
|
[_ request] (composers/body->event body)]
|
||||||
@ -114,10 +117,23 @@
|
|||||||
_ (when (and (some? json-status) (= "ERROR" json-status))
|
_ (when (and (some? json-status) (= "ERROR" json-status))
|
||||||
(throw (Exception. (str "Invoice request error: " (get invoice-json "reason")))))
|
(throw (Exception. (str "Invoice request error: " (get invoice-json "reason")))))
|
||||||
invoice (get invoice-json "pr")]
|
invoice (get invoice-json "pr")]
|
||||||
(prn 'zap-author invoice)
|
(update-mem :pending-zaps assoc invoice {:id (:id event)
|
||||||
(prn 'zap-author 'metadata metadata))
|
:amount amount})
|
||||||
|
(util/copy-to-clipboard invoice)
|
||||||
|
(alert (str "Invoice is copied to clipboard.\n"
|
||||||
|
"Paste it into your wallet and Zap!\n\n"
|
||||||
|
(formatter-util/abbreviate invoice 20)
|
||||||
|
(subs invoice (- (count invoice) 5)))))
|
||||||
)
|
)
|
||||||
(catch Exception e
|
(catch Exception e
|
||||||
(log-pr 1 'zap-author (.getMessage e))
|
(log-pr 1 'zap-author (.getMessage e))
|
||||||
(alert (str "Cannot zap. " (.getMessage e)))))
|
(alert (str "Cannot zap. " (.getMessage e))))))
|
||||||
)
|
|
||||||
|
(defn process-zap-receipt [event]
|
||||||
|
(prn 'zap-receipt event)
|
||||||
|
(let [[[receipt-invoice]] (events/get-tag event :bolt11)
|
||||||
|
transaction (get-mem [:pending-zaps receipt-invoice])]
|
||||||
|
(when (some? transaction)
|
||||||
|
(let [{:keys [id amount]} transaction]
|
||||||
|
(prn 'got-zap-receipt (util/hexify id) (/ amount 1000) 'sats)
|
||||||
|
(update-mem :pending-zaps dissoc receipt-invoice)))))
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
[more-speech.logger.default :refer [log-pr]]
|
[more-speech.logger.default :refer [log-pr]]
|
||||||
[more-speech.mem :refer :all]
|
[more-speech.mem :refer :all]
|
||||||
[more-speech.nostr.event-handlers :as handlers]
|
[more-speech.nostr.event-dispatcher :as handlers]
|
||||||
[more-speech.nostr.util :as util]
|
[more-speech.nostr.util :as util]
|
||||||
[more-speech.ui.formatter-util :as formatter-util]
|
[more-speech.ui.formatter-util :as formatter-util]
|
||||||
[more-speech.ui.swing.article-panel :as article-panel]
|
[more-speech.ui.swing.article-panel :as article-panel]
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
[more-speech.config :as config]
|
[more-speech.config :as config]
|
||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
[more-speech.mem :refer :all]
|
[more-speech.mem :refer :all]
|
||||||
[more-speech.nostr.event-handlers :as event-handlers]
|
[more-speech.nostr.event-dispatcher :as event-handlers]
|
||||||
|
[more-speech.nostr.util :as util]
|
||||||
[more-speech.ui.swing.article-tree-util :as at-util])
|
[more-speech.ui.swing.article-tree-util :as at-util])
|
||||||
(:use (seesaw [core]))
|
(:use (seesaw [core]))
|
||||||
(:import (java.awt.datatransfer StringSelection)))
|
(:import (java.awt.datatransfer StringSelection)))
|
||||||
@ -96,12 +97,8 @@
|
|||||||
(let [send-chan (get-mem :send-chan)]
|
(let [send-chan (get-mem :send-chan)]
|
||||||
(future (async/>!! send-chan [:relaunch]))))
|
(future (async/>!! send-chan [:relaunch]))))
|
||||||
|
|
||||||
(defn- get-clipboard []
|
|
||||||
(.getSystemClipboard (java.awt.Toolkit/getDefaultToolkit)))
|
|
||||||
|
|
||||||
(defn copy-to-clipboard [text _e]
|
(defn copy-to-clipboard [text _e]
|
||||||
(let [selection (StringSelection. text)]
|
(util/copy-to-clipboard text))
|
||||||
(.setContents (get-clipboard) selection selection)))
|
|
||||||
|
|
||||||
(defn load-event [id]
|
(defn load-event [id]
|
||||||
(let [event (gateway/get-event (config/get-db) id)
|
(let [event (gateway/get-event (config/get-db) id)
|
||||||
|
Loading…
Reference in New Issue
Block a user