Send the filter names ipx actually understands (#6)

The Pinned tab was not filtering. It sent filter=pinned, and Filter::parse
in db.rs knows unread, downloaded, flagged and in_progress and falls
through to All for anything else -- so the tab returned every item and
looked like it had worked. The column is still named flagged, for what it
was before the interface called it pinned, and the page had this right all
along.

Currently Listening was worse in kind. ipx has filter=in_progress for
exactly it: started past the first few seconds, short of the 90% the UI
calls finished, measured against the length this person's player reported
where there is one. The client asked for everything and trimmed the fifty
rows it happened to receive, so the view showed whichever started episodes
were near the top of the library, left out the rest, and counted wrong.

Both came of writing the filter names from the interface's words instead of
reading what the server parses.

The tests now assert what each filter means rather than how many rows it
returns -- every unread row unread, every downloaded row with a file, every
pinned row pinned, every in-progress row started -- because the failure
here was a full page of entirely plausible rows, which no count would have
caught. Pinned also has to match fewer than everything, which is the shape
the bug took.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-20 09:56:28 -04:00
parent 33c3790fe3
commit 14170fe5aa
4 changed files with 64 additions and 11 deletions

View File

@@ -100,20 +100,19 @@ final class LibraryStore: ObservableObject {
do {
// Currently Listening is not a feed; it is the started-but-unfinished filter, which
// the page reaches through the same route.
// Currently Listening is the server's in_progress filter, not a pass over the page
// we happened to receive: trimming fifty rows here showed whichever started episodes
// were near the top of the library and quietly left out the rest.
let page = try await api.entries(
feed: place.feedId,
filter: place == .listening ? .all : filter,
filter: place == .listening ? .inProgress : filter,
search: search,
sort: sort,
direction: direction,
offset: offset)
guard !Task.isCancelled else { return }
var rows = offset == 0 ? page.entries : entries + page.entries
if place == .listening {
rows = rows.filter { $0.position > 0 && !$0.read }
}
entries = rows
total = place == .listening ? rows.count : page.total
entries = offset == 0 ? page.entries : entries + page.entries
total = page.total
failure = nil
} catch is CancellationError {
} catch {