feat: in-room text chat over the gossip plane

Add room text chat riding the existing iroh-gossip topic (same layer as the
presence roster). New GossipMessage::Chat { name, text, ts }; the gossip loop
forwards it as RoomEvent::ChatMessage, core relays it to the UI as
UiEvent::ChatMessage, and RoomState::send_chat broadcasts an authored line
(display name from self-state, ms timestamp). CoreCommand::SendChat sends; our
own author is suppressed by the existing self-echo guard, so the UI echoes our
sent line locally instead.

UI: a full-width chat dock along the bottom of the room (the chosen layout) —
bottom-anchored scrollback with per-sender name colouring (green = you), an
input with Enter-to-send + a Send button, history capped at 300 lines. The room
window default grows to 900x760 so the dock doesn't squeeze the controls column.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 21:55:49 -04:00
co-authored by Claude Opus 4.8
parent c3cf00f46f
commit a6aca73c67
5 changed files with 179 additions and 6 deletions
+5
View File
@@ -29,6 +29,8 @@ pub enum CoreCommand {
/// Start/stop recording the call to a local WAV (your mic + the incoming
/// mix). No-op start if already recording / not in a call.
SetRecording(bool),
/// Broadcast a room text-chat message. No-op when not in a call.
SendChat(String),
}
#[derive(Debug, Clone)]
@@ -51,5 +53,8 @@ pub enum UiEvent {
RecordingStarted { path: String },
/// Call recording stopped; carries the finished WAV path.
RecordingStopped { path: String },
/// A room text-chat message arrived from a peer (never our own — local
/// messages are echoed by the UI on send).
ChatMessage { name: String, text: String },
Error(String),
}