Commit Graph
12 Commits
Author SHA1 Message Date
Michel de Graaf 1b4c3f3531 refactor: trim the folder mark's allocations and indirection
The unmarked-folder span and size string allocated per row per frame
for nothing, and a filter/map_or_else chain built a string that only
one state ever fills. A matches! fills it directly.
2026-09-10 09:55:04 +02:00
Michel de Graaf cfa81120ef feat: folders in the browse tree carry their download's mark too
A folder queued from the browse tree is really the queue of every file
under it, so its row reports the loudest status among those files:
working while anything moves, paused, queued, a failure once quiet, and
✓ only when every file is done. A working folder shows the percent the
queued bytes have come in its size cell.
2026-09-10 09:48:41 +02:00
Michel de Graaf 0703f22ad7 refactor: drop the per-row String behind the browse marker's gap
Span::raw takes a &'static str; the to_string allocated for every
unmarked row of every frame. Points the doc comment at the Downloads
pane, which is what actually marks downloads.
2026-09-10 09:23:18 +02:00
Michel de Graaf 3a49c551ea feat: mark browsed files with their download status
Queueing a file or folder from a user's browse tree left no trace in
the window it was queued from. A row whose download is in the transfer
list now carries the same status glyph the Downloads pane uses —
⋯ queued, ↯ active, ⏸ paused, ✓ done — and an active row shows its
percent beside the size. Folders mark through their files: queue a
folder and watch the ✓ spread down it.
2026-09-10 09:18:44 +02:00
Michel de Graaf 0cacc8cc10 refactor(tui): one page window and one filter editor for every list
Four panes had grown the same dance around ratatui's table: clamp the
selection, take the visible page, hand the table a page-local state,
keep the page start. It is now page_window and render_page in a paging
module beside page_of, and the two popups page by the same count they
draw, tab bar or header included.

Five typed filters had grown the same key handling too. edit_filter now
takes a key for all of them, which also stops a control or alt chord
from typing its letter into a filter, stops Enter, which keeps a filter,
from resetting the view it is over, and lets the results and room-list
filters page like the others. Their titles and the typing shortcuts
come from one place as well.
2026-09-08 11:24:59 +02:00
Michel de Graaf b8da8668b4 feat(tui): folder jumps, open-all and a path filter in the browse popup
A browsed share only moved a row at a time, so a folder of a few
hundred files stood between the user and the next folder. J and K now
jump between folder rows, H and L close or open every folder, and /
filters the whole tree by path the way the results and the room list
filter: type to narrow, Enter keeps it, Esc clears it, then hides. A
folder under a filter shows the paths that match and d downloads just
those. The keys popup gains a browse section and the bar lists them.
2026-09-08 11:24:41 +02:00
Michel de Graaf 0931bb01b4 perf(tui): flatten a browsed share once and draw one page of it
Moving through a browsed share felt laggy for the same reason the
results did: the popup re-flattened the whole expanded tree on every
frame, cloning every row's name and path, then built a table row for
each, and every keypress flattened it twice more. A heavy sharer's
tree runs to tens of thousands of rows once a few folders are open.

The flattened rows now live on the browse state and are rebuilt only
when a folder opens or closes, and the popup draws the visible page
alone. In the harness a 30,000-row tree went from 11ms to 0.35ms a
frame and a keypress from 2.7ms to under a microsecond.

The downloads pane had the same shape (every transfer became a row
each frame, and a select-all can queue ten thousand), so it takes the
same page window, which now lives beside page_of for every pane to
share.
2026-09-08 11:24:36 +02:00
Michel de Graaf c6d41796c9 feat(tui): give the panes the colour the demo promised
The cursor row set a foreground, and ratatui only skips a cell's colour
when that field is None — so selecting a row repainted its gold sizes,
blue usernames and status glyphs into one flat cream. Table cursors now
tint the background only, over a warm oxide wash instead of neutral.

Browse files, their sizes and the settings popup rendered in the raw
terminal foreground; they take the palette now, and free slots read
green when a peer has one.
2026-07-25 03:44:07 +02:00
Michel de Graaf 105c798855 feat(ui): theme the TUI with the soulseek-rs design system
Replace the ANSI Light* palette with the design system's tokens
(tokens/colors.css): oxide accent, phosphor focus, tape/signal/alarm
semantics, paper text on dust chrome. Only foregrounds and the row
highlight are painted so the user's terminal background shows through.

Route every bordered pane through a single pane_block() helper carrying
one column of horizontal padding, and give legends a consistent
[n] Title form with the tag in signal. The command bar now derives its
cursor position from the block's inner rect instead of a hardcoded
border offset.

Also collapses the download-status glyph match that was duplicated
across three render sites into download_status_glyph().
2026-07-24 21:18:20 +02:00
michel e59c2bc199 fix(tui): make browse retry work and de-jargon the copy
- Retry actually retries: 'r' in the browse popup re-requests a
  timed-out user (previously the 'Press b to retry' hint did nothing —
  b wasn't handled inside the popup). BrowseTabs::retry_active is
  unit-tested.
- Friendlier timeout copy that explains the likely cause: "Couldn't
  reach <user>. They may be offline, or their connection can't be
  reached (both of you may be behind a router/firewall). Press r to try
  again."
- Replace protocol terminology in user-facing labels: 'Peer slots' ->
  'Free slots', 'Peer upload speed' -> 'Upload speed'.
2026-07-19 20:49:32 +02:00
michel 60896619d7 feat(tui): tabbed browsing — browse several users at once
Replace the single browse view with BrowseTabs (one tab per user),
mirroring the chat-room tabs. Browsing a new user (from search results
or a chat room's member list) opens or focuses their tab; Tab/Shift-Tab
switch between open users, 'w' closes the active tab, Esc hides the
popup while keeping the tabs. A tab bar shows the open users when more
than one is open, and each tab polls/loads independently. Re-browsing a
timed-out user retries. BrowseTabs is unit-tested.
2026-07-19 20:38:34 +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