Mechanical sweep across 30 files: every Material Icons.* replaced with
the signed-off Lucide equivalent + a flutter_lucide import per file.
Zero Material Icons.* remain in lib/; no unused imports.
Judgment-call mappings: album->disc_3, library_music->library_big,
playlist_play->list_video, graphic_eq->audio_lines,
system_update->download, restore->archive_restore,
download_done->circle_check_big.
track_actions_sheet like menu row: collapsed `liked ? favorite :
favorite_border` to a single LucideIcons.heart (the row's Like/Unlike
text label conveys state). Icon-only LikeButton + the notification keep
the filled-vs-outline shape per the design decision.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#392's dispatcher only invalidates publicly-importable providers
(myQuarantine + home). Screen-scoped providers (file-private in their
feature folders) get their own ref.listen(liveEventsProvider, ...) so
they go live without needing back-edge dependencies from /shared.
Five screens wired:
- library_screen.dart _LikedTab — invalidates _likedTracksProvider /
_likedAlbumsProvider / _likedArtistsProvider on any of the six
track/album/artist like/unlike kinds.
- playlist_detail_screen.dart — invalidates playlistDetailProvider(id)
on playlist.updated / playlist.tracks_changed matching the visible
playlist_id. On playlist.deleted matching the visible id, pops back
so the user isn't left staring at a gone playlist.
- admin_requests_screen.dart — invalidates adminRequestsProvider on
request.status_changed (covers user create/cancel + admin
approve/reject + reconciler complete).
- admin_quarantine_screen.dart — invalidates adminQuarantineProvider
on any quarantine.* event (flag from a user / admin resolve / file
delete / lidarr delete).
- requests_screen.dart (own requests) — invalidates myRequestsProvider
on request.status_changed. Server-side events are user-scoped via
publishRequestStatusChanged's row.UserID, so admin actions on
someone else's request route to the right stream.
History tab is NOT wired (no server-side play.scrobbled event yet —
documented in #402 body as deferred until that event ships).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>