Open a profile by pressing a face, and nothing else
Resting a pointer on a face raised the card too, with a 400ms grace period for crossing from the face to it and the card reporting its own pointer back so that leaving the face was not the end of it. That bought a second way in at a price: the card arrived unasked for on every face crossed on the way to the scrollbar, and the dialog had to be non-modal whenever a pointer was what held it open — a modal one makes the window underneath it deaf, so the face would never hear the pointer leave and could not close what it opened. One gesture now, on both desktop backends and the phone alike. The dialog is unconditionally modal, which is what it always wanted to be, and reads `viewing` alone; `dismiss!` collapses into `close!`, since there is only one thing left to clear. The grace period was `frq.io/after!`'s only caller, so the seam entry and both host implementations go with it. `frq.profile.pointer` is renamed to `frq.profile.host`: what is left in it is this backend's fetch and its avatar, and no pointer at all. The reaction-hover card is untouched — it is still the pointer's, and still non-modal for the same reason this one no longer has to be. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
8f05e74 parent: 54b668a modified
common/frq/actions.cljc +0 -6 | @@ -90,7 +90,6 @@ | ||
| 90 | 90 | |
| 91 | 91 | (defn desktop? [] (boolean (call :desktop? []))) |
| 92 | 92 | (defn quit! [] (call :quit! [])) |
| 93 | -(defn hovering [] (call :hovering [])) | |
| 94 | 93 | (defn viewing [] (call :viewing [])) |
| 95 | 94 | (defn accept-policy! [& args] (call :accept-policy! args)) |
| 96 | 95 | (defn close-picker! [& args] (call :close-picker! args)) |
| @@ -135,8 +134,6 @@ | ||
| 135 | 134 | |
| 136 | 135 | ;; ---------------------------------------------------------------- profile |
| 137 | 136 | |
| 138 | -(defn profile-hover! [& args] (call :profile-hover! args)) | |
| 139 | -(defn profile-unhover! [& args] (call :profile-unhover! args)) | |
| 140 | 137 | (defn profile-open! [& args] (call :profile-open! args)) |
| 141 | 138 | (defn toggle-hide-join-part! [] (call :toggle-hide-join-part! [])) |
| 142 | 139 | |
| @@ -156,10 +153,7 @@ | ||
| 156 | 153 | (defn avatar-ready [& args] (call :avatar-ready args)) |
| 157 | 154 | |
| 158 | 155 | (defn profile-close! [& args] (call :profile-close! args)) |
| 159 | -(defn profile-dismiss! [& args] (call :profile-dismiss! args)) | |
| 160 | -(defn profile-enter-dialog! [& args] (call :profile-enter-dialog! args)) | |
| 161 | 156 | (defn profile-entry [& args] (call :profile-entry args)) |
| 162 | -(defn profile-leave-dialog! [& args] (call :profile-leave-dialog! args)) | |
| 163 | 157 | (defn profile-stats-line [& args] (call :profile-stats-line args)) |
| 164 | 158 | (defn profile-tick [] (call :profile-tick [])) |
| 165 | 159 | (defn profile-truncate [& args] (call :profile-truncate args)) |
| @@ -90,7 +90,6 @@ | |||
| 90 | 90 | ||
| 91 | (defn desktop? [] (boolean (call :desktop? []))) | 91 | (defn desktop? [] (boolean (call :desktop? []))) |
| 92 | (defn quit! [] (call :quit! [])) | 92 | (defn quit! [] (call :quit! [])) |
| 93 | -(defn hovering [] (call :hovering [])) | ||
| 94 | (defn viewing [] (call :viewing [])) | 93 | (defn viewing [] (call :viewing [])) |
| 95 | (defn accept-policy! [& args] (call :accept-policy! args)) | 94 | (defn accept-policy! [& args] (call :accept-policy! args)) |
| 96 | (defn close-picker! [& args] (call :close-picker! args)) | 95 | (defn close-picker! [& args] (call :close-picker! args)) |
| @@ -135,8 +134,6 @@ | |||
| 135 | 134 | ||
| 136 | ;; ---------------------------------------------------------------- profile | 135 | ;; ---------------------------------------------------------------- profile |
| 137 | 136 | ||
| 138 | -(defn profile-hover! [& args] (call :profile-hover! args)) | ||
| 139 | -(defn profile-unhover! [& args] (call :profile-unhover! args)) | ||
| 140 | (defn profile-open! [& args] (call :profile-open! args)) | 137 | (defn profile-open! [& args] (call :profile-open! args)) |
| 141 | (defn toggle-hide-join-part! [] (call :toggle-hide-join-part! [])) | 138 | (defn toggle-hide-join-part! [] (call :toggle-hide-join-part! [])) |
| 142 | 139 | ||
| @@ -156,10 +153,7 @@ | |||
| 156 | (defn avatar-ready [& args] (call :avatar-ready args)) | 153 | (defn avatar-ready [& args] (call :avatar-ready args)) |
| 157 | 154 | ||
| 158 | (defn profile-close! [& args] (call :profile-close! args)) | 155 | (defn profile-close! [& args] (call :profile-close! args)) |
| 159 | -(defn profile-dismiss! [& args] (call :profile-dismiss! args)) | ||
| 160 | -(defn profile-enter-dialog! [& args] (call :profile-enter-dialog! args)) | ||
| 161 | (defn profile-entry [& args] (call :profile-entry args)) | 156 | (defn profile-entry [& args] (call :profile-entry args)) |
| 162 | -(defn profile-leave-dialog! [& args] (call :profile-leave-dialog! args)) | ||
| 163 | (defn profile-stats-line [& args] (call :profile-stats-line args)) | 157 | (defn profile-stats-line [& args] (call :profile-stats-line args)) |
| 164 | (defn profile-tick [] (call :profile-tick [])) | 158 | (defn profile-tick [] (call :profile-tick [])) |
| 165 | (defn profile-truncate [& args] (call :profile-truncate args)) | 159 | (defn profile-truncate [& args] (call :profile-truncate args)) |
modified
common/frq/cells.cljc +1 -5 | @@ -238,10 +238,6 @@ | ||
| 238 | 238 | ;; or handle, and nil for a guest. |
| 239 | 239 | (defonce profile-viewing (atom nil)) |
| 240 | 240 | |
| 241 | -;; The face the pointer is resting on, the same shape. A card is painted for | |
| 242 | -;; this one alone rather than hung under every avatar in the column. | |
| 243 | -(defonce profile-hovering (atom nil)) | |
| 244 | - | |
| 245 | 241 | ;; Bumped when a profile fetch lands, so the screen re-renders without |
| 246 | 242 | ;; watching the cache map itself. |
| 247 | 243 | (defonce profile-tick (atom 0)) |
| @@ -273,4 +269,4 @@ | ||
| 273 | 269 | attachment jump-tick show-users? hide-chat-list? overview? at-present? |
| 274 | 270 | emoji-group emoji-search highlight jump-to lightbox overview-return |
| 275 | 271 | saved-to reacting window-height window-width reaction-hover hide-join-part? |
| 276 | - image-picker profile-viewing profile-hovering profile-tick]) | |
| 272 | + image-picker profile-viewing profile-tick]) | |
| @@ -238,10 +238,6 @@ | |||
| 238 | ;; or handle, and nil for a guest. | 238 | ;; or handle, and nil for a guest. |
| 239 | (defonce profile-viewing (atom nil)) | 239 | (defonce profile-viewing (atom nil)) |
| 240 | 240 | ||
| 241 | -;; The face the pointer is resting on, the same shape. A card is painted for | ||
| 242 | -;; this one alone rather than hung under every avatar in the column. | ||
| 243 | -(defonce profile-hovering (atom nil)) | ||
| 244 | - | ||
| 245 | ;; Bumped when a profile fetch lands, so the screen re-renders without | 241 | ;; Bumped when a profile fetch lands, so the screen re-renders without |
| 246 | ;; watching the cache map itself. | 242 | ;; watching the cache map itself. |
| 247 | (defonce profile-tick (atom 0)) | 243 | (defonce profile-tick (atom 0)) |
| @@ -273,4 +269,4 @@ | |||
| 273 | attachment jump-tick show-users? hide-chat-list? overview? at-present? | 269 | attachment jump-tick show-users? hide-chat-list? overview? at-present? |
| 274 | emoji-group emoji-search highlight jump-to lightbox overview-return | 270 | emoji-group emoji-search highlight jump-to lightbox overview-return |
| 275 | saved-to reacting window-height window-width reaction-hover hide-join-part? | 271 | saved-to reacting window-height window-width reaction-hover hide-join-part? |
| 276 | - image-picker profile-viewing profile-hovering profile-tick]) | 272 | + image-picker profile-viewing profile-tick]) |
modified
common/frq/io.cljc +0 -12 | @@ -142,15 +142,3 @@ | ||
| 142 | 142 | backlog read in November carries messages from August." |
| 143 | 143 | [epoch-secs] |
| 144 | 144 | (call :local-offset-seconds [epoch-secs])) |
| 145 | - | |
| 146 | -(defn after! | |
| 147 | - "Run `f` in about `ms` milliseconds, wherever this host runs UI work. | |
| 148 | - | |
| 149 | - Named for when rather than for how, like the rest of this seam. The window | |
| 150 | - lends the toolkit's own timer — a callback off the UI thread repaints from | |
| 151 | - the wrong one — and the phone has an event loop already and needs no | |
| 152 | - lending. What hangs on it is the grace period for crossing from a face to | |
| 153 | - the card it raised: see `frq.profile/unhover!`." | |
| 154 | - [ms f] | |
| 155 | - (call :after! [ms f]) | |
| 156 | - nil) | |
| @@ -142,15 +142,3 @@ | |||
| 142 | backlog read in November carries messages from August." | 142 | backlog read in November carries messages from August." |
| 143 | [epoch-secs] | 143 | [epoch-secs] |
| 144 | (call :local-offset-seconds [epoch-secs])) | 144 | (call :local-offset-seconds [epoch-secs])) |
| 145 | - | ||
| 146 | -(defn after! | ||
| 147 | - "Run `f` in about `ms` milliseconds, wherever this host runs UI work. | ||
| 148 | - | ||
| 149 | - Named for when rather than for how, like the rest of this seam. The window | ||
| 150 | - lends the toolkit's own timer — a callback off the UI thread repaints from | ||
| 151 | - the wrong one — and the phone has an event loop already and needs no | ||
| 152 | - lending. What hangs on it is the grace period for crossing from a face to | ||
| 153 | - the card it raised: see `frq.profile/unhover!`." | ||
| 154 | - [ms f] | ||
| 155 | - (call :after! [ms f]) | ||
| 156 | - nil) | ||
modified
common/frq/profile.cljc +13 -90 | @@ -11,22 +11,22 @@ | ||
| 11 | 11 | them the screen is the nick and a line saying so, which is the honest answer |
| 12 | 12 | rather than a spinner that never lands. |
| 13 | 13 | |
| 14 | - What a pointer does about one is here too, at the foot of this file: hovering | |
| 15 | - a face, the grace period for crossing from the face to the card, and the card | |
| 16 | - reporting its own pointer. That used to be jolt's alone, on the reading that | |
| 17 | - a pointer meant libcosmic — but `just flutter-desktop` is a window with a | |
| 18 | - mouse in it as much as `just cosmic run` is, and the machine is a few atoms | |
| 19 | - and a timer with nothing host-shaped in it. The timer is the one thing that was, | |
| 20 | - and `frq.io/after!` is where that went. Whether there is a pointer at all is | |
| 21 | - still the host's answer: `actions/desktop?`. | |
| 14 | + One gesture opens it, on every backend: a press. A pointer resting on a face | |
| 15 | + used to open the card too, with a grace period for crossing from the face to | |
| 16 | + it and the card reporting its own pointer back, so that leaving the face was | |
| 17 | + not the end of it. That is gone. It made the card something that could arrive | |
| 18 | + and leave without being asked for — crossing a column of faces on the way to | |
| 19 | + the scrollbar flickered one open per row — and it bought a second way in at | |
| 20 | + the price of a dialog that had to be non-modal to be able to close itself. | |
| 21 | + Pressing a face is the whole of it now, and what it opens stays until it is | |
| 22 | + closed. | |
| 22 | 23 | |
| 23 | 24 | The fetch is a seam, because it is the one part that differs — a future and a |
| 24 | 25 | blocking request on one side, an awaited one on the other. Nothing is fetched |
| 25 | 26 | until a backend installs one, and `entry` simply answers nil." |
| 26 | 27 | (:require [clojure.string :as str] |
| 27 | 28 | [frq.atproto.core :as atproto] |
| 28 | - [frq.cells :as cells] | |
| 29 | - [frq.io :as io])) | |
| 29 | + [frq.cells :as cells])) | |
| 30 | 30 | |
| 31 | 31 | (def directory-host atproto/directory-host) |
| 32 | 32 | |
| @@ -37,7 +37,6 @@ | ||
| 37 | 37 | (defonce ^:private cache (atom {})) |
| 38 | 38 | |
| 39 | 39 | (def viewing cells/profile-viewing) |
| 40 | -(def hovering cells/profile-hovering) | |
| 41 | 40 | (def tick cells/profile-tick) |
| 42 | 41 | |
| 43 | 42 | ;; A handle is a domain: labels joined by dots, ending in something alphabetic. |
| @@ -153,86 +152,10 @@ | ||
| 153 | 152 | (reset! viewing {:nick nick :actor actor}) |
| 154 | 153 | (fetch! actor)) |
| 155 | 154 | |
| 156 | -(defn close! [] (reset! viewing nil)) | |
| 157 | - | |
| 158 | -;; ------------------------------------------------------- what a pointer does | |
| 159 | - | |
| 160 | -;; Whether the pointer is on the dialog the hover put up. | |
| 161 | -;; | |
| 162 | -;; This is what makes a hovered profile something you can move into and read | |
| 163 | -;; rather than something you can only glance at: the dialog reports its own | |
| 164 | -;; pointer, so leaving the face is not the end of the hover if the pointer | |
| 165 | -;; turned up here instead. | |
| 166 | -(defonce ^:private over-dialog? (atom false)) | |
| 167 | - | |
| 168 | -(defn dismiss! | |
| 169 | - "Put the profile away, however it was opened. | |
| 170 | - | |
| 171 | - The dialog is shown for `viewing` or for `hovering`, so a Close that cleared | |
| 172 | - only the first left one the pointer had opened on screen with its own button | |
| 173 | - doing nothing to it." | |
| 174 | - [] | |
| 175 | - (reset! viewing nil) | |
| 176 | - (reset! hovering nil) | |
| 177 | - ;; And the pointer's claim on it. Close takes the dialog out from under the | |
| 178 | - ;; pointer, so there is no leaving edge coming to say so — left set, it | |
| 179 | - ;; would hold the next hover open for good. | |
| 180 | - (reset! over-dialog? false)) | |
| 181 | - | |
| 182 | -;; How long the pointer may be on neither the face nor the dialog before the | |
| 183 | -;; dialog goes. | |
| 184 | -;; | |
| 185 | -;; There is a gap between the two — the dialog is centred and the face is | |
| 186 | -;; wherever the message is — and a hover that ended the instant the pointer | |
| 187 | -;; left the face would close it halfway across every time. Long enough to | |
| 188 | -;; cross, short enough that a pointer moving somewhere else entirely does not | |
| 189 | -;; drag it along. | |
| 190 | -(def ^:private grace-ms 400) | |
| 191 | - | |
| 192 | -(defn- release! | |
| 193 | - "Let `nick`'s hover go, unless something has taken it up again. | |
| 194 | - | |
| 195 | - Three things can have happened in the grace period: the pointer arrived on | |
| 196 | - the dialog, it went back to the face, or it landed on someone else's. In all | |
| 197 | - three there is a hover to keep, and it is not this one's to end — which is | |
| 198 | - what the nick guard says." | |
| 199 | - [nick] | |
| 200 | - (when-not @over-dialog? | |
| 201 | - (swap! hovering #(when-not (= nick (:nick %)) %)))) | |
| 202 | - | |
| 203 | -(defn hover! | |
| 204 | - "The pointer has come to rest on someone's face. Starts the fetch opening | |
| 205 | - them would, so the card has something on it by the time it is read. | |
| 206 | - | |
| 207 | - Their picture is not asked for here. It is the one part of this that needs | |
| 208 | - the host — the desktop downloads a file and the phone hands the CDN URL | |
| 209 | - straight to the widget — so each backend asks for it at the seam, beside the | |
| 210 | - call to this." | |
| 211 | - [nick actor] | |
| 212 | - (reset! hovering {:nick nick :actor actor}) | |
| 213 | - (fetch! actor)) | |
| 214 | - | |
| 215 | -(defn unhover! | |
| 216 | - "The pointer has left `nick`'s face — which is not yet the end of it. | |
| 217 | - | |
| 218 | - Guarded by who is being left, so the leaving of one face cannot take down | |
| 219 | - the card of the next one: both edges arrive in the same frame when the | |
| 220 | - pointer crosses straight over." | |
| 221 | - [nick] | |
| 222 | - (io/after! grace-ms #(release! nick))) | |
| 223 | - | |
| 224 | -(defn enter-dialog! | |
| 225 | - "The pointer is on the dialog. Whatever hover put it there is now this." | |
| 226 | - [] | |
| 227 | - (reset! over-dialog? true)) | |
| 228 | - | |
| 229 | -(defn leave-dialog! | |
| 230 | - "The pointer has left the dialog, and with it the last thing holding the | |
| 231 | - profile open — unless it went back to the face it came from." | |
| 155 | +(defn close! | |
| 156 | + "Put the profile away." | |
| 232 | 157 | [] |
| 233 | - (reset! over-dialog? false) | |
| 234 | - (let [nick (:nick @hovering)] | |
| 235 | - (io/after! grace-ms #(release! nick)))) | |
| 158 | + (reset! viewing nil)) | |
| 236 | 159 | |
| 237 | 160 | (defn web-url |
| 238 | 161 | "Their profile on the web, by handle where there is one and DID otherwise." |
| @@ -11,22 +11,22 @@ | |||
| 11 | them the screen is the nick and a line saying so, which is the honest answer | 11 | them the screen is the nick and a line saying so, which is the honest answer |
| 12 | rather than a spinner that never lands. | 12 | rather than a spinner that never lands. |
| 13 | 13 | ||
| 14 | - What a pointer does about one is here too, at the foot of this file: hovering | 14 | + One gesture opens it, on every backend: a press. A pointer resting on a face |
| 15 | - a face, the grace period for crossing from the face to the card, and the card | 15 | + used to open the card too, with a grace period for crossing from the face to |
| 16 | - reporting its own pointer. That used to be jolt's alone, on the reading that | 16 | + it and the card reporting its own pointer back, so that leaving the face was |
| 17 | - a pointer meant libcosmic — but `just flutter-desktop` is a window with a | 17 | + not the end of it. That is gone. It made the card something that could arrive |
| 18 | - mouse in it as much as `just cosmic run` is, and the machine is a few atoms | 18 | + and leave without being asked for — crossing a column of faces on the way to |
| 19 | - and a timer with nothing host-shaped in it. The timer is the one thing that was, | 19 | + the scrollbar flickered one open per row — and it bought a second way in at |
| 20 | - and `frq.io/after!` is where that went. Whether there is a pointer at all is | 20 | + the price of a dialog that had to be non-modal to be able to close itself. |
| 21 | - still the host's answer: `actions/desktop?`. | 21 | + Pressing a face is the whole of it now, and what it opens stays until it is |
| 22 | + closed. | ||
| 22 | 23 | ||
| 23 | The fetch is a seam, because it is the one part that differs — a future and a | 24 | The fetch is a seam, because it is the one part that differs — a future and a |
| 24 | blocking request on one side, an awaited one on the other. Nothing is fetched | 25 | blocking request on one side, an awaited one on the other. Nothing is fetched |
| 25 | until a backend installs one, and `entry` simply answers nil." | 26 | until a backend installs one, and `entry` simply answers nil." |
| 26 | (:require [clojure.string :as str] | 27 | (:require [clojure.string :as str] |
| 27 | [frq.atproto.core :as atproto] | 28 | [frq.atproto.core :as atproto] |
| 28 | - [frq.cells :as cells] | 29 | + [frq.cells :as cells])) |
| 29 | - [frq.io :as io])) | ||
| 30 | 30 | ||
| 31 | (def directory-host atproto/directory-host) | 31 | (def directory-host atproto/directory-host) |
| 32 | 32 | ||
| @@ -37,7 +37,6 @@ | |||
| 37 | (defonce ^:private cache (atom {})) | 37 | (defonce ^:private cache (atom {})) |
| 38 | 38 | ||
| 39 | (def viewing cells/profile-viewing) | 39 | (def viewing cells/profile-viewing) |
| 40 | -(def hovering cells/profile-hovering) | ||
| 41 | (def tick cells/profile-tick) | 40 | (def tick cells/profile-tick) |
| 42 | 41 | ||
| 43 | ;; A handle is a domain: labels joined by dots, ending in something alphabetic. | 42 | ;; A handle is a domain: labels joined by dots, ending in something alphabetic. |
| @@ -153,86 +152,10 @@ | |||
| 153 | (reset! viewing {:nick nick :actor actor}) | 152 | (reset! viewing {:nick nick :actor actor}) |
| 154 | (fetch! actor)) | 153 | (fetch! actor)) |
| 155 | 154 | ||
| 156 | -(defn close! [] (reset! viewing nil)) | 155 | +(defn close! |
| 157 | - | 156 | + "Put the profile away." |
| 158 | -;; ------------------------------------------------------- what a pointer does | ||
| 159 | - | ||
| 160 | -;; Whether the pointer is on the dialog the hover put up. | ||
| 161 | -;; | ||
| 162 | -;; This is what makes a hovered profile something you can move into and read | ||
| 163 | -;; rather than something you can only glance at: the dialog reports its own | ||
| 164 | -;; pointer, so leaving the face is not the end of the hover if the pointer | ||
| 165 | -;; turned up here instead. | ||
| 166 | -(defonce ^:private over-dialog? (atom false)) | ||
| 167 | - | ||
| 168 | -(defn dismiss! | ||
| 169 | - "Put the profile away, however it was opened. | ||
| 170 | - | ||
| 171 | - The dialog is shown for `viewing` or for `hovering`, so a Close that cleared | ||
| 172 | - only the first left one the pointer had opened on screen with its own button | ||
| 173 | - doing nothing to it." | ||
| 174 | - [] | ||
| 175 | - (reset! viewing nil) | ||
| 176 | - (reset! hovering nil) | ||
| 177 | - ;; And the pointer's claim on it. Close takes the dialog out from under the | ||
| 178 | - ;; pointer, so there is no leaving edge coming to say so — left set, it | ||
| 179 | - ;; would hold the next hover open for good. | ||
| 180 | - (reset! over-dialog? false)) | ||
| 181 | - | ||
| 182 | -;; How long the pointer may be on neither the face nor the dialog before the | ||
| 183 | -;; dialog goes. | ||
| 184 | -;; | ||
| 185 | -;; There is a gap between the two — the dialog is centred and the face is | ||
| 186 | -;; wherever the message is — and a hover that ended the instant the pointer | ||
| 187 | -;; left the face would close it halfway across every time. Long enough to | ||
| 188 | -;; cross, short enough that a pointer moving somewhere else entirely does not | ||
| 189 | -;; drag it along. | ||
| 190 | -(def ^:private grace-ms 400) | ||
| 191 | - | ||
| 192 | -(defn- release! | ||
| 193 | - "Let `nick`'s hover go, unless something has taken it up again. | ||
| 194 | - | ||
| 195 | - Three things can have happened in the grace period: the pointer arrived on | ||
| 196 | - the dialog, it went back to the face, or it landed on someone else's. In all | ||
| 197 | - three there is a hover to keep, and it is not this one's to end — which is | ||
| 198 | - what the nick guard says." | ||
| 199 | - [nick] | ||
| 200 | - (when-not @over-dialog? | ||
| 201 | - (swap! hovering #(when-not (= nick (:nick %)) %)))) | ||
| 202 | - | ||
| 203 | -(defn hover! | ||
| 204 | - "The pointer has come to rest on someone's face. Starts the fetch opening | ||
| 205 | - them would, so the card has something on it by the time it is read. | ||
| 206 | - | ||
| 207 | - Their picture is not asked for here. It is the one part of this that needs | ||
| 208 | - the host — the desktop downloads a file and the phone hands the CDN URL | ||
| 209 | - straight to the widget — so each backend asks for it at the seam, beside the | ||
| 210 | - call to this." | ||
| 211 | - [nick actor] | ||
| 212 | - (reset! hovering {:nick nick :actor actor}) | ||
| 213 | - (fetch! actor)) | ||
| 214 | - | ||
| 215 | -(defn unhover! | ||
| 216 | - "The pointer has left `nick`'s face — which is not yet the end of it. | ||
| 217 | - | ||
| 218 | - Guarded by who is being left, so the leaving of one face cannot take down | ||
| 219 | - the card of the next one: both edges arrive in the same frame when the | ||
| 220 | - pointer crosses straight over." | ||
| 221 | - [nick] | ||
| 222 | - (io/after! grace-ms #(release! nick))) | ||
| 223 | - | ||
| 224 | -(defn enter-dialog! | ||
| 225 | - "The pointer is on the dialog. Whatever hover put it there is now this." | ||
| 226 | - [] | ||
| 227 | - (reset! over-dialog? true)) | ||
| 228 | - | ||
| 229 | -(defn leave-dialog! | ||
| 230 | - "The pointer has left the dialog, and with it the last thing holding the | ||
| 231 | - profile open — unless it went back to the face it came from." | ||
| 232 | [] | 157 | [] |
| 233 | - (reset! over-dialog? false) | 158 | + (reset! viewing nil)) |
| 234 | - (let [nick (:nick @hovering)] | ||
| 235 | - (io/after! grace-ms #(release! nick)))) | ||
| 236 | 159 | ||
| 237 | (defn web-url | 160 | (defn web-url |
| 238 | "Their profile on the web, by handle where there is one and DID otherwise." | 161 | "Their profile on the web, by handle where there is one and DID otherwise." |
modified
common/frq/screens/app.cljc +15 -32 | @@ -149,33 +149,22 @@ | ||
| 149 | 149 | opens is a dialog that moves under the pointer, and the fetch lands whenever |
| 150 | 150 | it lands. |
| 151 | 151 | |
| 152 | - Who it is about comes from either of two places, and that — with the | |
| 153 | - modality below — is the whole of what hovering and pressing a face do | |
| 154 | - differently. Resting on one sets `hovering`, which the pointer takes away | |
| 155 | - again when it leaves; pressing one sets `viewing`, which nothing takes away | |
| 156 | - but Close. `viewing` is read first, so a pinned profile is not swapped out | |
| 157 | - from under the reader by a face the pointer crosses on the way to it. | |
| 158 | - | |
| 159 | - And a dialog the pointer is holding open is not modal. A modal one makes | |
| 160 | - the window underneath it deaf — libcosmic wraps the app in a popover that | |
| 161 | - hands its content an `Unavailable` cursor while a popup is up, and Flutter's | |
| 162 | - side of this puts a scrim over the screens that absorbs what lands on it — so | |
| 163 | - the face that opened it never hears the pointer leave, and what a hover opened | |
| 164 | - could never close itself. Non-modal, the face keeps hearing, and moving away | |
| 165 | - shuts it. A pinned one is modal, which is what being pinned means: it is the | |
| 166 | - thing on the screen until it is dismissed." | |
| 152 | + Who it is about is `viewing`, and there is nothing else it could be: a press | |
| 153 | + sets it and only Close clears it. So the dialog is modal, which is what it | |
| 154 | + always wanted to be — the thing on the screen until it is closed. It was | |
| 155 | + modal only some of the time while a hovered face could raise it too: a modal | |
| 156 | + dialog makes the window underneath it deaf, and the face that opened one | |
| 157 | + would then never hear the pointer leave to close it again. See `frq.profile` | |
| 158 | + for why that second way in is gone." | |
| 167 | 159 | [] |
| 168 | - (let [pinned? (some? (actions/viewing)) | |
| 169 | - {:keys [nick actor]} (or (actions/viewing) (actions/hovering)) | |
| 160 | + (let [{:keys [nick actor]} (actions/viewing) | |
| 170 | 161 | _ (actions/profile-tick) |
| 171 | 162 | _ (actions/media-tick) |
| 172 | 163 | pr (actions/profile-entry actor) |
| 173 | 164 | ready? (= :ready (:status pr)) |
| 174 | 165 | display (or (:display-name pr) nick) |
| 175 | 166 | url (when ready? (actions/profile-web-url pr))] |
| 176 | - [:dialog {:label display :max-width 520 :modal pinned? | |
| 177 | - :on-hover actions/profile-enter-dialog! | |
| 178 | - :on-unhover actions/profile-leave-dialog!} | |
| 167 | + [:dialog {:label display :max-width 520 :modal true} | |
| 179 | 168 | ;; The body is the screen's card without its heading: the dialog's own |
| 180 | 169 | ;; title is the name now, so repeating it under the picture is a line |
| 181 | 170 | ;; that says nothing. |
| @@ -215,15 +204,9 @@ | ||
| 215 | 204 | ;; `slot` is where libcosmic puts a button: the two actions go to the |
| 216 | 205 | ;; foot of the dialog, and anything else here would be another control |
| 217 | 206 | ;; stacked in the body. |
| 218 | - ;; | |
| 219 | - ;; Both are here whether the profile is pinned or only hovered. They were | |
| 220 | - ;; hidden while hovering, back when a hover could not be walked into: the | |
| 221 | - ;; dialog reports its own pointer now, so moving towards a button in it | |
| 222 | - ;; keeps it open instead of closing it, and a button you can reach is a | |
| 223 | - ;; button worth drawing. | |
| 224 | 207 | [:button {:key :close :slot "primary" |
| 225 | - :label (if pinned? "Close" "Dismiss") | |
| 226 | - :on-click actions/profile-dismiss!}] | |
| 208 | + :label "Close" | |
| 209 | + :on-click actions/profile-close!}] | |
| 227 | 210 | [:button {:key :web :slot "secondary" :label "Bluesky ↗" |
| 228 | 211 | :sensitive (boolean url) |
| 229 | 212 | :on-click #(when url (actions/open-url! url))}]])) |
| @@ -388,13 +371,13 @@ | ||
| 388 | 371 | ;; paint its contents inline at the bottom of the screen. So there it stays |
| 389 | 372 | ;; a screen you go to and come back from, which is `profile-screen`. |
| 390 | 373 | [:vbox {:key :root :fill-height true} |
| 391 | - ;; One dialog at a time, and a pinned profile outranks both pointers: it is | |
| 392 | - ;; the only one of the three that was asked for by a press rather than by | |
| 393 | - ;; where the pointer happens to be resting. | |
| 374 | + ;; One dialog at a time, and the profile outranks the reaction card: it is | |
| 375 | + ;; the one of the two that was asked for by a press rather than by where the | |
| 376 | + ;; pointer happens to be resting. | |
| 394 | 377 | [:vbox {:key :dialog} |
| 395 | 378 | (when-not @terminal? |
| 396 | 379 | (cond |
| 397 | - (or (actions/viewing) (actions/hovering)) [profile-dialog] | |
| 380 | + (actions/viewing) [profile-dialog] | |
| 398 | 381 | @cells/reaction-hover [reactor-dialog]))] |
| 399 | 382 | (cond |
| 400 | 383 | @cells/lightbox [:vbox {:key :screen-lightbox} [lightbox-screen]] |
| @@ -149,33 +149,22 @@ | |||
| 149 | opens is a dialog that moves under the pointer, and the fetch lands whenever | 149 | opens is a dialog that moves under the pointer, and the fetch lands whenever |
| 150 | it lands. | 150 | it lands. |
| 151 | 151 | ||
| 152 | - Who it is about comes from either of two places, and that — with the | 152 | + Who it is about is `viewing`, and there is nothing else it could be: a press |
| 153 | - modality below — is the whole of what hovering and pressing a face do | 153 | + sets it and only Close clears it. So the dialog is modal, which is what it |
| 154 | - differently. Resting on one sets `hovering`, which the pointer takes away | 154 | + always wanted to be — the thing on the screen until it is closed. It was |
| 155 | - again when it leaves; pressing one sets `viewing`, which nothing takes away | 155 | + modal only some of the time while a hovered face could raise it too: a modal |
| 156 | - but Close. `viewing` is read first, so a pinned profile is not swapped out | 156 | + dialog makes the window underneath it deaf, and the face that opened one |
| 157 | - from under the reader by a face the pointer crosses on the way to it. | 157 | + would then never hear the pointer leave to close it again. See `frq.profile` |
| 158 | - | 158 | + for why that second way in is gone." |
| 159 | - And a dialog the pointer is holding open is not modal. A modal one makes | ||
| 160 | - the window underneath it deaf — libcosmic wraps the app in a popover that | ||
| 161 | - hands its content an `Unavailable` cursor while a popup is up, and Flutter's | ||
| 162 | - side of this puts a scrim over the screens that absorbs what lands on it — so | ||
| 163 | - the face that opened it never hears the pointer leave, and what a hover opened | ||
| 164 | - could never close itself. Non-modal, the face keeps hearing, and moving away | ||
| 165 | - shuts it. A pinned one is modal, which is what being pinned means: it is the | ||
| 166 | - thing on the screen until it is dismissed." | ||
| 167 | [] | 159 | [] |
| 168 | - (let [pinned? (some? (actions/viewing)) | 160 | + (let [{:keys [nick actor]} (actions/viewing) |
| 169 | - {:keys [nick actor]} (or (actions/viewing) (actions/hovering)) | ||
| 170 | _ (actions/profile-tick) | 161 | _ (actions/profile-tick) |
| 171 | _ (actions/media-tick) | 162 | _ (actions/media-tick) |
| 172 | pr (actions/profile-entry actor) | 163 | pr (actions/profile-entry actor) |
| 173 | ready? (= :ready (:status pr)) | 164 | ready? (= :ready (:status pr)) |
| 174 | display (or (:display-name pr) nick) | 165 | display (or (:display-name pr) nick) |
| 175 | url (when ready? (actions/profile-web-url pr))] | 166 | url (when ready? (actions/profile-web-url pr))] |
| 176 | - [:dialog {:label display :max-width 520 :modal pinned? | 167 | + [:dialog {:label display :max-width 520 :modal true} |
| 177 | - :on-hover actions/profile-enter-dialog! | ||
| 178 | - :on-unhover actions/profile-leave-dialog!} | ||
| 179 | ;; The body is the screen's card without its heading: the dialog's own | 168 | ;; The body is the screen's card without its heading: the dialog's own |
| 180 | ;; title is the name now, so repeating it under the picture is a line | 169 | ;; title is the name now, so repeating it under the picture is a line |
| 181 | ;; that says nothing. | 170 | ;; that says nothing. |
| @@ -215,15 +204,9 @@ | |||
| 215 | ;; `slot` is where libcosmic puts a button: the two actions go to the | 204 | ;; `slot` is where libcosmic puts a button: the two actions go to the |
| 216 | ;; foot of the dialog, and anything else here would be another control | 205 | ;; foot of the dialog, and anything else here would be another control |
| 217 | ;; stacked in the body. | 206 | ;; stacked in the body. |
| 218 | - ;; | ||
| 219 | - ;; Both are here whether the profile is pinned or only hovered. They were | ||
| 220 | - ;; hidden while hovering, back when a hover could not be walked into: the | ||
| 221 | - ;; dialog reports its own pointer now, so moving towards a button in it | ||
| 222 | - ;; keeps it open instead of closing it, and a button you can reach is a | ||
| 223 | - ;; button worth drawing. | ||
| 224 | [:button {:key :close :slot "primary" | 207 | [:button {:key :close :slot "primary" |
| 225 | - :label (if pinned? "Close" "Dismiss") | 208 | + :label "Close" |
| 226 | - :on-click actions/profile-dismiss!}] | 209 | + :on-click actions/profile-close!}] |
| 227 | [:button {:key :web :slot "secondary" :label "Bluesky ↗" | 210 | [:button {:key :web :slot "secondary" :label "Bluesky ↗" |
| 228 | :sensitive (boolean url) | 211 | :sensitive (boolean url) |
| 229 | :on-click #(when url (actions/open-url! url))}]])) | 212 | :on-click #(when url (actions/open-url! url))}]])) |
| @@ -388,13 +371,13 @@ | |||
| 388 | ;; paint its contents inline at the bottom of the screen. So there it stays | 371 | ;; paint its contents inline at the bottom of the screen. So there it stays |
| 389 | ;; a screen you go to and come back from, which is `profile-screen`. | 372 | ;; a screen you go to and come back from, which is `profile-screen`. |
| 390 | [:vbox {:key :root :fill-height true} | 373 | [:vbox {:key :root :fill-height true} |
| 391 | - ;; One dialog at a time, and a pinned profile outranks both pointers: it is | 374 | + ;; One dialog at a time, and the profile outranks the reaction card: it is |
| 392 | - ;; the only one of the three that was asked for by a press rather than by | 375 | + ;; the one of the two that was asked for by a press rather than by where the |
| 393 | - ;; where the pointer happens to be resting. | 376 | + ;; pointer happens to be resting. |
| 394 | [:vbox {:key :dialog} | 377 | [:vbox {:key :dialog} |
| 395 | (when-not @terminal? | 378 | (when-not @terminal? |
| 396 | (cond | 379 | (cond |
| 397 | - (or (actions/viewing) (actions/hovering)) [profile-dialog] | 380 | + (actions/viewing) [profile-dialog] |
| 398 | @cells/reaction-hover [reactor-dialog]))] | 381 | @cells/reaction-hover [reactor-dialog]))] |
| 399 | (cond | 382 | (cond |
| 400 | @cells/lightbox [:vbox {:key :screen-lightbox} [lightbox-screen]] | 383 | @cells/lightbox [:vbox {:key :screen-lightbox} [lightbox-screen]] |
modified
common/frq/screens/chat.cljc +9 -14 | @@ -735,9 +735,6 @@ | ||
| 735 | 735 | ;; The face is also the way to the person behind it: Vidya's plain |
| 736 | 736 | ;; label does not answer the pointer, so the tap sleek puts on the |
| 737 | 737 | ;; nick lives here, on the one thing in the row that does. |
| 738 | - ;; And, where there is a pointer to ask with, resting on the face | |
| 739 | - ;; answers before the click does: the card under it is the profile | |
| 740 | - ;; screen's first few lines, painted beside the pointer. | |
| 741 | 738 | ;; And no face on this line in a terminal: the initial that stands in |
| 742 | 739 | ;; for a portrait in a window is a letter printed twice in a cell grid, |
| 743 | 740 | ;; which only pushed every nick in past the words it heads. Where the |
| @@ -745,17 +742,15 @@ | ||
| 745 | 742 | ;; the whole message rather than off its heading — `message-row` has it. |
| 746 | 743 | (when-not @terminal? |
| 747 | 744 | (let [src (actions/avatar-path (:actor m))] |
| 748 | - ;; One profile, two gestures, and no card hung under the face: the | |
| 749 | - ;; pointer opens the dialog and the press pins it. What makes that | |
| 750 | - ;; work is the dialog being non-modal while the pointer is what is | |
| 751 | - ;; holding it open — see `profile-dialog`. | |
| 752 | - [:avatar (cond-> {:label (:from m) | |
| 753 | - :src (or src "") | |
| 754 | - :size face-size | |
| 755 | - :on-click #(actions/profile-open! (:from m) (:actor m))} | |
| 756 | - (actions/desktop?) | |
| 757 | - (assoc :on-hover #(actions/profile-hover! (:from m) (:actor m)) | |
| 758 | - :on-unhover #(actions/profile-unhover! (:from m))))])) | |
| 745 | + ;; One profile and one gesture: the press opens the dialog, on a | |
| 746 | + ;; phone and in a window alike. Resting a pointer on the face used | |
| 747 | + ;; to open it too, which made the card something that arrived | |
| 748 | + ;; unasked for every face crossed on the way somewhere else — see | |
| 749 | + ;; `frq.profile`. | |
| 750 | + [:avatar {:label (:from m) | |
| 751 | + :src (or src "") | |
| 752 | + :size face-size | |
| 753 | + :on-click #(actions/profile-open! (:from m) (:actor m))}])) | |
| 759 | 754 | ;; The name carries the row, so it is set at body size in the plain |
| 760 | 755 | ;; text colour: dimmed caption made the one thing you scan a column |
| 761 | 756 | ;; for the faintest thing on it. |
| @@ -735,9 +735,6 @@ | |||
| 735 | ;; The face is also the way to the person behind it: Vidya's plain | 735 | ;; The face is also the way to the person behind it: Vidya's plain |
| 736 | ;; label does not answer the pointer, so the tap sleek puts on the | 736 | ;; label does not answer the pointer, so the tap sleek puts on the |
| 737 | ;; nick lives here, on the one thing in the row that does. | 737 | ;; nick lives here, on the one thing in the row that does. |
| 738 | - ;; And, where there is a pointer to ask with, resting on the face | ||
| 739 | - ;; answers before the click does: the card under it is the profile | ||
| 740 | - ;; screen's first few lines, painted beside the pointer. | ||
| 741 | ;; And no face on this line in a terminal: the initial that stands in | 738 | ;; And no face on this line in a terminal: the initial that stands in |
| 742 | ;; for a portrait in a window is a letter printed twice in a cell grid, | 739 | ;; for a portrait in a window is a letter printed twice in a cell grid, |
| 743 | ;; which only pushed every nick in past the words it heads. Where the | 740 | ;; which only pushed every nick in past the words it heads. Where the |
| @@ -745,17 +742,15 @@ | |||
| 745 | ;; the whole message rather than off its heading — `message-row` has it. | 742 | ;; the whole message rather than off its heading — `message-row` has it. |
| 746 | (when-not @terminal? | 743 | (when-not @terminal? |
| 747 | (let [src (actions/avatar-path (:actor m))] | 744 | (let [src (actions/avatar-path (:actor m))] |
| 748 | - ;; One profile, two gestures, and no card hung under the face: the | 745 | + ;; One profile and one gesture: the press opens the dialog, on a |
| 749 | - ;; pointer opens the dialog and the press pins it. What makes that | 746 | + ;; phone and in a window alike. Resting a pointer on the face used |
| 750 | - ;; work is the dialog being non-modal while the pointer is what is | 747 | + ;; to open it too, which made the card something that arrived |
| 751 | - ;; holding it open — see `profile-dialog`. | 748 | + ;; unasked for every face crossed on the way somewhere else — see |
| 752 | - [:avatar (cond-> {:label (:from m) | 749 | + ;; `frq.profile`. |
| 753 | - :src (or src "") | 750 | + [:avatar {:label (:from m) |
| 754 | - :size face-size | 751 | + :src (or src "") |
| 755 | - :on-click #(actions/profile-open! (:from m) (:actor m))} | 752 | + :size face-size |
| 756 | - (actions/desktop?) | 753 | + :on-click #(actions/profile-open! (:from m) (:actor m))}])) |
| 757 | - (assoc :on-hover #(actions/profile-hover! (:from m) (:actor m)) | ||
| 758 | - :on-unhover #(actions/profile-unhover! (:from m))))])) | ||
| 759 | ;; The name carries the row, so it is set at body size in the plain | 754 | ;; The name carries the row, so it is set at body size in the plain |
| 760 | ;; text colour: dimmed caption made the one thing you scan a column | 755 | ;; text colour: dimmed caption made the one thing you scan a column |
| 761 | ;; for the faintest thing on it. | 756 | ;; for the faintest thing on it. |
modified
flutter/src/frq/hiccup.cljd +62 -73 | @@ -873,14 +873,12 @@ | ||
| 873 | 873 | ;; On a phone there is no behind worth keeping — the screen is the width |
| 874 | 874 | ;; of the dialog already — so this is a sheet: the title, a rule, and |
| 875 | 875 | ;; the body, drawn where the tree puts it, above the conversation it was |
| 876 | - ;; opened from. `:modal` and the hover pair are read and ignored, since | |
| 877 | - ;; they are what a pointer needs to tell a card it opened by resting | |
| 878 | - ;; from one it opened by pressing, and a finger only ever presses. | |
| 876 | + ;; opened from. `:modal` is read and ignored: a sheet the width of the | |
| 877 | + ;; screen has nothing behind it to make deaf. | |
| 879 | 878 | ;; |
| 880 | 879 | ;; In a window it is what libcosmic's is: capped at `:max-width`, |
| 881 | - ;; centred over the screen, the buttons gathered into a foot, and the | |
| 882 | - ;; hover pair heard — so a card a pointer raised can be moved into and | |
| 883 | - ;; read rather than only glanced at. Nothing about the floating is here, | |
| 880 | + ;; centred over the screen, and the buttons gathered into a foot. | |
| 881 | + ;; Nothing about the floating is here, | |
| 884 | 882 | ;; though; a widget cannot lift itself out of the column it is in. That |
| 885 | 883 | ;; is `render-root`, which takes the dialog out of the tree and stacks |
| 886 | 884 | ;; it over what is left. This arm only has to draw the card. |
| @@ -910,59 +908,57 @@ | ||
| 910 | 908 | ;; one nearest the corner the pointer leaves by. |
| 911 | 909 | foot (concat (remove #(= "primary" (:slot (props %))) foot) |
| 912 | 910 | (filter #(= "primary" (:slot (props %))) foot))] |
| 913 | - (hovered | |
| 914 | - p | |
| 915 | - (m/ConstrainedBox | |
| 916 | - ;; Capped both ways. The width is what libcosmic is asked for; the | |
| 917 | - ;; height is so that a long bio is a card with a scroll in it | |
| 918 | - ;; rather than a card taller than the window. The body is the part | |
| 919 | - ;; that gives — the title and the buttons are why it is a dialog. | |
| 920 | - .constraints (m/BoxConstraints | |
| 921 | - .maxWidth (dbl (:max-width p) 520.0) | |
| 922 | - .maxHeight (* 0.8 (.-height (.-size (m/MediaQuery.of ctx))))) | |
| 911 | + (m/ConstrainedBox | |
| 912 | + ;; Capped both ways. The width is what libcosmic is asked for; the | |
| 913 | + ;; height is so that a long bio is a card with a scroll in it | |
| 914 | + ;; rather than a card taller than the window. The body is the part | |
| 915 | + ;; that gives — the title and the buttons are why it is a dialog. | |
| 916 | + .constraints (m/BoxConstraints | |
| 917 | + .maxWidth (dbl (:max-width p) 520.0) | |
| 918 | + .maxHeight (* 0.8 (.-height (.-size (m/MediaQuery.of ctx))))) | |
| 919 | + .child | |
| 920 | + (m/Container | |
| 921 | + ;; Infinity under a maxWidth of 520 is 520, and under a narrower | |
| 922 | + ;; window it is the window: the card is as wide as it is allowed | |
| 923 | + ;; to be, never as wide as its longest line. Without it the | |
| 924 | + ;; Column is sized to its children and the rules inside it ask | |
| 925 | + ;; for an unbounded width, which is a layout error rather than a | |
| 926 | + ;; narrow dialog. | |
| 927 | + .width double/infinity | |
| 928 | + .padding (m/EdgeInsets.all t/space-s) | |
| 929 | + .decoration (m/BoxDecoration | |
| 930 | + .color t/card | |
| 931 | + .border (m/Border.all .color t/divider .width 1.0) | |
| 932 | + .borderRadius (m/BorderRadius.circular t/radius-m)) | |
| 923 | 933 | .child |
| 924 | - (m/Container | |
| 925 | - ;; Infinity under a maxWidth of 520 is 520, and under a narrower | |
| 926 | - ;; window it is the window: the card is as wide as it is allowed | |
| 927 | - ;; to be, never as wide as its longest line. Without it the | |
| 928 | - ;; Column is sized to its children and the rules inside it ask | |
| 929 | - ;; for an unbounded width, which is a layout error rather than a | |
| 930 | - ;; narrow dialog. | |
| 931 | - .width double/infinity | |
| 932 | - .padding (m/EdgeInsets.all t/space-s) | |
| 933 | - .decoration (m/BoxDecoration | |
| 934 | - .color t/card | |
| 935 | - .border (m/Border.all .color t/divider .width 1.0) | |
| 936 | - .borderRadius (m/BorderRadius.circular t/radius-m)) | |
| 937 | - .child | |
| 938 | - ;; Built out rather than handed to `col`, because the foot is a | |
| 939 | - ;; Row aligned to the end and `:hbox` has no word for that. One | |
| 940 | - ;; place that wants it and no prop invented for it. | |
| 941 | - (m/Column | |
| 942 | - .crossAxisAlignment m/CrossAxisAlignment.start | |
| 943 | - .mainAxisSize m/MainAxisSize.min | |
| 944 | - .spacing t/space-xxs | |
| 945 | - .children | |
| 946 | - (concat [(render [:title-2 {:label (:label p "")}]) | |
| 947 | - (render [:separator {}])] | |
| 948 | - ;; Flexible and loose: the body takes what it needs up | |
| 949 | - ;; to what the cap leaves, and scrolls inside that. A | |
| 950 | - ;; short profile is still a short card. | |
| 951 | - [(m/Flexible | |
| 952 | - .child | |
| 953 | - (m/SingleChildScrollView | |
| 954 | - .child (m/Column | |
| 955 | - .crossAxisAlignment m/CrossAxisAlignment.start | |
| 956 | - .mainAxisSize m/MainAxisSize.min | |
| 957 | - .spacing t/space-xxs | |
| 958 | - .children (children (remove slotted kids)))))] | |
| 959 | - (when (seq foot) | |
| 960 | - [(render [:separator {}]) | |
| 961 | - (m/Row | |
| 962 | - .mainAxisSize m/MainAxisSize.max | |
| 963 | - .mainAxisAlignment m/MainAxisAlignment.end | |
| 964 | - .spacing t/space-xxs | |
| 965 | - .children (children foot))])))))))) | |
| 934 | + ;; Built out rather than handed to `col`, because the foot is a | |
| 935 | + ;; Row aligned to the end and `:hbox` has no word for that. One | |
| 936 | + ;; place that wants it and no prop invented for it. | |
| 937 | + (m/Column | |
| 938 | + .crossAxisAlignment m/CrossAxisAlignment.start | |
| 939 | + .mainAxisSize m/MainAxisSize.min | |
| 940 | + .spacing t/space-xxs | |
| 941 | + .children | |
| 942 | + (concat [(render [:title-2 {:label (:label p "")}]) | |
| 943 | + (render [:separator {}])] | |
| 944 | + ;; Flexible and loose: the body takes what it needs up | |
| 945 | + ;; to what the cap leaves, and scrolls inside that. A | |
| 946 | + ;; short profile is still a short card. | |
| 947 | + [(m/Flexible | |
| 948 | + .child | |
| 949 | + (m/SingleChildScrollView | |
| 950 | + .child (m/Column | |
| 951 | + .crossAxisAlignment m/CrossAxisAlignment.start | |
| 952 | + .mainAxisSize m/MainAxisSize.min | |
| 953 | + .spacing t/space-xxs | |
| 954 | + .children (children (remove slotted kids)))))] | |
| 955 | + (when (seq foot) | |
| 956 | + [(render [:separator {}]) | |
| 957 | + (m/Row | |
| 958 | + .mainAxisSize m/MainAxisSize.max | |
| 959 | + .mainAxisAlignment m/MainAxisAlignment.end | |
| 960 | + .spacing t/space-xxs | |
| 961 | + .children (children foot))]))))))) | |
| 966 | 962 | |
| 967 | 963 | :separator (m/Divider .height 1.0 .thickness 1.0 .color t/divider) |
| 968 | 964 | |
| @@ -1074,14 +1070,9 @@ | ||
| 1074 | 1070 | (m/Text (str (:emoji p "")) .style (t/emoji-style (dbl (:size p) 16.0))) |
| 1075 | 1071 | |
| 1076 | 1072 | ;; A face is a way in to who someone is, so it takes the press that |
| 1077 | - ;; opens their profile. It was drawn without one and the chat screen's | |
| 1078 | - ;; `:on-click` went nowhere — the one gesture a phone has for this. | |
| 1079 | - ;; | |
| 1080 | - ;; And, in a window, the gesture that comes before the press: resting on | |
| 1081 | - ;; a face raises the card without pinning it. `hovered` is what hears | |
| 1082 | - ;; that; the card it raises is the `:dialog` arm above, floated by | |
| 1083 | - ;; `render-root`. On the phone the screens do not even hang a hover on a | |
| 1084 | - ;; face — they ask `desktop?` first — and `hovered` is a no-op besides. | |
| 1073 | + ;; opens their profile — the one gesture a phone has for this, and the | |
| 1074 | + ;; only one either target uses. It was drawn without one and the chat | |
| 1075 | + ;; screen's `:on-click` went nowhere. | |
| 1085 | 1076 | :avatar |
| 1086 | 1077 | (let [s (dbl (:size p) 32.0) |
| 1087 | 1078 | src (:src p) |
| @@ -1111,13 +1102,11 @@ | ||
| 1111 | 1102 | (.toUpperCase (subs l 0 1)) |
| 1112 | 1103 | "?")) |
| 1113 | 1104 | t/text-body t/on-bg)))] |
| 1114 | - (hovered | |
| 1115 | - p | |
| 1116 | - (if-let [on (:on-click p)] | |
| 1117 | - (m/InkWell .onTap #(on) | |
| 1118 | - .customBorder (m/CircleBorder) | |
| 1119 | - .child face) | |
| 1120 | - face))) | |
| 1105 | + (if-let [on (:on-click p)] | |
| 1106 | + (m/InkWell .onTap #(on) | |
| 1107 | + .customBorder (m/CircleBorder) | |
| 1108 | + .child face) | |
| 1109 | + face)) | |
| 1121 | 1110 | |
| 1122 | 1111 | :image |
| 1123 | 1112 | (let [src (or (:src p) (:path p)) |
| @@ -873,14 +873,12 @@ | |||
| 873 | ;; On a phone there is no behind worth keeping — the screen is the width | 873 | ;; On a phone there is no behind worth keeping — the screen is the width |
| 874 | ;; of the dialog already — so this is a sheet: the title, a rule, and | 874 | ;; of the dialog already — so this is a sheet: the title, a rule, and |
| 875 | ;; the body, drawn where the tree puts it, above the conversation it was | 875 | ;; the body, drawn where the tree puts it, above the conversation it was |
| 876 | - ;; opened from. `:modal` and the hover pair are read and ignored, since | 876 | + ;; opened from. `:modal` is read and ignored: a sheet the width of the |
| 877 | - ;; they are what a pointer needs to tell a card it opened by resting | 877 | + ;; screen has nothing behind it to make deaf. |
| 878 | - ;; from one it opened by pressing, and a finger only ever presses. | ||
| 879 | ;; | 878 | ;; |
| 880 | ;; In a window it is what libcosmic's is: capped at `:max-width`, | 879 | ;; In a window it is what libcosmic's is: capped at `:max-width`, |
| 881 | - ;; centred over the screen, the buttons gathered into a foot, and the | 880 | + ;; centred over the screen, and the buttons gathered into a foot. |
| 882 | - ;; hover pair heard — so a card a pointer raised can be moved into and | 881 | + ;; Nothing about the floating is here, |
| 883 | - ;; read rather than only glanced at. Nothing about the floating is here, | ||
| 884 | ;; though; a widget cannot lift itself out of the column it is in. That | 882 | ;; though; a widget cannot lift itself out of the column it is in. That |
| 885 | ;; is `render-root`, which takes the dialog out of the tree and stacks | 883 | ;; is `render-root`, which takes the dialog out of the tree and stacks |
| 886 | ;; it over what is left. This arm only has to draw the card. | 884 | ;; it over what is left. This arm only has to draw the card. |
| @@ -910,59 +908,57 @@ | |||
| 910 | ;; one nearest the corner the pointer leaves by. | 908 | ;; one nearest the corner the pointer leaves by. |
| 911 | foot (concat (remove #(= "primary" (:slot (props %))) foot) | 909 | foot (concat (remove #(= "primary" (:slot (props %))) foot) |
| 912 | (filter #(= "primary" (:slot (props %))) foot))] | 910 | (filter #(= "primary" (:slot (props %))) foot))] |
| 913 | - (hovered | 911 | + (m/ConstrainedBox |
| 914 | - p | 912 | + ;; Capped both ways. The width is what libcosmic is asked for; the |
| 915 | - (m/ConstrainedBox | 913 | + ;; height is so that a long bio is a card with a scroll in it |
| 916 | - ;; Capped both ways. The width is what libcosmic is asked for; the | 914 | + ;; rather than a card taller than the window. The body is the part |
| 917 | - ;; height is so that a long bio is a card with a scroll in it | 915 | + ;; that gives — the title and the buttons are why it is a dialog. |
| 918 | - ;; rather than a card taller than the window. The body is the part | 916 | + .constraints (m/BoxConstraints |
| 919 | - ;; that gives — the title and the buttons are why it is a dialog. | 917 | + .maxWidth (dbl (:max-width p) 520.0) |
| 920 | - .constraints (m/BoxConstraints | 918 | + .maxHeight (* 0.8 (.-height (.-size (m/MediaQuery.of ctx))))) |
| 921 | - .maxWidth (dbl (:max-width p) 520.0) | 919 | + .child |
| 922 | - .maxHeight (* 0.8 (.-height (.-size (m/MediaQuery.of ctx))))) | 920 | + (m/Container |
| 921 | + ;; Infinity under a maxWidth of 520 is 520, and under a narrower | ||
| 922 | + ;; window it is the window: the card is as wide as it is allowed | ||
| 923 | + ;; to be, never as wide as its longest line. Without it the | ||
| 924 | + ;; Column is sized to its children and the rules inside it ask | ||
| 925 | + ;; for an unbounded width, which is a layout error rather than a | ||
| 926 | + ;; narrow dialog. | ||
| 927 | + .width double/infinity | ||
| 928 | + .padding (m/EdgeInsets.all t/space-s) | ||
| 929 | + .decoration (m/BoxDecoration | ||
| 930 | + .color t/card | ||
| 931 | + .border (m/Border.all .color t/divider .width 1.0) | ||
| 932 | + .borderRadius (m/BorderRadius.circular t/radius-m)) | ||
| 923 | .child | 933 | .child |
| 924 | - (m/Container | 934 | + ;; Built out rather than handed to `col`, because the foot is a |
| 925 | - ;; Infinity under a maxWidth of 520 is 520, and under a narrower | 935 | + ;; Row aligned to the end and `:hbox` has no word for that. One |
| 926 | - ;; window it is the window: the card is as wide as it is allowed | 936 | + ;; place that wants it and no prop invented for it. |
| 927 | - ;; to be, never as wide as its longest line. Without it the | 937 | + (m/Column |
| 928 | - ;; Column is sized to its children and the rules inside it ask | 938 | + .crossAxisAlignment m/CrossAxisAlignment.start |
| 929 | - ;; for an unbounded width, which is a layout error rather than a | 939 | + .mainAxisSize m/MainAxisSize.min |
| 930 | - ;; narrow dialog. | 940 | + .spacing t/space-xxs |
| 931 | - .width double/infinity | 941 | + .children |
| 932 | - .padding (m/EdgeInsets.all t/space-s) | 942 | + (concat [(render [:title-2 {:label (:label p "")}]) |
| 933 | - .decoration (m/BoxDecoration | 943 | + (render [:separator {}])] |
| 934 | - .color t/card | 944 | + ;; Flexible and loose: the body takes what it needs up |
| 935 | - .border (m/Border.all .color t/divider .width 1.0) | 945 | + ;; to what the cap leaves, and scrolls inside that. A |
| 936 | - .borderRadius (m/BorderRadius.circular t/radius-m)) | 946 | + ;; short profile is still a short card. |
| 937 | - .child | 947 | + [(m/Flexible |
| 938 | - ;; Built out rather than handed to `col`, because the foot is a | 948 | + .child |
| 939 | - ;; Row aligned to the end and `:hbox` has no word for that. One | 949 | + (m/SingleChildScrollView |
| 940 | - ;; place that wants it and no prop invented for it. | 950 | + .child (m/Column |
| 941 | - (m/Column | 951 | + .crossAxisAlignment m/CrossAxisAlignment.start |
| 942 | - .crossAxisAlignment m/CrossAxisAlignment.start | 952 | + .mainAxisSize m/MainAxisSize.min |
| 943 | - .mainAxisSize m/MainAxisSize.min | 953 | + .spacing t/space-xxs |
| 944 | - .spacing t/space-xxs | 954 | + .children (children (remove slotted kids)))))] |
| 945 | - .children | 955 | + (when (seq foot) |
| 946 | - (concat [(render [:title-2 {:label (:label p "")}]) | 956 | + [(render [:separator {}]) |
| 947 | - (render [:separator {}])] | 957 | + (m/Row |
| 948 | - ;; Flexible and loose: the body takes what it needs up | 958 | + .mainAxisSize m/MainAxisSize.max |
| 949 | - ;; to what the cap leaves, and scrolls inside that. A | 959 | + .mainAxisAlignment m/MainAxisAlignment.end |
| 950 | - ;; short profile is still a short card. | 960 | + .spacing t/space-xxs |
| 951 | - [(m/Flexible | 961 | + .children (children foot))]))))))) |
| 952 | - .child | ||
| 953 | - (m/SingleChildScrollView | ||
| 954 | - .child (m/Column | ||
| 955 | - .crossAxisAlignment m/CrossAxisAlignment.start | ||
| 956 | - .mainAxisSize m/MainAxisSize.min | ||
| 957 | - .spacing t/space-xxs | ||
| 958 | - .children (children (remove slotted kids)))))] | ||
| 959 | - (when (seq foot) | ||
| 960 | - [(render [:separator {}]) | ||
| 961 | - (m/Row | ||
| 962 | - .mainAxisSize m/MainAxisSize.max | ||
| 963 | - .mainAxisAlignment m/MainAxisAlignment.end | ||
| 964 | - .spacing t/space-xxs | ||
| 965 | - .children (children foot))])))))))) | ||
| 966 | 962 | ||
| 967 | :separator (m/Divider .height 1.0 .thickness 1.0 .color t/divider) | 963 | :separator (m/Divider .height 1.0 .thickness 1.0 .color t/divider) |
| 968 | 964 | ||
| @@ -1074,14 +1070,9 @@ | |||
| 1074 | (m/Text (str (:emoji p "")) .style (t/emoji-style (dbl (:size p) 16.0))) | 1070 | (m/Text (str (:emoji p "")) .style (t/emoji-style (dbl (:size p) 16.0))) |
| 1075 | 1071 | ||
| 1076 | ;; A face is a way in to who someone is, so it takes the press that | 1072 | ;; A face is a way in to who someone is, so it takes the press that |
| 1077 | - ;; opens their profile. It was drawn without one and the chat screen's | 1073 | + ;; opens their profile — the one gesture a phone has for this, and the |
| 1078 | - ;; `:on-click` went nowhere — the one gesture a phone has for this. | 1074 | + ;; only one either target uses. It was drawn without one and the chat |
| 1079 | - ;; | 1075 | + ;; screen's `:on-click` went nowhere. |
| 1080 | - ;; And, in a window, the gesture that comes before the press: resting on | ||
| 1081 | - ;; a face raises the card without pinning it. `hovered` is what hears | ||
| 1082 | - ;; that; the card it raises is the `:dialog` arm above, floated by | ||
| 1083 | - ;; `render-root`. On the phone the screens do not even hang a hover on a | ||
| 1084 | - ;; face — they ask `desktop?` first — and `hovered` is a no-op besides. | ||
| 1085 | :avatar | 1076 | :avatar |
| 1086 | (let [s (dbl (:size p) 32.0) | 1077 | (let [s (dbl (:size p) 32.0) |
| 1087 | src (:src p) | 1078 | src (:src p) |
| @@ -1111,13 +1102,11 @@ | |||
| 1111 | (.toUpperCase (subs l 0 1)) | 1102 | (.toUpperCase (subs l 0 1)) |
| 1112 | "?")) | 1103 | "?")) |
| 1113 | t/text-body t/on-bg)))] | 1104 | t/text-body t/on-bg)))] |
| 1114 | - (hovered | 1105 | + (if-let [on (:on-click p)] |
| 1115 | - p | 1106 | + (m/InkWell .onTap #(on) |
| 1116 | - (if-let [on (:on-click p)] | 1107 | + .customBorder (m/CircleBorder) |
| 1117 | - (m/InkWell .onTap #(on) | 1108 | + .child face) |
| 1118 | - .customBorder (m/CircleBorder) | 1109 | + face)) |
| 1119 | - .child face) | ||
| 1120 | - face))) | ||
| 1121 | 1110 | ||
| 1122 | :image | 1111 | :image |
| 1123 | (let [src (or (:src p) (:path p)) | 1112 | (let [src (or (:src p) (:path p)) |
modified
flutter/src/frq/io/dart.cljd +1 -6 | @@ -176,9 +176,4 @@ | ||
| 176 | 176 | :utf8-string utf8-string |
| 177 | 177 | :wall-nanos (fn [] (* 1000 (.-microsecondsSinceEpoch (DateTime/now)))) |
| 178 | 178 | :mono-nanos (fn [] (* 1000 (.-inMicroseconds (.-elapsed ^Stopwatch uptime)))) |
| 179 | - :local-offset-seconds local-offset-seconds | |
| 180 | - ;; Dart has one event loop and the UI runs on it, so there is no thread to | |
| 181 | - ;; hand the callback back to — a timer is the whole of it. | |
| 182 | - :after! (fn [ms f] | |
| 183 | - (Future.delayed (Duration .milliseconds (int ms)) f) | |
| 184 | - nil)})) | |
| 179 | + :local-offset-seconds local-offset-seconds})) | |
| @@ -176,9 +176,4 @@ | |||
| 176 | :utf8-string utf8-string | 176 | :utf8-string utf8-string |
| 177 | :wall-nanos (fn [] (* 1000 (.-microsecondsSinceEpoch (DateTime/now)))) | 177 | :wall-nanos (fn [] (* 1000 (.-microsecondsSinceEpoch (DateTime/now)))) |
| 178 | :mono-nanos (fn [] (* 1000 (.-inMicroseconds (.-elapsed ^Stopwatch uptime)))) | 178 | :mono-nanos (fn [] (* 1000 (.-inMicroseconds (.-elapsed ^Stopwatch uptime)))) |
| 179 | - :local-offset-seconds local-offset-seconds | 179 | + :local-offset-seconds local-offset-seconds})) |
| 180 | - ;; Dart has one event loop and the UI runs on it, so there is no thread to | ||
| 181 | - ;; hand the callback back to — a timer is the whole of it. | ||
| 182 | - :after! (fn [ms f] | ||
| 183 | - (Future.delayed (Duration .milliseconds (int ms)) f) | ||
| 184 | - nil)})) | ||
modified
flutter/src/frq/main.cljd +0 -16 | @@ -1176,28 +1176,12 @@ | ||
| 1176 | 1176 | (avatars/fetch! actor bump!) |
| 1177 | 1177 | (profile/open! nick actor)) |
| 1178 | 1178 | :profile-close! profile/close! |
| 1179 | - ;; `dismiss!` and not `close!`: the card is shown for `viewing` or for | |
| 1180 | - ;; `hovering`, and a Close that cleared only the first leaves the one a | |
| 1181 | - ;; pointer opened on screen with its own button doing nothing. | |
| 1182 | - :profile-dismiss! profile/dismiss! | |
| 1183 | 1179 | :profile-entry profile/entry |
| 1184 | 1180 | :profile-tick (fn [] @profile/tick) |
| 1185 | 1181 | :profile-stats-line profile/stats-line |
| 1186 | 1182 | :profile-truncate profile/truncate |
| 1187 | 1183 | :profile-web-url profile/web-url |
| 1188 | 1184 | :viewing (fn [] @profile/viewing) |
| 1189 | - ;; The pointer half of a profile. These were no-ops while this file was | |
| 1190 | - ;; only ever an APK — a finger is either on a face or not on it — and | |
| 1191 | - ;; `just flutter-desktop` has a mouse, so the machine under them is the | |
| 1192 | - ;; shared one now. Nothing reaches them on the phone anyway: the screens | |
| 1193 | - ;; ask `desktop?` before they hang a hover on a face at all. | |
| 1194 | - :hovering (fn [] @profile/hovering) | |
| 1195 | - :profile-hover! (fn [nick actor] | |
| 1196 | - (avatars/fetch! actor bump!) | |
| 1197 | - (profile/hover! nick actor)) | |
| 1198 | - :profile-unhover! profile/unhover! | |
| 1199 | - :profile-enter-dialog! profile/enter-dialog! | |
| 1200 | - :profile-leave-dialog! profile/leave-dialog! | |
| 1201 | 1185 | ;; Their profile on the web, handed to the browser the same way the |
| 1202 | 1186 | ;; sign-in link is. |
| 1203 | 1187 | :open-url! (fn [url] (fio/open-url! url)) |
| @@ -1176,28 +1176,12 @@ | |||
| 1176 | (avatars/fetch! actor bump!) | 1176 | (avatars/fetch! actor bump!) |
| 1177 | (profile/open! nick actor)) | 1177 | (profile/open! nick actor)) |
| 1178 | :profile-close! profile/close! | 1178 | :profile-close! profile/close! |
| 1179 | - ;; `dismiss!` and not `close!`: the card is shown for `viewing` or for | ||
| 1180 | - ;; `hovering`, and a Close that cleared only the first leaves the one a | ||
| 1181 | - ;; pointer opened on screen with its own button doing nothing. | ||
| 1182 | - :profile-dismiss! profile/dismiss! | ||
| 1183 | :profile-entry profile/entry | 1179 | :profile-entry profile/entry |
| 1184 | :profile-tick (fn [] @profile/tick) | 1180 | :profile-tick (fn [] @profile/tick) |
| 1185 | :profile-stats-line profile/stats-line | 1181 | :profile-stats-line profile/stats-line |
| 1186 | :profile-truncate profile/truncate | 1182 | :profile-truncate profile/truncate |
| 1187 | :profile-web-url profile/web-url | 1183 | :profile-web-url profile/web-url |
| 1188 | :viewing (fn [] @profile/viewing) | 1184 | :viewing (fn [] @profile/viewing) |
| 1189 | - ;; The pointer half of a profile. These were no-ops while this file was | ||
| 1190 | - ;; only ever an APK — a finger is either on a face or not on it — and | ||
| 1191 | - ;; `just flutter-desktop` has a mouse, so the machine under them is the | ||
| 1192 | - ;; shared one now. Nothing reaches them on the phone anyway: the screens | ||
| 1193 | - ;; ask `desktop?` before they hang a hover on a face at all. | ||
| 1194 | - :hovering (fn [] @profile/hovering) | ||
| 1195 | - :profile-hover! (fn [nick actor] | ||
| 1196 | - (avatars/fetch! actor bump!) | ||
| 1197 | - (profile/hover! nick actor)) | ||
| 1198 | - :profile-unhover! profile/unhover! | ||
| 1199 | - :profile-enter-dialog! profile/enter-dialog! | ||
| 1200 | - :profile-leave-dialog! profile/leave-dialog! | ||
| 1201 | ;; Their profile on the web, handed to the browser the same way the | 1185 | ;; Their profile on the web, handed to the browser the same way the |
| 1202 | ;; sign-in link is. | 1186 | ;; sign-in link is. |
| 1203 | :open-url! (fn [url] (fio/open-url! url)) | 1187 | :open-url! (fn [url] (fio/open-url! url)) |
modified
src/frq/app.clj +3 -9 | @@ -25,7 +25,7 @@ | ||
| 25 | 25 | [frq.glyphs :as glyphs] |
| 26 | 26 | [frq.media :as media] |
| 27 | 27 | [frq.platform :as platform] |
| 28 | - [frq.profile.pointer :as profile] | |
| 28 | + [frq.profile.host :as profile] | |
| 29 | 29 | ;; The connect screen lives in common/ now — the same file the |
| 30 | 30 | ;; phone renders. It reads frq.cells and calls frq.actions, and |
| 31 | 31 | ;; this requires it exactly where its own copy used to be. |
| @@ -208,18 +208,12 @@ | ||
| 208 | 208 | {:avatar-path (fn [actor] @(avatar-path actor)) |
| 209 | 209 | :image-path (fn [url] @(image-path url)) |
| 210 | 210 | ;; The profile half lives here rather than in frq.state, which does not |
| 211 | - ;; require frq.profile — who is hovered and whose card is open is a question | |
| 212 | - ;; about the screen, not about the connection. | |
| 213 | - :hovering (fn [] @profile/hovering) | |
| 211 | + ;; require frq.profile — whose card is open is a question about the screen, | |
| 212 | + ;; not about the connection. | |
| 214 | 213 | :viewing (fn [] @profile/viewing) |
| 215 | - :profile-hover! profile/hover! | |
| 216 | - :profile-unhover! profile/unhover! | |
| 217 | 214 | :profile-open! profile/open! |
| 218 | 215 | :profile-close! profile/close! |
| 219 | - :profile-dismiss! profile/dismiss! | |
| 220 | - :profile-enter-dialog! profile/enter-dialog! | |
| 221 | 216 | :profile-entry profile/entry |
| 222 | - :profile-leave-dialog! profile/leave-dialog! | |
| 223 | 217 | :profile-stats-line profile/stats-line |
| 224 | 218 | :profile-tick (fn [] @profile/tick) |
| 225 | 219 | :profile-truncate profile/truncate |
| @@ -25,7 +25,7 @@ | |||
| 25 | [frq.glyphs :as glyphs] | 25 | [frq.glyphs :as glyphs] |
| 26 | [frq.media :as media] | 26 | [frq.media :as media] |
| 27 | [frq.platform :as platform] | 27 | [frq.platform :as platform] |
| 28 | - [frq.profile.pointer :as profile] | 28 | + [frq.profile.host :as profile] |
| 29 | ;; The connect screen lives in common/ now — the same file the | 29 | ;; The connect screen lives in common/ now — the same file the |
| 30 | ;; phone renders. It reads frq.cells and calls frq.actions, and | 30 | ;; phone renders. It reads frq.cells and calls frq.actions, and |
| 31 | ;; this requires it exactly where its own copy used to be. | 31 | ;; this requires it exactly where its own copy used to be. |
| @@ -208,18 +208,12 @@ | |||
| 208 | {:avatar-path (fn [actor] @(avatar-path actor)) | 208 | {:avatar-path (fn [actor] @(avatar-path actor)) |
| 209 | :image-path (fn [url] @(image-path url)) | 209 | :image-path (fn [url] @(image-path url)) |
| 210 | ;; The profile half lives here rather than in frq.state, which does not | 210 | ;; The profile half lives here rather than in frq.state, which does not |
| 211 | - ;; require frq.profile — who is hovered and whose card is open is a question | 211 | + ;; require frq.profile — whose card is open is a question about the screen, |
| 212 | - ;; about the screen, not about the connection. | 212 | + ;; not about the connection. |
| 213 | - :hovering (fn [] @profile/hovering) | ||
| 214 | :viewing (fn [] @profile/viewing) | 213 | :viewing (fn [] @profile/viewing) |
| 215 | - :profile-hover! profile/hover! | ||
| 216 | - :profile-unhover! profile/unhover! | ||
| 217 | :profile-open! profile/open! | 214 | :profile-open! profile/open! |
| 218 | :profile-close! profile/close! | 215 | :profile-close! profile/close! |
| 219 | - :profile-dismiss! profile/dismiss! | ||
| 220 | - :profile-enter-dialog! profile/enter-dialog! | ||
| 221 | :profile-entry profile/entry | 216 | :profile-entry profile/entry |
| 222 | - :profile-leave-dialog! profile/leave-dialog! | ||
| 223 | :profile-stats-line profile/stats-line | 217 | :profile-stats-line profile/stats-line |
| 224 | :profile-tick (fn [] @profile/tick) | 218 | :profile-tick (fn [] @profile/tick) |
| 225 | :profile-truncate profile/truncate | 219 | :profile-truncate profile/truncate |
modified
src/frq/io/jolt.clj +1 -5 | @@ -118,8 +118,4 @@ | ||
| 118 | 118 | :utf8-string (fn [bs] (String. (byte-array (map unchecked-byte bs)))) |
| 119 | 119 | :wall-nanos host/wall-nanos |
| 120 | 120 | :mono-nanos host/mono-nanos |
| 121 | - :local-offset-seconds (fn [secs] (host/tz-offset-seconds @zone secs)) | |
| 122 | - ;; The window's own timer and not a thread that sleeps: a callback that | |
| 123 | - ;; repaints has to arrive on the thread the toolkit draws from, and | |
| 124 | - ;; `frq.platform` is where each backend lends this one its loop. | |
| 125 | - :after! platform/after!}) | |
| 121 | + :local-offset-seconds (fn [secs] (host/tz-offset-seconds @zone secs))}) | |
| @@ -118,8 +118,4 @@ | |||
| 118 | :utf8-string (fn [bs] (String. (byte-array (map unchecked-byte bs)))) | 118 | :utf8-string (fn [bs] (String. (byte-array (map unchecked-byte bs)))) |
| 119 | :wall-nanos host/wall-nanos | 119 | :wall-nanos host/wall-nanos |
| 120 | :mono-nanos host/mono-nanos | 120 | :mono-nanos host/mono-nanos |
| 121 | - :local-offset-seconds (fn [secs] (host/tz-offset-seconds @zone secs)) | 121 | + :local-offset-seconds (fn [secs] (host/tz-offset-seconds @zone secs))}) |
| 122 | - ;; The window's own timer and not a thread that sleeps: a callback that | ||
| 123 | - ;; repaints has to arrive on the thread the toolkit draws from, and | ||
| 124 | - ;; `frq.platform` is where each backend lends this one its loop. | ||
| 125 | - :after! platform/after!}) | ||
renamed
src/frq/profile/host.clj +6 -23 | similarity index 54% | ||
| rename from src/frq/profile/pointer.clj | ||
| rename to src/frq/profile/host.clj | ||
| @@ -1,18 +1,12 @@ | ||
| 1 | -(ns frq.profile.pointer | |
| 1 | +(ns frq.profile.host | |
| 2 | 2 | "How this half fetches a profile, and the picture that goes with one. |
| 3 | 3 | |
| 4 | 4 | `frq.profile` under common/ is what a profile *is* — the cache, the fields, |
| 5 | - the URL, the counts — and what a pointer does about one: hovering a face, the | |
| 6 | - grace period for crossing to the card, the card reporting its own pointer. | |
| 7 | - All of that used to be here, on the reading that a pointer meant libcosmic. | |
| 8 | - It does not: `just flutter-desktop` is a window with a mouse in it too, and | |
| 9 | - the machine was a few atoms and a timer. It moved, and `frq.io/after!` took | |
| 10 | - the timer with it. | |
| 11 | - | |
| 12 | - What is left is the two things that genuinely differ by host. The fetch, | |
| 13 | - because a `future` and a blocking request is this backend's answer to a | |
| 14 | - question the other one answers by awaiting. And the avatar, because the | |
| 15 | - desktop downloads a file where the phone hands over a CDN URL. | |
| 5 | + the URL, the counts, and the press that opens one. What is left here is the | |
| 6 | + two things that genuinely differ by host. The fetch, because a `future` and a | |
| 7 | + blocking request is this backend's answer to a question the other one answers | |
| 8 | + by awaiting. And the avatar, because the desktop downloads a file where the | |
| 9 | + phone hands over a CDN URL. | |
| 16 | 10 | |
| 17 | 11 | The shared names are re-exported so callers did not have to move." |
| 18 | 12 | (:require [frq.atproto :as atproto] |
| @@ -20,17 +14,12 @@ | ||
| 20 | 14 | [frq.profile :as profile])) |
| 21 | 15 | |
| 22 | 16 | (def viewing profile/viewing) |
| 23 | -(def hovering profile/hovering) | |
| 24 | 17 | (def tick profile/tick) |
| 25 | 18 | (def entry profile/entry) |
| 26 | 19 | (def close! profile/close!) |
| 27 | -(def dismiss! profile/dismiss!) | |
| 28 | 20 | (def web-url profile/web-url) |
| 29 | 21 | (def stats-line profile/stats-line) |
| 30 | 22 | (def truncate profile/truncate) |
| 31 | -(def enter-dialog! profile/enter-dialog!) | |
| 32 | -(def leave-dialog! profile/leave-dialog!) | |
| 33 | -(def unhover! profile/unhover!) | |
| 34 | 23 | |
| 35 | 24 | (profile/install-fetch! |
| 36 | 25 | (fn [actor] |
| @@ -54,9 +43,3 @@ | ||
| 54 | 43 | [nick actor] |
| 55 | 44 | (with-avatar! actor) |
| 56 | 45 | (profile/open! nick actor)) |
| 57 | - | |
| 58 | -(defn hover! | |
| 59 | - "The pointer has come to rest on someone's face." | |
| 60 | - [nick actor] | |
| 61 | - (with-avatar! actor) | |
| 62 | - (profile/hover! nick actor)) | |
| similarity index 54% | |||
| rename from src/frq/profile/pointer.clj | |||
| rename to src/frq/profile/host.clj | |||
| @@ -1,18 +1,12 @@ | |||
| 1 | -(ns frq.profile.pointer | 1 | +(ns frq.profile.host |
| 2 | "How this half fetches a profile, and the picture that goes with one. | 2 | "How this half fetches a profile, and the picture that goes with one. |
| 3 | 3 | ||
| 4 | `frq.profile` under common/ is what a profile *is* — the cache, the fields, | 4 | `frq.profile` under common/ is what a profile *is* — the cache, the fields, |
| 5 | - the URL, the counts — and what a pointer does about one: hovering a face, the | 5 | + the URL, the counts, and the press that opens one. What is left here is the |
| 6 | - grace period for crossing to the card, the card reporting its own pointer. | 6 | + two things that genuinely differ by host. The fetch, because a `future` and a |
| 7 | - All of that used to be here, on the reading that a pointer meant libcosmic. | 7 | + blocking request is this backend's answer to a question the other one answers |
| 8 | - It does not: `just flutter-desktop` is a window with a mouse in it too, and | 8 | + by awaiting. And the avatar, because the desktop downloads a file where the |
| 9 | - the machine was a few atoms and a timer. It moved, and `frq.io/after!` took | 9 | + phone hands over a CDN URL. |
| 10 | - the timer with it. | ||
| 11 | - | ||
| 12 | - What is left is the two things that genuinely differ by host. The fetch, | ||
| 13 | - because a `future` and a blocking request is this backend's answer to a | ||
| 14 | - question the other one answers by awaiting. And the avatar, because the | ||
| 15 | - desktop downloads a file where the phone hands over a CDN URL. | ||
| 16 | 10 | ||
| 17 | The shared names are re-exported so callers did not have to move." | 11 | The shared names are re-exported so callers did not have to move." |
| 18 | (:require [frq.atproto :as atproto] | 12 | (:require [frq.atproto :as atproto] |
| @@ -20,17 +14,12 @@ | |||
| 20 | [frq.profile :as profile])) | 14 | [frq.profile :as profile])) |
| 21 | 15 | ||
| 22 | (def viewing profile/viewing) | 16 | (def viewing profile/viewing) |
| 23 | -(def hovering profile/hovering) | ||
| 24 | (def tick profile/tick) | 17 | (def tick profile/tick) |
| 25 | (def entry profile/entry) | 18 | (def entry profile/entry) |
| 26 | (def close! profile/close!) | 19 | (def close! profile/close!) |
| 27 | -(def dismiss! profile/dismiss!) | ||
| 28 | (def web-url profile/web-url) | 20 | (def web-url profile/web-url) |
| 29 | (def stats-line profile/stats-line) | 21 | (def stats-line profile/stats-line) |
| 30 | (def truncate profile/truncate) | 22 | (def truncate profile/truncate) |
| 31 | -(def enter-dialog! profile/enter-dialog!) | ||
| 32 | -(def leave-dialog! profile/leave-dialog!) | ||
| 33 | -(def unhover! profile/unhover!) | ||
| 34 | 23 | ||
| 35 | (profile/install-fetch! | 24 | (profile/install-fetch! |
| 36 | (fn [actor] | 25 | (fn [actor] |
| @@ -54,9 +43,3 @@ | |||
| 54 | [nick actor] | 43 | [nick actor] |
| 55 | (with-avatar! actor) | 44 | (with-avatar! actor) |
| 56 | (profile/open! nick actor)) | 45 | (profile/open! nick actor)) |
| 57 | - | ||
| 58 | -(defn hover! | ||
| 59 | - "The pointer has come to rest on someone's face." | ||
| 60 | - [nick actor] | ||
| 61 | - (with-avatar! actor) | ||
| 62 | - (profile/hover! nick actor)) | ||