Commit Graph
13 Commits
Author SHA1 Message Date
michel 9595afe9fb fix(rooms): harden chat-room parsing and TUI state from review findings
Adversarial review of the chat-rooms feature surfaced seven confirmed
issues; all fixed with regression tests:

lib (DoS hardening — a malicious/MITM server could send a tiny frame
with a ~4-billion element count):
- room_list: bound the name/count vector loops by remaining payload.
- join_room: bound the member-list loop the same way.

TUI (soulseek-rs/src/models/rooms.rs, ui):
- a message for a room we already left no longer resurrects its tab
  (route via open_index, not ensure_open).
- closing a tab now clears the unread badge on the room we land on.
- a room-list refresh keeps the highlight on the same room across a
  re-sort (track selection by name, not index).
- Esc in the room list clears a lingering filter before closing, matching
  the title's 'Esc: clear' hint.
- chat log renders one row per line so the newest message is never
  clipped by wrapping.
2026-07-19 20:15:42 +02:00
michel 08272ac867 feat(tui): chat rooms — browsable list, multiple open rooms, unread badges
Add a chat-rooms popup (open with 'c') satisfying the requested UX:
- Browsable, /-filterable room list showing per-room user counts,
  busiest first; already-open rooms are marked.
- Multiple rooms open at once as tabs; Tab/Shift-Tab switch, 'x' leaves.
- Per-room chat log with a live member list and an inline compose line
  (Enter to type, Enter to send; the server echo renders the message).
- Unread indicators: bold tab name + 'room (n)' badge per room, plus
  'chat (n)' and 'inbox (n)' counters in the shortcut bar; viewing a
  room clears its badge.

RoomsState is unit-tested (routing, unread accounting, tab lifecycle,
filtering).
2026-07-19 19:58:32 +02:00
michel aa8f4182d3 feat(tui): hierarchical browse tree with file/folder downloads
Wire browsing a user's shared files into the TUI as a modal tree popup:
- press 'b' on a highlighted search result to browse that result's owner, or
  'b' elsewhere to type a username (new CommandBarMode::Browse);
- a new models/browse.rs synthesizes the flat SharedDirectory list into a
  nested, collapsible tree (intermediate folders reconstructed from the
  backslash paths; file download paths kept byte-exact from the original names),
  with expand/collapse state and a flatten-to-rows renderer — fully unit-tested;
- the popup polls take_browse_result each tick (with a timeout), navigates with
  arrows/hjkl, expands/collapses folders, and queues downloads: Enter on a file,
  'd' on a file or an entire folder subtree (recursively) — all funneled into
  the existing Downloads pane;
- shortcuts bar advertises browse keys and surfaces our own sharing status.
2026-07-19 19:27:05 +02:00
michel 05b06ec2ec feat(tui): compose and read private messages
Add private messaging to the TUI:
- 'm' opens the command bar in message mode; type '<recipient> <text>' and
  Enter sends it via the client;
- incoming messages are polled each tick into an inbox;
- 'i' toggles a centered inbox popup listing sent/received messages.

The shared command bar now carries a mode (search vs message) so the prefix,
submit action and shortcut hints follow what is being typed.
2026-07-19 13:38:36 +02:00
michel e72c8a5c07 style: crank clippy to pedantic+nursery and fix all lints
Enable the full clippy all + pedantic + nursery groups as workspace warnings,
with a small documented allow-list for the pedantic/nursery lints this project
intentionally does not follow (rustdoc-style requirements, deliberate numeric
casts in the protocol/UI layers, and a few noisy nursery lints). Also enable
the rust unused_lifetimes and unsafe_op_in_unsafe_fn lints.

Fixed every resulting warning (527 -> 0) mechanically per clippy's suggestions:
inline format args, const fns, item ordering, let-else, redundant clones,
map_or, cast_lossless, Eq derives, associated-fn conversions for methods that
never used self, and removing unnecessary Result wrappers whose call sites could
never propagate an error. No runtime behavior changed; cargo fmt applied.

cargo clippy --workspace --all-targets: 0 warnings. All tests pass.
2026-07-19 00:09:17 +02:00
michel bdaeb33a4f fix: TUI selection underflow and filtered-results desync
Three related TUI correctness bugs:

- download_selector navigation (select_previous/next/last) computed
  items.len() - 1, panicking with an arithmetic underflow when the list was
  empty (e.g. a filter matched nothing). Index math is now in wrap-safe
  helpers that return no selection for an empty list.

- update_search_results overwrote the filtered results view with the full
  unfiltered list on every ~100ms poll, so an active filter silently stopped
  working as new results streamed in. It now re-derives the filtered view
  from the current query.

- The results pane rendered selection checkboxes by testing the display-row
  index against a selection set that stores unfiltered indices, so under an
  active filter the wrong rows showed as checked. It now maps the display
  index back through the filtered-index table.

Filtering and index-mapping logic extracted into pure, unit-tested helpers.
2026-07-18 14:30:02 +02:00
michel 574833bf61 feat: add download info pane to TUI
Splits the downloads area 60/40 with a new info pane that adapts to the
selected download's status: header (filename, user, size, status, save
path, bitrate, length) plus queued-specific fields (queue position, peer
slots, peer upload speed) or live progress/speed/ETA when transferring.

Plumbs queue position via a new ClientOperation::PlaceInQueueUpdate so
PlaceInQueueResponse messages from peers reach DownloadStore, and threads
search-time metadata (bitrate, length, peer slots/speed) onto Download
through a new download_with_metadata entry point.
2026-04-26 17:19:26 +02:00
michel 807dea5f17 Fix TUI search cursor editing 2026-04-26 11:43:44 +02:00
Michel de Graaf dfe6f532fa chore: formatting 2026-01-04 20:37:03 +01:00
Michel de Graaf bb86e50b4f fix: queuing downloads 2025-11-19 08:27:50 +01:00
Michel de Graaf 4c6d7c6850 chore: refactor UI to use Downloads struct 2025-11-18 14:33:33 +01:00
Michel de Graaf 9a4ad6c38a feat: main TUI 2025-11-13 14:12:37 +01:00
Michel de Graaf 5816d9b632 chore: refactor CLI app with new modules for seperation of concerns, reusable components and consistent styling 2025-11-12 02:02:35 +01:00