nandi/frqpublic Fork 0
b4172e953d70d5164f0837f6a88b0b92448c32f6
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

A picture is bytes where there is no file, and the clipboard is one way in f4d18a5 · on b4172e953d70d5164f0837f6a88b0b92448c32f6 · nandi · yesterday
pictures.cljd · 57 lines · 2.4 KBGDScript3 Blame HistoryRaw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
(ns frq.pictures
  "Choosing a picture and sending it, named once for both Flutter targets.

  The fifth seam, and it exists because a browser has no file. dart:io picks
  one with the system chooser, copies it into the app's own storage and
  uploads it by path; a browser is handed BYTES  from the chooser, or from
  the clipboard  and there is no path to copy to. `File.copy` on the web
  throws `Unsupported operation: _Namespace`, which is dart:io's filesystem
  saying it is not there, and what the reader saw was `Could not read that
  picture: _Namespace`.

  So a picture here is a map, and either half of it may be missing: `:path`
  where there is a filesystem, `:bytes` where there is not, `:filename`
  always. `frq.upload.core` already builds the multipart body out of bytes, so
  only the transport and the chooser differ."
  (:refer-clojure :exclude [name]))

(defonce ^:private impl (atom {}))

(defn install! [m] (swap! impl merge m) nil)

(defn ^:async pick!
  "Ask the reader for a picture. Nil when they chose none.

  `dir` is where a copy belongs on the targets that have one  it is the
  caller's, because it comes from `frq.io/config-dir`, and the web backend
  ignores it."
  [dir]
  (if-let [f (:pick! @impl)]
    (await (f dir))
    (throw (ex-info "frq.pictures: no backend installed" {:op :pick!}))))

(defn ^:async upload!
  "Send `picture` and answer the URL freeq serves it back at."
  [host did channel picture]
  (if-let [f (:upload! @impl)]
    (await (f host did channel picture))
    (throw (ex-info "frq.pictures: no backend installed" {:op :upload!}))))

(defn preview-url
  "What the renderer should draw for the picture at `url`, or nil while there
  is nothing to draw yet.

  Two different answers, and the browser's is the simpler one. dart:io
  downloads the picture into a cache and hands back a path, because a phone
  wants the bytes on disk and `frq.media` is the thing that puts them there.
  A browser already has an image loader with a cache in front of it, and no
  disk to put anything on  so the answer is the URL, which
  `frq.hiccup/src-url` then sends through the same proxy the avatars use.

  Synchronous, because the screens call it while they build a row and read nil
  as \"not here yet\" — see `frq.media/path-when-ready`, which is the answer on
  the other two targets."
  [url]
  (if-let [f (:preview-url @impl)]
    (f url)
    nil))