nandi/frqpublic Fork 0
da84772
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

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>
nandi committed 2026-09-01T20:08:47-07:00 Browse files
da84772 parent: 49162f1
modified src/frq/app.jolt +10 -2
@@ -1234,6 +1234,12 @@
12341234 [:button {:label "Disconnect" :kind :destructive :on-click s/disconnect!}]
12351235 [:button {:label "Back to connect"
12361236 :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."}]]
12371243 [:card {}
12381244 [:title-2 {:label "frq"}]
12391245 [:dim-label {:label "freeq client in jolt — glimmer components on the Vidya/egui backend."}]
@@ -1261,8 +1267,10 @@
12611267 [chats-screen])))
12621268
12631269 (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!)
12661274 (s/restore-channels!)
12671275 (when (s/restore-session!)
12681276 ;; 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-in1270+ ;; 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 said1276 ;; And then it connects on its own. A remembered account has already said
modified src/frq/state.jolt +28 -4
@@ -146,6 +146,27 @@
146146 (defonce access-tick (atom 0))
147147 (defonce search (atom ""))
148148
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+
149170 (defn connected? [] (some? @conn))
150171
151172 (declare channel-order request-names!)
@@ -656,7 +677,8 @@
656677 ;; already there is just a second line of noise.
657678 (when fresh? (push-message! ch "*" (str "Joined " ch))))
658679 (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"))))))
660682 ;; NAMES, a line at a time. The channel is the parameter that names one:
661683 ;; the reply is `<us> <symbol> <channel> :<names>`, and a server that
662684 ;; leaves the symbol out shifts everything before the list along by one.
@@ -679,7 +701,8 @@
679701 (assoc-in [ch :joining?] false)
680702 (assoc-in [ch :users] {})))
681703 (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"))))))
683706 "KICK" (let [[ch who] params]
684707 (if (= who @form-nick)
685708 (swap! channels #(-> % (assoc-in [ch :joined?] false)
@@ -691,8 +714,9 @@
691714 ;; buffer the person was listed in and said out loud only where they
692715 ;; were, which is what keeps a stranger's rename out of a quiet room.
693716 "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"))))
696720 (remove-user-everywhere! from))
697721 "NICK" (let [new-nick (last params)
698722 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 that683 ;; 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 they714 ;; 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 @@
7171 (host/delete-file! (session-file)))
7272 true
7373 (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 true72 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)))