| @@ -134,8 +134,20 @@ |
| 134 | [connect-action]] | 134 | [connect-action]] |
| 135 | [:dim-label {:label "TLS rides jolt's OpenSSL bindings; untick it for a plain :6667 listener. Sign-in needs TLS, so it is desktop-only."}]]) | 135 | [:dim-label {:label "TLS rides jolt's OpenSSL bindings; untick it for a plain :6667 listener. Sign-in needs TLS, so it is desktop-only."}]]) |
| 136 | | 136 | |
| | 137 | +;; Whether the backend under this tree is a terminal, set by `frq.tui` before |
| | 138 | +;; the first paint and never again. Two things in a message hang on it, and |
| | 139 | +;; both are about a cell grid rather than a canvas: there is no picture to |
| | 140 | +;; draw a face with, and a name with nothing to its left is the heading the |
| | 141 | +;; text hangs off — the shape a terminal has read messages in for forty years. |
| | 142 | +(defonce terminal? (atom false)) |
| | 143 | + |
| 137 | ;; ---------------------------------------------------------------- chats | 144 | ;; ---------------------------------------------------------------- chats |
| 138 | | 145 | |
| | 146 | +(defn- open-button [name] |
| | 147 | + [:button {:label "Open" |
| | 148 | + :kind :primary |
| | 149 | + :on-click #(s/open-channel! name)}]) |
| | 150 | + |
| 139 | (defn conversation-row [buffer] | 151 | (defn conversation-row [buffer] |
| 140 | (let [name (:name buffer) | 152 | (let [name (:name buffer) |
| 141 | unread (:unread buffer)] | 153 | unread (:unread buffer)] |
| @@ -147,8 +159,17 @@ |
| 147 | ;; split down two lines — while the card, sized to a row that no longer | 159 | ;; split down two lines — while the card, sized to a row that no longer |
| 148 | ;; fits, sticks out past the cards above and below it. | 160 | ;; fits, sticks out past the cards above and below it. |
| 149 | ;; | 161 | ;; |
| | 162 | + ;; In a terminal the Open button rides up onto the name's line. A row of |
| | 163 | + ;; chrome there is one cell, so a button on a line of its own costs the |
| | 164 | + ;; card a whole row — four of them and the list has spent a screenful on |
| | 165 | + ;; buttons. A window's row is 34 points and its button is a lozenge with |
| | 166 | + ;; air around it, which is why it keeps its own line there. |
| | 167 | + (if @terminal? |
| | 168 | + [:hbox {:spacing 8 :wrap false} |
| | 169 | + [:title-2 {:label name}] |
| | 170 | + [open-button name]] |
| | 171 | + [:title-2 {:label name}]) |
| 150 | ;; `:wrap false` on the badges: they sit beside each other or not at all. | 172 | ;; `:wrap false` on the badges: they sit beside each other or not at all. |
| 151 | - [:title-2 {:label name}] | | |
| 152 | [:hbox {:spacing 12 :wrap false} | 173 | [:hbox {:spacing 12 :wrap false} |
| 153 | ;; A DM has no membership to report — there is nothing to be in — so the | 174 | ;; A DM has no membership to report — there is nothing to be in — so the |
| 154 | ;; badge says what the buffer is instead of answering a question nobody | 175 | ;; badge says what the buffer is instead of answering a question nobody |
| @@ -159,7 +180,7 @@ |
| 159 | :live (boolean (:joined? buffer))}] | 180 | :live (boolean (:joined? buffer))}] |
| 160 | (when (pos? unread) [:label {:label (str "● " unread)}])] | 181 | (when (pos? unread) [:label {:label (str "● " unread)}])] |
| 161 | [:dim-label {:label (s/last-preview buffer)}] | 182 | [:dim-label {:label (s/last-preview buffer)}] |
| 162 | - [:button {:label "Open" :kind :primary :on-click #(s/open-channel! name)}]])) | 183 | + (when-not @terminal? [open-button name])])) |
| 163 | | 184 | |
| 164 | (def ^:private sidebar-width 320) | 185 | (def ^:private sidebar-width 320) |
| 165 | | 186 | |
| @@ -180,13 +201,6 @@ |
| 180 | | 201 | |
| 181 | (defn- chrome-scale [] (/ (double @chrome-row) window-row)) | 202 | (defn- chrome-scale [] (/ (double @chrome-row) window-row)) |
| 182 | | 203 | |
| 183 | -;; Whether the backend under this tree is a terminal, set by `frq.tui` before | | |
| 184 | -;; the first paint and never again. Two things in a message hang on it, and | | |
| 185 | -;; both are about a cell grid rather than a canvas: there is no picture to | | |
| 186 | -;; draw a face with, and a name with nothing to its left is the heading the | | |
| 187 | -;; text hangs off — the shape a terminal has read messages in for forty years. | | |
| 188 | -(defonce terminal? (atom false)) | | |
| 189 | - | | |
| 190 | (defn- chip-gap | 204 | (defn- chip-gap |
| 191 | "The air between two chips on a row. | 205 | "The air between two chips on a row. |
| 192 | | 206 | |
| @@ -289,7 +303,13 @@ |
| 289 | [:vbox {:key :list :fill-height true :reserve (below-list)} | 303 | [:vbox {:key :list :fill-height true :reserve (below-list)} |
| 290 | [:scroll {:scroll-key "chats-list" :orientation :vertical} | 304 | [:scroll {:scroll-key "chats-list" :orientation :vertical} |
| 291 | (if (seq buffers) | 305 | (if (seq buffers) |
| 292 | - (for [b buffers] [conversation-row b]) | 306 | + ;; Keyed on the name, because this list reorders: opening a |
| | 307 | + ;; conversation bumps it to the top, and unkeyed children reconcile by |
| | 308 | + ;; position — the widgets stay put and their props are rewritten under |
| | 309 | + ;; them. What is focused is a widget, so the highlight would stay in |
| | 310 | + ;; the slot the reader clicked while the row that moved into it is |
| | 311 | + ;; someone else's conversation. |
| | 312 | + (for [b buffers] ^{:key (:name b)} [conversation-row b]) |
| 293 | [:card {} [:dim-label {:label "No conversations yet — join a channel."}]])]] | 313 | [:card {} [:dim-label {:label "No conversations yet — join a channel."}]])]] |
| 294 | [:vbox {:key :foot :spacing 8} | 314 | [:vbox {:key :foot :spacing 8} |
| 295 | [:separator {}] | 315 | [:separator {}] |
| @@ -1158,7 +1178,10 @@ |
| 1158 | [:scroll {:scroll-key (str "users-" name) | 1178 | [:scroll {:scroll-key (str "users-" name) |
| 1159 | :orientation :vertical} | 1179 | :orientation :vertical} |
| 1160 | (if (seq people) | 1180 | (if (seq people) |
| 1161 | - (for [p people] [member-row p]) | 1181 | + ;; Keyed, for the reason the conversation list is: this list reorders |
| | 1182 | + ;; as people come and go, and a name is a button someone can be |
| | 1183 | + ;; standing on. |
| | 1184 | + (for [p people] ^{:key (:nick p)} [member-row p]) |
| 1162 | [:dim-label {:label "Nobody listed yet."}])]])) | 1185 | [:dim-label {:label "Nobody listed yet."}])]])) |
| 1163 | | 1186 | |
| 1164 | (defn chat-screen [] | 1187 | (defn chat-screen [] |