Show the overview strip on the Flutter side too
The strip itself was already shared — `frq.screens.chat/overview-pane` draws it, and the toggle beside People turned `cells/overview?` on here as well. It came up empty and the row buttons went nowhere, because the three things under it were `frq.state`'s and nothing answered them on this half: `recent-everywhere` was a private def in the jolt namespace, and `leaving-for-overview!`, `overview-back!` and `after!` were installed only there. `frq.actions` makes a missing key a no-op, so none of that was an error — it was a heading, a separator, and "Nothing has been said in any other room yet." over rooms that had plenty. `recent-everywhere` and its round-robin move to `frq.rooms`, beside `channel-list` and `last-preview`, which they belong with: it is a read over `cells/channels` and `cells/current` and nothing else, so it was shared code sitting on the wrong side of the boundary. `frq.state` re-defs it the way it re-defs the other three, and the jolt half is unchanged. `after!` is the one that is not a query. The strip's rows jump across rooms, and the jump lets go of the scroll target one frame later and clears the mark five seconds after that — without it the view stays pinned where the jump put it and the reader cannot scroll away. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5f32523 parent: 795fda4 modified
common/frq/rooms.cljc +62 -2 | @@ -3,8 +3,9 @@ | ||
| 3 | 3 | |
| 4 | 4 | Pure, and so shared: `channel-list` is a filter and a sort over |
| 5 | 5 | `frq.cells/channels` and the search box, `dm?` is a question about a name, |
| 6 | - `last-preview` reads the last message of a buffer. `frq.state` re-defs all | |
| 7 | - three, so the thousand lines below them did not move." | |
| 6 | + `last-preview` reads the last message of a buffer, `recent-everywhere` is | |
| 7 | + the overview strip's list of what is happening in every other room. `frq.state` | |
| 8 | + re-defs them all, so the thousand lines below them did not move." | |
| 8 | 9 | (:require [clojure.string :as str] |
| 9 | 10 | [frq.cells :as cells])) |
| 10 | 11 | |
| @@ -66,3 +67,62 @@ | ||
| 66 | 67 | (seq (or (:from m) "")) |
| 67 | 68 | (= (str/lower-case (:from m)) |
| 68 | 69 | (str/lower-case (or me ""))))) |
| 70 | + | |
| 71 | + | |
| 72 | +;; How many lines the overview holds in all. | |
| 73 | +(def overview-limit 100) | |
| 74 | + | |
| 75 | +(defn- round-robin | |
| 76 | + "The colls' firsts, then their seconds, and so on until they are spent. | |
| 77 | + | |
| 78 | + This is how the overview stays about every room while still being a fixed | |
| 79 | + number of lines. Taking the newest hundred outright would be the strip | |
| 80 | + answering about whichever room is busiest — which is the one you can already | |
| 81 | + see. A turn each means a room that said one thing all day is in the first | |
| 82 | + handful, beside the room that has said a hundred." | |
| 83 | + [colls] | |
| 84 | + (lazy-seq | |
| 85 | + (let [colls (remove empty? colls)] | |
| 86 | + (when (seq colls) | |
| 87 | + (concat (map first colls) | |
| 88 | + (round-robin (map rest colls))))))) | |
| 89 | + | |
| 90 | +(defn recent-everywhere | |
| 91 | + "The newest lines from every buffer at once, newest first, and at most | |
| 92 | + `overview-limit` of them — a turn to each room until they run out. | |
| 93 | + | |
| 94 | + Each carries the room it was said in, since that is the one thing a line | |
| 95 | + taken out of its own conversation no longer says for itself. | |
| 96 | + | |
| 97 | + Bounded per room before anything else, so the cost is the number of rooms | |
| 98 | + rather than the length of their backlogs: a channel with a week of history | |
| 99 | + in it must not make this the most expensive thing on the screen. | |
| 100 | + | |
| 101 | + Joins, parts and the rest of the system's own chatter are left out. They are | |
| 102 | + the noise this strip would drown in: a room nobody has spoken in for a day | |
| 103 | + still reports everyone who came and went in it. | |
| 104 | + | |
| 105 | + So is the room being read. It is on the screen already, in full, directly | |
| 106 | + above — repeating its last three lines under itself spends the strip's room | |
| 107 | + saying what the conversation just said, and what the strip is for is the | |
| 108 | + rooms you are not looking at." | |
| 109 | + [] | |
| 110 | + (->> (dissoc @cells/channels @cells/current) | |
| 111 | + (map (fn [[name buffer]] | |
| 112 | + ;; Newest first, which is the order a turn each has to be taken | |
| 113 | + ;; in: the first round is every room's latest line. | |
| 114 | + (->> (:messages buffer) | |
| 115 | + (remove :system?) | |
| 116 | + (take-last overview-limit) | |
| 117 | + reverse | |
| 118 | + (map #(assoc % :channel name))))) | |
| 119 | + (remove empty?) | |
| 120 | + round-robin | |
| 121 | + (take overview-limit) | |
| 122 | + ;; Newest at the top, which is the other way round from a conversation | |
| 123 | + ;; and right for the same reason a conversation is the way it is: what | |
| 124 | + ;; you came to the strip for is what has just happened, and a list you | |
| 125 | + ;; have to scroll to the bottom of to find it is a list that answers | |
| 126 | + ;; last. The turn-taking above is about which lines are in it, not | |
| 127 | + ;; about where they sit. | |
| 128 | + (sort-by #(or (:at %) 0) >))) | |
| @@ -3,8 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | Pure, and so shared: `channel-list` is a filter and a sort over | 4 | Pure, and so shared: `channel-list` is a filter and a sort over |
| 5 | `frq.cells/channels` and the search box, `dm?` is a question about a name, | 5 | `frq.cells/channels` and the search box, `dm?` is a question about a name, |
| 6 | - `last-preview` reads the last message of a buffer. `frq.state` re-defs all | 6 | + `last-preview` reads the last message of a buffer, `recent-everywhere` is |
| 7 | - three, so the thousand lines below them did not move." | 7 | + the overview strip's list of what is happening in every other room. `frq.state` |
| 8 | + re-defs them all, so the thousand lines below them did not move." | ||
| 8 | (:require [clojure.string :as str] | 9 | (:require [clojure.string :as str] |
| 9 | [frq.cells :as cells])) | 10 | [frq.cells :as cells])) |
| 10 | 11 | ||
| @@ -66,3 +67,62 @@ | |||
| 66 | (seq (or (:from m) "")) | 67 | (seq (or (:from m) "")) |
| 67 | (= (str/lower-case (:from m)) | 68 | (= (str/lower-case (:from m)) |
| 68 | (str/lower-case (or me ""))))) | 69 | (str/lower-case (or me ""))))) |
| 70 | + | ||
| 71 | + | ||
| 72 | +;; How many lines the overview holds in all. | ||
| 73 | +(def overview-limit 100) | ||
| 74 | + | ||
| 75 | +(defn- round-robin | ||
| 76 | + "The colls' firsts, then their seconds, and so on until they are spent. | ||
| 77 | + | ||
| 78 | + This is how the overview stays about every room while still being a fixed | ||
| 79 | + number of lines. Taking the newest hundred outright would be the strip | ||
| 80 | + answering about whichever room is busiest — which is the one you can already | ||
| 81 | + see. A turn each means a room that said one thing all day is in the first | ||
| 82 | + handful, beside the room that has said a hundred." | ||
| 83 | + [colls] | ||
| 84 | + (lazy-seq | ||
| 85 | + (let [colls (remove empty? colls)] | ||
| 86 | + (when (seq colls) | ||
| 87 | + (concat (map first colls) | ||
| 88 | + (round-robin (map rest colls))))))) | ||
| 89 | + | ||
| 90 | +(defn recent-everywhere | ||
| 91 | + "The newest lines from every buffer at once, newest first, and at most | ||
| 92 | + `overview-limit` of them — a turn to each room until they run out. | ||
| 93 | + | ||
| 94 | + Each carries the room it was said in, since that is the one thing a line | ||
| 95 | + taken out of its own conversation no longer says for itself. | ||
| 96 | + | ||
| 97 | + Bounded per room before anything else, so the cost is the number of rooms | ||
| 98 | + rather than the length of their backlogs: a channel with a week of history | ||
| 99 | + in it must not make this the most expensive thing on the screen. | ||
| 100 | + | ||
| 101 | + Joins, parts and the rest of the system's own chatter are left out. They are | ||
| 102 | + the noise this strip would drown in: a room nobody has spoken in for a day | ||
| 103 | + still reports everyone who came and went in it. | ||
| 104 | + | ||
| 105 | + So is the room being read. It is on the screen already, in full, directly | ||
| 106 | + above — repeating its last three lines under itself spends the strip's room | ||
| 107 | + saying what the conversation just said, and what the strip is for is the | ||
| 108 | + rooms you are not looking at." | ||
| 109 | + [] | ||
| 110 | + (->> (dissoc @cells/channels @cells/current) | ||
| 111 | + (map (fn [[name buffer]] | ||
| 112 | + ;; Newest first, which is the order a turn each has to be taken | ||
| 113 | + ;; in: the first round is every room's latest line. | ||
| 114 | + (->> (:messages buffer) | ||
| 115 | + (remove :system?) | ||
| 116 | + (take-last overview-limit) | ||
| 117 | + reverse | ||
| 118 | + (map #(assoc % :channel name))))) | ||
| 119 | + (remove empty?) | ||
| 120 | + round-robin | ||
| 121 | + (take overview-limit) | ||
| 122 | + ;; Newest at the top, which is the other way round from a conversation | ||
| 123 | + ;; and right for the same reason a conversation is the way it is: what | ||
| 124 | + ;; you came to the strip for is what has just happened, and a list you | ||
| 125 | + ;; have to scroll to the bottom of to find it is a list that answers | ||
| 126 | + ;; last. The turn-taking above is about which lines are in it, not | ||
| 127 | + ;; about where they sit. | ||
| 128 | + (sort-by #(or (:at %) 0) >))) | ||
modified
flutter/src/frq/main.cljd +19 -0 | @@ -695,6 +695,25 @@ | ||
| 695 | 695 | :member-list (fn [room] (members/member-list @cells/channels room)) |
| 696 | 696 | :toggle-users! (fn [] (swap! cells/show-users? not)) |
| 697 | 697 | :toggle-overview! (fn [] (swap! cells/overview? not)) |
| 698 | + ;; What the strip is a list of: every other room's recent lines, a turn | |
| 699 | + ;; each. `frq.rooms` reads it off the cells, so both halves ask the same | |
| 700 | + ;; question of the same buffers — the desktop's is the same def. | |
| 701 | + :recent-everywhere rooms/recent-everywhere | |
| 702 | + ;; Where the reader was when a line in the strip took them out of it, | |
| 703 | + ;; and the way back to it. The room, not the place in it: one scroll | |
| 704 | + ;; position is remembered per conversation either way. | |
| 705 | + :leaving-for-overview! (fn [] (reset! cells/overview-return @cells/current)) | |
| 706 | + :overview-back! (fn [] | |
| 707 | + (when-let [room @cells/overview-return] | |
| 708 | + (reset! cells/overview-return nil) | |
| 709 | + (actions/open-channel! room))) | |
| 710 | + ;; Timers, for the two the strip's jump needs: aim the scroll, then let | |
| 711 | + ;; go of it, and clear the mark a while after that. `Future.delayed` in | |
| 712 | + ;; milliseconds, which is the unit `frq.screens.chat` asks in. | |
| 713 | + :after! (fn [ms f] | |
| 714 | + (.then (async/Future.delayed (Duration .milliseconds ms)) | |
| 715 | + (fn [_] (f) nil)) | |
| 716 | + nil) | |
| 698 | 717 | :toggle-chat-list! (fn [] (swap! cells/hide-chat-list? not)) |
| 699 | 718 | :toggle-hide-join-part! (fn [] (swap! cells/hide-join-part? not)) |
| 700 | 719 | :quit! (fn [] nil) |
| @@ -695,6 +695,25 @@ | |||
| 695 | :member-list (fn [room] (members/member-list @cells/channels room)) | 695 | :member-list (fn [room] (members/member-list @cells/channels room)) |
| 696 | :toggle-users! (fn [] (swap! cells/show-users? not)) | 696 | :toggle-users! (fn [] (swap! cells/show-users? not)) |
| 697 | :toggle-overview! (fn [] (swap! cells/overview? not)) | 697 | :toggle-overview! (fn [] (swap! cells/overview? not)) |
| 698 | + ;; What the strip is a list of: every other room's recent lines, a turn | ||
| 699 | + ;; each. `frq.rooms` reads it off the cells, so both halves ask the same | ||
| 700 | + ;; question of the same buffers — the desktop's is the same def. | ||
| 701 | + :recent-everywhere rooms/recent-everywhere | ||
| 702 | + ;; Where the reader was when a line in the strip took them out of it, | ||
| 703 | + ;; and the way back to it. The room, not the place in it: one scroll | ||
| 704 | + ;; position is remembered per conversation either way. | ||
| 705 | + :leaving-for-overview! (fn [] (reset! cells/overview-return @cells/current)) | ||
| 706 | + :overview-back! (fn [] | ||
| 707 | + (when-let [room @cells/overview-return] | ||
| 708 | + (reset! cells/overview-return nil) | ||
| 709 | + (actions/open-channel! room))) | ||
| 710 | + ;; Timers, for the two the strip's jump needs: aim the scroll, then let | ||
| 711 | + ;; go of it, and clear the mark a while after that. `Future.delayed` in | ||
| 712 | + ;; milliseconds, which is the unit `frq.screens.chat` asks in. | ||
| 713 | + :after! (fn [ms f] | ||
| 714 | + (.then (async/Future.delayed (Duration .milliseconds ms)) | ||
| 715 | + (fn [_] (f) nil)) | ||
| 716 | + nil) | ||
| 698 | :toggle-chat-list! (fn [] (swap! cells/hide-chat-list? not)) | 717 | :toggle-chat-list! (fn [] (swap! cells/hide-chat-list? not)) |
| 699 | :toggle-hide-join-part! (fn [] (swap! cells/hide-join-part? not)) | 718 | :toggle-hide-join-part! (fn [] (swap! cells/hide-join-part? not)) |
| 700 | :quit! (fn [] nil) | 719 | :quit! (fn [] nil) |
modified
src/frq/state.clj +2 -60 | @@ -1725,67 +1725,9 @@ | ||
| 1725 | 1725 | (def highlight cells/highlight) |
| 1726 | 1726 | |
| 1727 | 1727 | |
| 1728 | +(def overview-limit rooms/overview-limit) | |
| 1728 | 1729 | |
| 1729 | -;; How many lines the overview holds in all. | |
| 1730 | -(def overview-limit 100) | |
| 1731 | - | |
| 1732 | -;; How many it shows without being scrolled — the terminal's whole answer, | |
| 1733 | -;; since a strip there is a handful of rows taken off a conversation that is | |
| 1734 | -;; measured in how many of those fit. | |
| 1735 | -(defn- round-robin | |
| 1736 | - "The colls' firsts, then their seconds, and so on until they are spent. | |
| 1737 | - | |
| 1738 | - This is how the overview stays about every room while still being a fixed | |
| 1739 | - number of lines. Taking the newest hundred outright would be the strip | |
| 1740 | - answering about whichever room is busiest — which is the one you can already | |
| 1741 | - see. A turn each means a room that said one thing all day is in the first | |
| 1742 | - handful, beside the room that has said a hundred." | |
| 1743 | - [colls] | |
| 1744 | - (lazy-seq | |
| 1745 | - (let [colls (remove empty? colls)] | |
| 1746 | - (when (seq colls) | |
| 1747 | - (concat (map first colls) | |
| 1748 | - (round-robin (map rest colls))))))) | |
| 1749 | - | |
| 1750 | -(defn recent-everywhere | |
| 1751 | - "The newest lines from every buffer at once, newest first, and at most | |
| 1752 | - `overview-limit` of them — a turn to each room until they run out. | |
| 1753 | - | |
| 1754 | - Each carries the room it was said in, since that is the one thing a line | |
| 1755 | - taken out of its own conversation no longer says for itself. | |
| 1756 | - | |
| 1757 | - Bounded per room before anything else, so the cost is the number of rooms | |
| 1758 | - rather than the length of their backlogs: a channel with a week of history | |
| 1759 | - in it must not make this the most expensive thing on the screen. | |
| 1760 | - | |
| 1761 | - Joins, parts and the rest of the system's own chatter are left out. They are | |
| 1762 | - the noise this strip would drown in: a room nobody has spoken in for a day | |
| 1763 | - still reports everyone who came and went in it. | |
| 1764 | - | |
| 1765 | - So is the room being read. It is on the screen already, in full, directly | |
| 1766 | - above — repeating its last three lines under itself spends the strip's room | |
| 1767 | - saying what the conversation just said, and what the strip is for is the | |
| 1768 | - rooms you are not looking at." | |
| 1769 | - [] | |
| 1770 | - (->> (dissoc @channels @current) | |
| 1771 | - (map (fn [[name buffer]] | |
| 1772 | - ;; Newest first, which is the order a turn each has to be taken | |
| 1773 | - ;; in: the first round is every room's latest line. | |
| 1774 | - (->> (:messages buffer) | |
| 1775 | - (remove :system?) | |
| 1776 | - (take-last overview-limit) | |
| 1777 | - reverse | |
| 1778 | - (map #(assoc % :channel name))))) | |
| 1779 | - (remove empty?) | |
| 1780 | - round-robin | |
| 1781 | - (take overview-limit) | |
| 1782 | - ;; Newest at the top, which is the other way round from a conversation | |
| 1783 | - ;; and right for the same reason a conversation is the way it is: what | |
| 1784 | - ;; you came to the strip for is what has just happened, and a list you | |
| 1785 | - ;; have to scroll to the bottom of to find it is a list that answers | |
| 1786 | - ;; last. The turn-taking above is about which lines are in it, not | |
| 1787 | - ;; about where they sit. | |
| 1788 | - (sort-by #(or (:at %) 0) >))) | |
| 1730 | +(def recent-everywhere rooms/recent-everywhere) | |
| 1789 | 1731 | |
| 1790 | 1732 | (def last-preview rooms/last-preview) |
| 1791 | 1733 | |
| @@ -1725,67 +1725,9 @@ | |||
| 1725 | (def highlight cells/highlight) | 1725 | (def highlight cells/highlight) |
| 1726 | 1726 | ||
| 1727 | 1727 | ||
| 1728 | +(def overview-limit rooms/overview-limit) | ||
| 1728 | 1729 | ||
| 1729 | -;; How many lines the overview holds in all. | 1730 | +(def recent-everywhere rooms/recent-everywhere) |
| 1730 | -(def overview-limit 100) | ||
| 1731 | - | ||
| 1732 | -;; How many it shows without being scrolled — the terminal's whole answer, | ||
| 1733 | -;; since a strip there is a handful of rows taken off a conversation that is | ||
| 1734 | -;; measured in how many of those fit. | ||
| 1735 | -(defn- round-robin | ||
| 1736 | - "The colls' firsts, then their seconds, and so on until they are spent. | ||
| 1737 | - | ||
| 1738 | - This is how the overview stays about every room while still being a fixed | ||
| 1739 | - number of lines. Taking the newest hundred outright would be the strip | ||
| 1740 | - answering about whichever room is busiest — which is the one you can already | ||
| 1741 | - see. A turn each means a room that said one thing all day is in the first | ||
| 1742 | - handful, beside the room that has said a hundred." | ||
| 1743 | - [colls] | ||
| 1744 | - (lazy-seq | ||
| 1745 | - (let [colls (remove empty? colls)] | ||
| 1746 | - (when (seq colls) | ||
| 1747 | - (concat (map first colls) | ||
| 1748 | - (round-robin (map rest colls))))))) | ||
| 1749 | - | ||
| 1750 | -(defn recent-everywhere | ||
| 1751 | - "The newest lines from every buffer at once, newest first, and at most | ||
| 1752 | - `overview-limit` of them — a turn to each room until they run out. | ||
| 1753 | - | ||
| 1754 | - Each carries the room it was said in, since that is the one thing a line | ||
| 1755 | - taken out of its own conversation no longer says for itself. | ||
| 1756 | - | ||
| 1757 | - Bounded per room before anything else, so the cost is the number of rooms | ||
| 1758 | - rather than the length of their backlogs: a channel with a week of history | ||
| 1759 | - in it must not make this the most expensive thing on the screen. | ||
| 1760 | - | ||
| 1761 | - Joins, parts and the rest of the system's own chatter are left out. They are | ||
| 1762 | - the noise this strip would drown in: a room nobody has spoken in for a day | ||
| 1763 | - still reports everyone who came and went in it. | ||
| 1764 | - | ||
| 1765 | - So is the room being read. It is on the screen already, in full, directly | ||
| 1766 | - above — repeating its last three lines under itself spends the strip's room | ||
| 1767 | - saying what the conversation just said, and what the strip is for is the | ||
| 1768 | - rooms you are not looking at." | ||
| 1769 | - [] | ||
| 1770 | - (->> (dissoc @channels @current) | ||
| 1771 | - (map (fn [[name buffer]] | ||
| 1772 | - ;; Newest first, which is the order a turn each has to be taken | ||
| 1773 | - ;; in: the first round is every room's latest line. | ||
| 1774 | - (->> (:messages buffer) | ||
| 1775 | - (remove :system?) | ||
| 1776 | - (take-last overview-limit) | ||
| 1777 | - reverse | ||
| 1778 | - (map #(assoc % :channel name))))) | ||
| 1779 | - (remove empty?) | ||
| 1780 | - round-robin | ||
| 1781 | - (take overview-limit) | ||
| 1782 | - ;; Newest at the top, which is the other way round from a conversation | ||
| 1783 | - ;; and right for the same reason a conversation is the way it is: what | ||
| 1784 | - ;; you came to the strip for is what has just happened, and a list you | ||
| 1785 | - ;; have to scroll to the bottom of to find it is a list that answers | ||
| 1786 | - ;; last. The turn-taking above is about which lines are in it, not | ||
| 1787 | - ;; about where they sit. | ||
| 1788 | - (sort-by #(or (:at %) 0) >))) | ||
| 1789 | 1731 | ||
| 1790 | (def last-preview rooms/last-preview) | 1732 | (def last-preview rooms/last-preview) |
| 1791 | 1733 | ||