Let the reader turn off comings and goings
Other people joining, leaving and quitting is how you notice a quiet room filling up, and what a busy one drowns in — so it is a setting rather than a decision. Only other people's: your own "Joined #chan" answers something you just did. The people panel still follows who is here either way. Kept in prefs.edn beside the channel list — names and flags, not a credential, so an ordinary file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
da84772 parent: 49162f1 modified
src/frq/app.jolt +10 -2 | @@ -1234,6 +1234,12 @@ | ||
| 1234 | 1234 | [:button {:label "Disconnect" :kind :destructive :on-click s/disconnect!}] |
| 1235 | 1235 | [:button {:label "Back to connect" |
| 1236 | 1236 | :on-click #(reset! s/screen :connect)}])]] |
| 1237 | + [:card {} | |
| 1238 | + [:title-2 {:label "Messages"}] | |
| 1239 | + [:checkbutton {:label "Hide join/part messages" | |
| 1240 | + :active @s/hide-join-part? | |
| 1241 | + :on-toggled s/toggle-hide-join-part!}] | |
| 1242 | + [:dim-label {:label "Hides other people arriving, leaving and quitting. The people panel still follows who is here."}]] | |
| 1237 | 1243 | [:card {} |
| 1238 | 1244 | [:title-2 {:label "frq"}] |
| 1239 | 1245 | [:dim-label {:label "freeq client in jolt — glimmer components on the Vidya/egui backend."}] |
| @@ -1261,8 +1267,10 @@ | ||
| 1261 | 1267 | [chats-screen]))) |
| 1262 | 1268 | |
| 1263 | 1269 | (defn -main [& _] |
| 1264 | - ;; Before the window: the rooms this client has been in, and a saved sign-in | |
| 1265 | - ;; deciding which mode the connect screen opens in and what it says. | |
| 1270 | + ;; Before the window: the settings, the rooms this client has been in, and a | |
| 1271 | + ;; saved sign-in deciding which mode the connect screen opens in and what it | |
| 1272 | + ;; says. | |
| 1273 | + (s/restore-prefs!) | |
| 1266 | 1274 | (s/restore-channels!) |
| 1267 | 1275 | (when (s/restore-session!) |
| 1268 | 1276 | ;; And then it connects on its own. A remembered account has already said |
| @@ -1234,6 +1234,12 @@ | |||
| 1234 | [:button {:label "Disconnect" :kind :destructive :on-click s/disconnect!}] | 1234 | [:button {:label "Disconnect" :kind :destructive :on-click s/disconnect!}] |
| 1235 | [:button {:label "Back to connect" | 1235 | [:button {:label "Back to connect" |
| 1236 | :on-click #(reset! s/screen :connect)}])]] | 1236 | :on-click #(reset! s/screen :connect)}])]] |
| 1237 | + [:card {} | ||
| 1238 | + [:title-2 {:label "Messages"}] | ||
| 1239 | + [:checkbutton {:label "Hide join/part messages" | ||
| 1240 | + :active @s/hide-join-part? | ||
| 1241 | + :on-toggled s/toggle-hide-join-part!}] | ||
| 1242 | + [:dim-label {:label "Hides other people arriving, leaving and quitting. The people panel still follows who is here."}]] | ||
| 1237 | [:card {} | 1243 | [:card {} |
| 1238 | [:title-2 {:label "frq"}] | 1244 | [:title-2 {:label "frq"}] |
| 1239 | [:dim-label {:label "freeq client in jolt — glimmer components on the Vidya/egui backend."}] | 1245 | [:dim-label {:label "freeq client in jolt — glimmer components on the Vidya/egui backend."}] |
| @@ -1261,8 +1267,10 @@ | |||
| 1261 | [chats-screen]))) | 1267 | [chats-screen]))) |
| 1262 | 1268 | ||
| 1263 | (defn -main [& _] | 1269 | (defn -main [& _] |
| 1264 | - ;; Before the window: the rooms this client has been in, and a saved sign-in | 1270 | + ;; Before the window: the settings, the rooms this client has been in, and a |
| 1265 | - ;; deciding which mode the connect screen opens in and what it says. | 1271 | + ;; saved sign-in deciding which mode the connect screen opens in and what it |
| 1272 | + ;; says. | ||
| 1273 | + (s/restore-prefs!) | ||
| 1266 | (s/restore-channels!) | 1274 | (s/restore-channels!) |
| 1267 | (when (s/restore-session!) | 1275 | (when (s/restore-session!) |
| 1268 | ;; And then it connects on its own. A remembered account has already said | 1276 | ;; And then it connects on its own. A remembered account has already said |
modified
src/frq/state.jolt +28 -4 | @@ -146,6 +146,27 @@ | ||
| 146 | 146 | (defonce access-tick (atom 0)) |
| 147 | 147 | (defonce search (atom "")) |
| 148 | 148 | |
| 149 | +;; Comings and goings, hidden or not. A quiet room reads better with them — | |
| 150 | +;; they are how you notice someone arriving — and a busy one drowns in them, | |
| 151 | +;; so it is the reader's call. Only other people's: your own "Joined #chan" is | |
| 152 | +;; the answer to something you just did. | |
| 153 | +(defonce hide-join-part? (atom false)) | |
| 154 | + | |
| 155 | +(defn- save-prefs! [] | |
| 156 | + (future (store/save-prefs! (assoc (store/load-prefs) | |
| 157 | + :hide-join-part? @hide-join-part?)))) | |
| 158 | + | |
| 159 | +(defn toggle-hide-join-part! [] | |
| 160 | + (swap! hide-join-part? not) | |
| 161 | + (save-prefs!)) | |
| 162 | + | |
| 163 | +(defn restore-prefs! | |
| 164 | + "Bring back the saved settings at startup." | |
| 165 | + [] | |
| 166 | + (let [prefs (store/load-prefs)] | |
| 167 | + (reset! hide-join-part? (boolean (:hide-join-part? prefs))) | |
| 168 | + prefs)) | |
| 169 | + | |
| 149 | 170 | (defn connected? [] (some? @conn)) |
| 150 | 171 | |
| 151 | 172 | (declare channel-order request-names!) |
| @@ -656,7 +677,8 @@ | ||
| 656 | 677 | ;; already there is just a second line of noise. |
| 657 | 678 | (when fresh? (push-message! ch "*" (str "Joined " ch)))) |
| 658 | 679 | (do (add-user! ch from) |
| 659 | - (push-message! ch "*" (str from " joined"))))) | |
| 680 | + (when-not @hide-join-part? | |
| 681 | + (push-message! ch "*" (str from " joined")))))) | |
| 660 | 682 | ;; NAMES, a line at a time. The channel is the parameter that names one: |
| 661 | 683 | ;; the reply is `<us> <symbol> <channel> :<names>`, and a server that |
| 662 | 684 | ;; leaves the symbol out shifts everything before the list along by one. |
| @@ -679,7 +701,8 @@ | ||
| 679 | 701 | (assoc-in [ch :joining?] false) |
| 680 | 702 | (assoc-in [ch :users] {}))) |
| 681 | 703 | (do (remove-user! ch from) |
| 682 | - (push-message! ch "*" (str from " left"))))) | |
| 704 | + (when-not @hide-join-part? | |
| 705 | + (push-message! ch "*" (str from " left")))))) | |
| 683 | 706 | "KICK" (let [[ch who] params] |
| 684 | 707 | (if (= who @form-nick) |
| 685 | 708 | (swap! channels #(-> % (assoc-in [ch :joined?] false) |
| @@ -691,8 +714,9 @@ | ||
| 691 | 714 | ;; buffer the person was listed in — and said out loud only where they |
| 692 | 715 | ;; were, which is what keeps a stranger's rename out of a quiet room. |
| 693 | 716 | "QUIT" (let [rooms (keep (fn [[k v]] (when (get (:users v) from) k)) @channels)] |
| 694 | - (doseq [ch rooms] | |
| 695 | - (push-message! ch "*" (str from " quit"))) | |
| 717 | + (when-not @hide-join-part? | |
| 718 | + (doseq [ch rooms] | |
| 719 | + (push-message! ch "*" (str from " quit")))) | |
| 696 | 720 | (remove-user-everywhere! from)) |
| 697 | 721 | "NICK" (let [new-nick (last params) |
| 698 | 722 | rooms (keep (fn [[k v]] (when (get (:users v) from) k)) @channels)] |
| @@ -146,6 +146,27 @@ | |||
| 146 | (defonce access-tick (atom 0)) | 146 | (defonce access-tick (atom 0)) |
| 147 | (defonce search (atom "")) | 147 | (defonce search (atom "")) |
| 148 | 148 | ||
| 149 | +;; Comings and goings, hidden or not. A quiet room reads better with them — | ||
| 150 | +;; they are how you notice someone arriving — and a busy one drowns in them, | ||
| 151 | +;; so it is the reader's call. Only other people's: your own "Joined #chan" is | ||
| 152 | +;; the answer to something you just did. | ||
| 153 | +(defonce hide-join-part? (atom false)) | ||
| 154 | + | ||
| 155 | +(defn- save-prefs! [] | ||
| 156 | + (future (store/save-prefs! (assoc (store/load-prefs) | ||
| 157 | + :hide-join-part? @hide-join-part?)))) | ||
| 158 | + | ||
| 159 | +(defn toggle-hide-join-part! [] | ||
| 160 | + (swap! hide-join-part? not) | ||
| 161 | + (save-prefs!)) | ||
| 162 | + | ||
| 163 | +(defn restore-prefs! | ||
| 164 | + "Bring back the saved settings at startup." | ||
| 165 | + [] | ||
| 166 | + (let [prefs (store/load-prefs)] | ||
| 167 | + (reset! hide-join-part? (boolean (:hide-join-part? prefs))) | ||
| 168 | + prefs)) | ||
| 169 | + | ||
| 149 | (defn connected? [] (some? @conn)) | 170 | (defn connected? [] (some? @conn)) |
| 150 | 171 | ||
| 151 | (declare channel-order request-names!) | 172 | (declare channel-order request-names!) |
| @@ -656,7 +677,8 @@ | |||
| 656 | ;; already there is just a second line of noise. | 677 | ;; already there is just a second line of noise. |
| 657 | (when fresh? (push-message! ch "*" (str "Joined " ch)))) | 678 | (when fresh? (push-message! ch "*" (str "Joined " ch)))) |
| 658 | (do (add-user! ch from) | 679 | (do (add-user! ch from) |
| 659 | - (push-message! ch "*" (str from " joined"))))) | 680 | + (when-not @hide-join-part? |
| 681 | + (push-message! ch "*" (str from " joined")))))) | ||
| 660 | ;; NAMES, a line at a time. The channel is the parameter that names one: | 682 | ;; NAMES, a line at a time. The channel is the parameter that names one: |
| 661 | ;; the reply is `<us> <symbol> <channel> :<names>`, and a server that | 683 | ;; the reply is `<us> <symbol> <channel> :<names>`, and a server that |
| 662 | ;; leaves the symbol out shifts everything before the list along by one. | 684 | ;; leaves the symbol out shifts everything before the list along by one. |
| @@ -679,7 +701,8 @@ | |||
| 679 | (assoc-in [ch :joining?] false) | 701 | (assoc-in [ch :joining?] false) |
| 680 | (assoc-in [ch :users] {}))) | 702 | (assoc-in [ch :users] {}))) |
| 681 | (do (remove-user! ch from) | 703 | (do (remove-user! ch from) |
| 682 | - (push-message! ch "*" (str from " left"))))) | 704 | + (when-not @hide-join-part? |
| 705 | + (push-message! ch "*" (str from " left")))))) | ||
| 683 | "KICK" (let [[ch who] params] | 706 | "KICK" (let [[ch who] params] |
| 684 | (if (= who @form-nick) | 707 | (if (= who @form-nick) |
| 685 | (swap! channels #(-> % (assoc-in [ch :joined?] false) | 708 | (swap! channels #(-> % (assoc-in [ch :joined?] false) |
| @@ -691,8 +714,9 @@ | |||
| 691 | ;; buffer the person was listed in — and said out loud only where they | 714 | ;; buffer the person was listed in — and said out loud only where they |
| 692 | ;; were, which is what keeps a stranger's rename out of a quiet room. | 715 | ;; were, which is what keeps a stranger's rename out of a quiet room. |
| 693 | "QUIT" (let [rooms (keep (fn [[k v]] (when (get (:users v) from) k)) @channels)] | 716 | "QUIT" (let [rooms (keep (fn [[k v]] (when (get (:users v) from) k)) @channels)] |
| 694 | - (doseq [ch rooms] | 717 | + (when-not @hide-join-part? |
| 695 | - (push-message! ch "*" (str from " quit"))) | 718 | + (doseq [ch rooms] |
| 719 | + (push-message! ch "*" (str from " quit")))) | ||
| 696 | (remove-user-everywhere! from)) | 720 | (remove-user-everywhere! from)) |
| 697 | "NICK" (let [new-nick (last params) | 721 | "NICK" (let [new-nick (last params) |
| 698 | rooms (keep (fn [[k v]] (when (get (:users v) from) k)) @channels)] | 722 | rooms (keep (fn [[k v]] (when (get (:users v) from) k)) @channels)] |
modified
src/frq/store.jolt +26 -0 | @@ -71,3 +71,29 @@ | ||
| 71 | 71 | (host/delete-file! (session-file))) |
| 72 | 72 | true |
| 73 | 73 | (catch Exception _ false))) |
| 74 | + | |
| 75 | +(defn prefs-file [] (str (config-dir) "/prefs.edn")) | |
| 76 | + | |
| 77 | +(defn load-prefs | |
| 78 | + "The user's settings, or an empty map. Like the channel list beside it these | |
| 79 | + are names and flags rather than secrets, so it is an ordinary file — and one | |
| 80 | + that will not parse is treated as absent rather than as an error worth | |
| 81 | + stopping the launch for." | |
| 82 | + [] | |
| 83 | + (let [path (prefs-file)] | |
| 84 | + (or (when (host/file-exists? path) | |
| 85 | + (try | |
| 86 | + (let [m (edn/read-string (slurp path))] | |
| 87 | + (when (map? m) m)) | |
| 88 | + (catch Exception _ nil))) | |
| 89 | + {}))) | |
| 90 | + | |
| 91 | +(defn save-prefs! | |
| 92 | + "Write the settings map whole. There are few enough of them that merging is | |
| 93 | + the caller's job, and a partial write would silently drop the rest." | |
| 94 | + [prefs] | |
| 95 | + (try | |
| 96 | + (host/mkdirs! (config-dir)) | |
| 97 | + (spit (prefs-file) (pr-str prefs)) | |
| 98 | + true | |
| 99 | + (catch Exception _ false))) | |
| @@ -71,3 +71,29 @@ | |||
| 71 | (host/delete-file! (session-file))) | 71 | (host/delete-file! (session-file))) |
| 72 | true | 72 | true |
| 73 | (catch Exception _ false))) | 73 | (catch Exception _ false))) |
| 74 | + | ||
| 75 | +(defn prefs-file [] (str (config-dir) "/prefs.edn")) | ||
| 76 | + | ||
| 77 | +(defn load-prefs | ||
| 78 | + "The user's settings, or an empty map. Like the channel list beside it these | ||
| 79 | + are names and flags rather than secrets, so it is an ordinary file — and one | ||
| 80 | + that will not parse is treated as absent rather than as an error worth | ||
| 81 | + stopping the launch for." | ||
| 82 | + [] | ||
| 83 | + (let [path (prefs-file)] | ||
| 84 | + (or (when (host/file-exists? path) | ||
| 85 | + (try | ||
| 86 | + (let [m (edn/read-string (slurp path))] | ||
| 87 | + (when (map? m) m)) | ||
| 88 | + (catch Exception _ nil))) | ||
| 89 | + {}))) | ||
| 90 | + | ||
| 91 | +(defn save-prefs! | ||
| 92 | + "Write the settings map whole. There are few enough of them that merging is | ||
| 93 | + the caller's job, and a partial write would silently drop the rest." | ||
| 94 | + [prefs] | ||
| 95 | + (try | ||
| 96 | + (host/mkdirs! (config-dir)) | ||
| 97 | + (spit (prefs-file) (pr-str prefs)) | ||
| 98 | + true | ||
| 99 | + (catch Exception _ false))) | ||