Let the Flutter build split a wide window too
The split view has been in common/frq/screens/app.cljc all along — the row with the list in one pane and the conversation in the other — and the Flutter backend answered :wide? with a flat false, so it never appeared. A laptop window ran the phone layout at any size: one screen at a time, with inches of margin either side of it. note-window-size! has been filling window-width in since the pictures needed it, so the question the desktop asks is askable here: the same comparison against the same threshold, which moves to frq.cells so two backends cannot drift apart on the number. Three things hang on it, not one. wide? is what app.cljc branches on, but opening a room has to stop trading the list away for the conversation when both fit, and an arriving line has to count as read while the room is the pane beside the list — so open-room! picks its screen the way frq.state does, and the PRIVMSG handler asks chat-visible? rather than the screen alone. Not gated on Platform.isAndroid: a tablet held the long way has the room and a desktop window dragged narrow has not. The width is the whole of it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
131c6db parent: f03729c modified
common/frq/cells.cljc +12 -0 | @@ -160,6 +160,18 @@ | ||
| 160 | 160 | ;; list and the conversation are both on screen instead of taking turns. |
| 161 | 161 | (defonce window-width (atom 0)) |
| 162 | 162 | |
| 163 | +;; Where the second pane starts paying for itself. Below this a 320pt list | |
| 164 | +;; beside a conversation leaves the messages narrower than the phone layout | |
| 165 | +;; they were written for. | |
| 166 | +;; | |
| 167 | +;; Here rather than in a backend because both of them answer `wide?` with it: | |
| 168 | +;; libcosmic measures its window, Flutter reads MediaQuery, and the terminal | |
| 169 | +;; multiplies its columns back up to points — three ways of filling | |
| 170 | +;; `window-width` in, one width they are all compared against. Two backends | |
| 171 | +;; drifting apart on the number would be two different apps out of the same | |
| 172 | +;; screens. | |
| 173 | +(def wide-width 900) | |
| 174 | + | |
| 163 | 175 | ;; ------------------------------------------------------------- derivation |
| 164 | 176 | |
| 165 | 177 | (defonce ^:private derived-cells |
| @@ -160,6 +160,18 @@ | |||
| 160 | ;; list and the conversation are both on screen instead of taking turns. | 160 | ;; list and the conversation are both on screen instead of taking turns. |
| 161 | (defonce window-width (atom 0)) | 161 | (defonce window-width (atom 0)) |
| 162 | 162 | ||
| 163 | +;; Where the second pane starts paying for itself. Below this a 320pt list | ||
| 164 | +;; beside a conversation leaves the messages narrower than the phone layout | ||
| 165 | +;; they were written for. | ||
| 166 | +;; | ||
| 167 | +;; Here rather than in a backend because both of them answer `wide?` with it: | ||
| 168 | +;; libcosmic measures its window, Flutter reads MediaQuery, and the terminal | ||
| 169 | +;; multiplies its columns back up to points — three ways of filling | ||
| 170 | +;; `window-width` in, one width they are all compared against. Two backends | ||
| 171 | +;; drifting apart on the number would be two different apps out of the same | ||
| 172 | +;; screens. | ||
| 173 | +(def wide-width 900) | ||
| 174 | + | ||
| 163 | ;; ------------------------------------------------------------- derivation | 175 | ;; ------------------------------------------------------------- derivation |
| 164 | 176 | ||
| 165 | (defonce ^:private derived-cells | 177 | (defonce ^:private derived-cells |
modified
flutter/src/frq/main.cljd +32 -3 | @@ -197,6 +197,32 @@ | ||
| 197 | 197 | (net/send-line! c (str "JOIN " name)))) |
| 198 | 198 | nil) |
| 199 | 199 | |
| 200 | +(defn- wide? | |
| 201 | + "True while the window has room for the list and a conversation at once. | |
| 202 | + | |
| 203 | + `note-window-size!` above is what fills `window-width` in, so this is the | |
| 204 | + same question `frq.state/wide?` answers on the desktop, asked of the same | |
| 205 | + number against the same threshold. It used to answer a flat false and the | |
| 206 | + Flutter build had one screen at a time at every size — which on a laptop | |
| 207 | + window is a phone with several inches of margin either side. | |
| 208 | + | |
| 209 | + Not desktop-only: `Platform.isAndroid` is the wrong question here, because a | |
| 210 | + tablet held the long way has the room and a desktop window dragged narrow | |
| 211 | + has not. The width is the whole of it." | |
| 212 | + [] | |
| 213 | + (>= @cells/window-width cells/wide-width)) | |
| 214 | + | |
| 215 | +(defn- chat-visible? | |
| 216 | + "Whether the room in `current` is on screen. | |
| 217 | + | |
| 218 | + Narrow that is the chat screen alone; wide it is the chats screen too, since | |
| 219 | + the conversation is the pane beside the list there. This and not the screen | |
| 220 | + is what decides whether an arriving line counts as read." | |
| 221 | + [name] | |
| 222 | + (and (= name @cells/current) | |
| 223 | + (or (= :chat @cells/screen) | |
| 224 | + (and (wide?) (= :chats @cells/screen))))) | |
| 225 | + | |
| 200 | 226 | (defn- open-room! |
| 201 | 227 | "Show a buffer, joining it on the way. A row can outlive the membership |
| 202 | 228 | behind it — a disconnect drops every channel and the buffer stays — so |
| @@ -222,7 +248,10 @@ | ||
| 222 | 248 | #(-> (rooms/ensure-channel % name) |
| 223 | 249 | (update name rooms/mark-read) |
| 224 | 250 | (assoc-in [name :accessed] (swap! rooms/access-tick inc)))) |
| 225 | - (reset! cells/screen :chat) | |
| 251 | + ;; On a wide window the conversation is the chats screen's second pane, so | |
| 252 | + ;; the list stays: `:chat` is the narrow window's way of showing the room | |
| 253 | + ;; *instead* of the list, and beside it there is nothing to trade away. | |
| 254 | + (reset! cells/screen (if (wide?) :chats :chat)) | |
| 226 | 255 | ;; Worth a write of its own: the order the list is read in is the order |
| 227 | 256 | ;; rooms were last opened, and this is the moment it changes. |
| 228 | 257 | (remember-rooms! true) |
| @@ -371,7 +400,7 @@ | ||
| 371 | 400 | ;; Reading a room is marking it read: a line arriving in the room |
| 372 | 401 | ;; on screen moves the marker past itself, and one arriving |
| 373 | 402 | ;; anywhere else is counted against the marker there. |
| 374 | - viewing? (and (= :chat @cells/screen) (= name @cells/current)) | |
| 403 | + viewing? (chat-visible? name) | |
| 375 | 404 | settle (fn [m] (update m name (if viewing? |
| 376 | 405 | rooms/mark-read |
| 377 | 406 | rooms/recount)))] |
| @@ -1157,7 +1186,7 @@ | ||
| 1157 | 1186 | ;; will serve again, a picture in a message is whatever host a stranger |
| 1158 | 1187 | ;; put a link to. |
| 1159 | 1188 | :image-path (fn [url] (media/path-when-ready url)) |
| 1160 | - :wide? (fn [] false) | |
| 1189 | + :wide? wide? | |
| 1161 | 1190 | ;; True where there is a pointer to hover with. Both Flutter targets |
| 1162 | 1191 | ;; compile this file, so it is asked rather than assumed: a window on the |
| 1163 | 1192 | ;; desktop has a mouse, Android has a finger. |
| @@ -197,6 +197,32 @@ | |||
| 197 | (net/send-line! c (str "JOIN " name)))) | 197 | (net/send-line! c (str "JOIN " name)))) |
| 198 | nil) | 198 | nil) |
| 199 | 199 | ||
| 200 | +(defn- wide? | ||
| 201 | + "True while the window has room for the list and a conversation at once. | ||
| 202 | + | ||
| 203 | + `note-window-size!` above is what fills `window-width` in, so this is the | ||
| 204 | + same question `frq.state/wide?` answers on the desktop, asked of the same | ||
| 205 | + number against the same threshold. It used to answer a flat false and the | ||
| 206 | + Flutter build had one screen at a time at every size — which on a laptop | ||
| 207 | + window is a phone with several inches of margin either side. | ||
| 208 | + | ||
| 209 | + Not desktop-only: `Platform.isAndroid` is the wrong question here, because a | ||
| 210 | + tablet held the long way has the room and a desktop window dragged narrow | ||
| 211 | + has not. The width is the whole of it." | ||
| 212 | + [] | ||
| 213 | + (>= @cells/window-width cells/wide-width)) | ||
| 214 | + | ||
| 215 | +(defn- chat-visible? | ||
| 216 | + "Whether the room in `current` is on screen. | ||
| 217 | + | ||
| 218 | + Narrow that is the chat screen alone; wide it is the chats screen too, since | ||
| 219 | + the conversation is the pane beside the list there. This and not the screen | ||
| 220 | + is what decides whether an arriving line counts as read." | ||
| 221 | + [name] | ||
| 222 | + (and (= name @cells/current) | ||
| 223 | + (or (= :chat @cells/screen) | ||
| 224 | + (and (wide?) (= :chats @cells/screen))))) | ||
| 225 | + | ||
| 200 | (defn- open-room! | 226 | (defn- open-room! |
| 201 | "Show a buffer, joining it on the way. A row can outlive the membership | 227 | "Show a buffer, joining it on the way. A row can outlive the membership |
| 202 | behind it — a disconnect drops every channel and the buffer stays — so | 228 | behind it — a disconnect drops every channel and the buffer stays — so |
| @@ -222,7 +248,10 @@ | |||
| 222 | #(-> (rooms/ensure-channel % name) | 248 | #(-> (rooms/ensure-channel % name) |
| 223 | (update name rooms/mark-read) | 249 | (update name rooms/mark-read) |
| 224 | (assoc-in [name :accessed] (swap! rooms/access-tick inc)))) | 250 | (assoc-in [name :accessed] (swap! rooms/access-tick inc)))) |
| 225 | - (reset! cells/screen :chat) | 251 | + ;; On a wide window the conversation is the chats screen's second pane, so |
| 252 | + ;; the list stays: `:chat` is the narrow window's way of showing the room | ||
| 253 | + ;; *instead* of the list, and beside it there is nothing to trade away. | ||
| 254 | + (reset! cells/screen (if (wide?) :chats :chat)) | ||
| 226 | ;; Worth a write of its own: the order the list is read in is the order | 255 | ;; Worth a write of its own: the order the list is read in is the order |
| 227 | ;; rooms were last opened, and this is the moment it changes. | 256 | ;; rooms were last opened, and this is the moment it changes. |
| 228 | (remember-rooms! true) | 257 | (remember-rooms! true) |
| @@ -371,7 +400,7 @@ | |||
| 371 | ;; Reading a room is marking it read: a line arriving in the room | 400 | ;; Reading a room is marking it read: a line arriving in the room |
| 372 | ;; on screen moves the marker past itself, and one arriving | 401 | ;; on screen moves the marker past itself, and one arriving |
| 373 | ;; anywhere else is counted against the marker there. | 402 | ;; anywhere else is counted against the marker there. |
| 374 | - viewing? (and (= :chat @cells/screen) (= name @cells/current)) | 403 | + viewing? (chat-visible? name) |
| 375 | settle (fn [m] (update m name (if viewing? | 404 | settle (fn [m] (update m name (if viewing? |
| 376 | rooms/mark-read | 405 | rooms/mark-read |
| 377 | rooms/recount)))] | 406 | rooms/recount)))] |
| @@ -1157,7 +1186,7 @@ | |||
| 1157 | ;; will serve again, a picture in a message is whatever host a stranger | 1186 | ;; will serve again, a picture in a message is whatever host a stranger |
| 1158 | ;; put a link to. | 1187 | ;; put a link to. |
| 1159 | :image-path (fn [url] (media/path-when-ready url)) | 1188 | :image-path (fn [url] (media/path-when-ready url)) |
| 1160 | - :wide? (fn [] false) | 1189 | + :wide? wide? |
| 1161 | ;; True where there is a pointer to hover with. Both Flutter targets | 1190 | ;; True where there is a pointer to hover with. Both Flutter targets |
| 1162 | ;; compile this file, so it is asked rather than assumed: a window on the | 1191 | ;; compile this file, so it is asked rather than assumed: a window on the |
| 1163 | ;; desktop has a mouse, Android has a finger. | 1192 | ;; desktop has a mouse, Android has a finger. |
modified
src/frq/state.clj +3 -4 | @@ -126,10 +126,9 @@ | ||
| 126 | 126 | |
| 127 | 127 | (def window-height cells/window-height) |
| 128 | 128 | |
| 129 | -;; Where the second pane starts paying for itself. Below this a 300pt list | |
| 130 | -;; beside a conversation leaves the messages narrower than the phone layout | |
| 131 | -;; they were written for. | |
| 132 | -(def wide-width 900) | |
| 129 | +;; Where the second pane starts paying for itself, shared with the other | |
| 130 | +;; backends — see `frq.cells/wide-width`. | |
| 131 | +(def wide-width cells/wide-width) | |
| 133 | 132 | |
| 134 | 133 | (defn wide? |
| 135 | 134 | "True while the window has room for the list and a conversation at once." |
| @@ -126,10 +126,9 @@ | |||
| 126 | 126 | ||
| 127 | (def window-height cells/window-height) | 127 | (def window-height cells/window-height) |
| 128 | 128 | ||
| 129 | -;; Where the second pane starts paying for itself. Below this a 300pt list | 129 | +;; Where the second pane starts paying for itself, shared with the other |
| 130 | -;; beside a conversation leaves the messages narrower than the phone layout | 130 | +;; backends — see `frq.cells/wide-width`. |
| 131 | -;; they were written for. | 131 | +(def wide-width cells/wide-width) |
| 132 | -(def wide-width 900) | ||
| 133 | 132 | ||
| 134 | (defn wide? | 133 | (defn wide? |
| 135 | "True while the window has room for the list and a conversation at once." | 134 | "True while the window has room for the list and a conversation at once." |