Closes the cleanest remaining #356 gap — Discover submits Lidarr
requests but had no surface for users to view or cancel their own.
Admin had it; user didn't.
- RequestsApi at lib/api/endpoints/requests.dart — listMine() +
cancel(id). Same /api/requests endpoint the web /requests page
uses; identical AdminRequest wire shape so the existing model
is reused (just augmented with matched_*_id fields for the
"Listen" CTA on completed rows).
- MyRequestsController mirrors the web's auto-poll (#369 piece
already shipped server-side / web-side): 12s refresh while any
row is mid-ingest (status='approved'), stops on settle. Riverpod
Timer in build() that's cancelled in onDispose.
- RequestsScreen with kind/status pills, ingest progress copy,
Cancel (with confirm dialog) and Listen CTAs per row state.
- Route /requests under the shell. Entry point in settings between
Profile and Appearance — "My requests".
- Widget tests cover empty / pending / completed / rejected states +
the Cancel-confirm dialog.
Out of scope this slice: Discover-screen "View your requests" CTA
after submitting a new request. Reasonable follow-up but doesn't
block the management loop.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hand-rolled to match the server's actual JSON shapes:
- AdminRequest carries user_id (UUID, not username); kind switches
which title field is the display name
- AdminQuarantineItem aggregates reports per track with reason_counts
and a nested reports[] list, mirroring adminQueueRowView
- AdminUser includes display_name + auto_approve_requests
- Invite uses invited_by UUID + note (server hardcodes 24h TTL)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>