feat(w7): recently-joined rooms list with one-click rejoin (P5)
Add a purely-local, most-recent-first recents list so users can hop back
into a room they were just in — meaningful now that rooms carry cosmetic
labels.
- src/recents.rs (new): `Recent {name, ticket, joined_at}`, `push_recent`
(de-dupes by room `topic_id`, refresh-and-move-to-front, caps at
RECENTS_MAX=12), `remove_recent`, `relative_time` ("5m ago"). 6 tests.
- PeerSpeakTicket::topic_of — the stable room identity used as the de-dup
key (host addr + label change between members/sessions; topic doesn't).
- AppConfig.recents (`#[serde(default)]`, back-compat) — local UI state,
never sent over the wire.
- Recorded on RoomJoined (label via label_of); rendered as a "Recent
rooms" block in connect_card (each entry → JoinRecent, ✕ → RemoveRecent),
shown only when non-empty.
Rejoin is best-effort by design: the stored ticket only admits us while
the room is still live and reachable (reliability is P6 discovery + the
member-issued ticket floor, not this list).
263 lib tests green, clippy --all-targets clean. Recents UI
screenshot-verified (seeded config → ages + Untitled-room fallback render).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -227,6 +227,11 @@ pub struct AppConfig {
|
||||
/// Empty / unset = look it up on `$PATH`. Hand-editable; no Settings UI yet.
|
||||
#[serde(default)]
|
||||
pub pixelpass_path: Option<String>,
|
||||
/// Recently-joined rooms (W7), most-recent-first. Purely local UI state for a
|
||||
/// one-click rejoin; never sent over the wire. De-duped by room topic and
|
||||
/// capped (see `recents`). Defaulted empty so older configs upgrade cleanly.
|
||||
#[serde(default)]
|
||||
pub recents: Vec<crate::recents::Recent>,
|
||||
/// Last window size (px), restored as the initial size on next launch.
|
||||
/// Saved on close.
|
||||
#[serde(default = "default_window_width")]
|
||||
@@ -281,6 +286,7 @@ impl Default for AppConfig {
|
||||
sound_mic_toggle_enabled: true,
|
||||
sound_reconnect_failed_enabled: true,
|
||||
pixelpass_path: None,
|
||||
recents: Vec::new(),
|
||||
window_width: default_window_width(),
|
||||
window_height: default_window_height(),
|
||||
window_x: None,
|
||||
@@ -403,6 +409,8 @@ mod tests {
|
||||
// Configs predating the remembered window size load the default size.
|
||||
assert_eq!(deserialized.window_width, 900.0);
|
||||
assert_eq!(deserialized.window_height, 760.0);
|
||||
// Configs predating the recents list load an empty list.
|
||||
assert!(deserialized.recents.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user