Commit Graph
891 Commits
Author SHA1 Message Date
austinried 7a0dd9aa5b show download status on the library tabs and offer it in their menus
Album tiles, artist rows and playlist rows now carry the badge (lower right on
tiles, trailing end on rows) and their long-press menus take the same bulk
Download / Cancel / Delete entries the hero uses, driven by the shared actions
rule so a partly downloaded item offers both rows and an in-flight one offers
Cancel. The artist page's album cells get the badge and album menu too.

The three list callbacks the artist menu used (and its artist-specific
view-model calls) collapse into one bulkDownload action over a MenuTarget, since
the same menu code now serves album, playlist and artist.
2026-10-04 00:30:03 +00:00
austinried edbcbeb380 group download status per entity for the library tabs
The detail heroes ask for one entity's status at a time. The list surfaces
need every status on screen at once, so add one grouped flow per tab that
returns a lookup of entity id to counts, which the tiles and rows read the way
song rows read the per-song map.
2026-10-04 00:30:03 +00:00
austinried d89b9e3a47 drop the concurrency dialog test 2026-10-04 00:30:03 +00:00
austinried 6f25f426ba fix the overlapping options in the concurrency dialog
ChoiceGroup emitted its header and option rows as siblings straight into the AlertDialog text slot, and they drew on top of each other, leaving only one radio visible with garbled labels. Wrap the group in its own Column so the rows stack, and cover it with a test that asserts the presets occupy separate rows.
2026-10-04 00:30:03 +00:00
austinried cf6ee00b6f move the artist header row down and the albums up
Drop the row's bottom padding and add to its top so the count and buttons sit closer to the album grid.
2026-10-04 00:30:03 +00:00
austinried 553752bf0a bump the artist album count text size
Use bodyLarge for the album count so it reads a little larger under the artist name.
2026-10-04 00:30:03 +00:00
austinried ea952e5a73 even out the artist album grid gutters
The columns were 16dp from the screen edges but 12dp apart, so the middle looked tighter than the sides. Use the same gap horizontally as vertically.
2026-10-04 00:30:03 +00:00
austinried 9f061e2a31 drop the artist biography placeholder and centre the header row
The 'Artist biography coming soon.' line is temporary and the bio work is shelved, so remove it. With only the album count left, centre it against the star and more buttons under the image (the buttons no longer need to sit below the hanging shuffle).
2026-10-04 00:30:03 +00:00
austinried 9ce7538e54 drop the cover thumbnail request to 384px to cover the common densities 2026-10-04 00:30:03 +00:00
austinried 74a91b2de0 request 512px cover thumbnails so the album grid stays sharp
main's 512px bump was reverted by bd748f5, which dropped it as a stray edit during the downloads rebase. Restore it.
2026-10-04 00:30:03 +00:00
austinried a88618421d drop two changes that are not part of this work
`git add -A` while rebasing and committing swept up another agent's edits from
this checkout: a THUMBNAIL_SIZE bump in SubsonicSource and a refreshArtistInfo
call appended to the artwork pass in DownloadRepository. Both are out of scope
here and are reverted to main's version, so they can land through their author's
own change or not at all.
2026-10-04 00:30:03 +00:00
austinried a6659f9f62 promote only the active source, and let a partial artist delete
Third review round:

- `promote` read every source's rows, so a single inactive source with waiting
  rows could fill the window and starve the source in use: its songs stayed
  queued with no engine id, for good, through every tick. It now scopes to the
  active source, which is also the only one that can resolve a URL here.
- An artist with some songs downloaded offered only Download, because the more
  menu rendered `action()` rather than the actions the state offers. It renders
  the whole list now, so a partial artist gets Download and Delete.
- The hero's long press is only advertised when there is something to delete,
  instead of announcing a Delete it would ignore, and it declares a button role
  again after losing `IconButton`.
- The delete dialog uses the platform size formatter rather than a hand-rolled
  one, which also fixes 999_999 reading as "1000.0 kB".
- The poll warms artwork through the same helper reconcile uses.
2026-10-04 00:30:03 +00:00
austinried a57ca92250 cancel a list in one go, and round the hero's touch feedback
- Cancelling a big playlist did per-row work: a binder cancel, two queries and a
  delete each, thousands of times, under the lock. The platform takes a list of
  ids in one call, so the cancel is now one binder call, one delete per chunk of
  rows and one sweep, which is both the several seconds and the stale button.
- Partial files are covered by the same sweep, which already deletes any file in
  a source directory that no row names; a test now proves a stray .part goes with
  the cancel.
- The hero's control was a plain clickable Box after the long-press work, so its
  splash was square; it clips to a circle the way an IconButton does.
2026-10-04 00:30:03 +00:00
austinried 3b6fb1341b long press the hero to delete a partially downloaded list
The hero's control now carries the whole rule: a tap does what the state offers
(Download, Cancel, Delete) and a long press asks to delete when there is anything
downloaded to delete, so a partially downloaded album can be emptied without
starting the rest first. Nothing downloaded means the long press does nothing.

The rule itself returns the actions rather than one of them, so a partially
downloaded list offers both Download and Delete; the tap takes the first. That
list is what the library tabs' context menus will read.
2026-10-04 00:30:03 +00:00
austinried 37ccfd0b17 confirm the artist delete too
Only a single song deletes without asking; the artist's delete now opens the same
dialog as the album and playlist, naming the artist and the space it frees. The
artist's download action stays in its more-menu rather than getting a visible
control, deliberately, so bulk downloading a whole artist is a considered
action.
2026-10-04 00:30:03 +00:00
austinried 475793059b keep main's setStar when resolving the rebase
The conflict resolution took my side of ItemActions.setStar, which still
suspended and returned Result; main's rework made it a plain action the menu
calls without a coroutine, with the star filled optimistically. Compiles again,
and ItemContextMenuStarTest passes.
2026-10-04 00:30:03 +00:00
austinried 4652430f73 bound the downloads handed to the platform, and confirm bulk deletes
Two things a 3k-song playlist turned up, plus the hero's downloaded state.

- The platform runs about eight downloads at a time, but a bulk action handed it
  every song at once. Three thousand pending requests meant a notification flood,
  and a poll tick that rewrote every row's bytes/total, so the whole list churned
  ten times a second. Now a bulk action only records the songs and hands over at
  most IN_FLIGHT_LIMIT, oldest first, promoting the next as each finishes, so our
  row state mirrors what is actually running and a cancel only has to reach what
  is in flight.
- Cancelling was therefore unusable at that size. It now touches at most the
  in-flight requests instead of thousands, and the rows wait behind it.
- A queued row with no engine id is waiting its turn, not lost, so reconcile no
  longer re-enqueues the whole list on every pass; a row whose engine entry
  vanished goes back to waiting and the next promote picks it up. A song that
  cannot be handed over fails instead of being retried every tick.
- Requests follow the order the screen shows: artist songs resolve through the
  same albums ordering the artist page uses, so they were the one list that did
  not.
- The hero's fully-downloaded state shows the downloaded glyph rather than a bin,
  and tapping it asks before deleting, naming the album or playlist and the space
  it frees.
2026-10-04 00:30:02 +00:00
austinried 17c1ea40a4 test the bulk cancel race, and keep cancellation working
Second review round on the bulk downloads:

- The cancel-during-bulk fix had no test, so the invariant it exists for could
  regress silently. The fake engine can now delay an enqueue, which holds the
  race window open: the queue loop is kept busy, a cancel is fired mid-queue,
  and the test asserts the whole list ends up cancelled. Reverting to per-song
  locking fails it, which I checked.
- The per-song catch around the queue loop swallowed CancellationException, so
  cancelling the caller did not stop the loop. It rethrows now.
- The artwork pass skips songs whose row a cancel has already taken.
- The lock-hold ceiling is recorded where the lock is taken: cancel latency and
  the poll tick both scale with the list length, and a per-list cancel
  generation would lift that if it ever bites.
- Tests: an empty list says so, one song failing to enqueue leaves the rest of
  the list alone, the applyAction test covers Delete as well as Download and
  Cancel, and the two playlist fixtures share a helper.
2026-10-04 00:30:02 +00:00
austinried bf561075a2 address the bulk download review
- Cancelling a list while its download loop was still enqueueing missed every
  song queued after the cancel looked. The loop now holds the lock for the whole
  queue, so a cancel waits for it to finish and then removes all of it. That
  needed the enqueue helper split into a locked entry point and a body the loop
  can call while already holding the lock — calling the locked one from inside
  the lock deadlocked, which is what hung the tests.
- An empty resolved list now says so instead of doing nothing.
- One song failing to enqueue no longer aborts the rest of the batch.
- The artist actions resolve through the albums the artist page lists, matching
  what is on screen, rather than through songs.artistId, which for a guest on a
  compilation enqueued nothing.
- Bulk actions are one `applyAction` on the repository, so the three view models
  and both screens stop repeating the same dispatch.
- Tests: the playlist and artist resolve paths, a Running row counted as
  downloading, the action dispatch, and the action rule moved to a plain unit
  test.
2026-10-04 00:30:02 +00:00
austinried b2b92a388e download a whole album, playlist or artist at once
Third block of #65: bulk downloads and the list-level actions.

- The hero's download button on albums and playlists is real now. It starts the
  songs the list is missing, cancels what is in flight, or deletes what is
  already downloaded, chosen from the list's own status. The artist has no hero
  button, so its bulk actions live in the context menu, which now carries the
  same status.
- No new storage: a bulk job is the download rows for the list, and the status is
  counted from song_downloads joined to the list's songs, so cancel and delete
  stay well defined without anything to keep in sync.
- downloadAll fetches artwork for the whole list under one shared budget, once
  per unique cover, and skips songs that are already downloaded so re-tapping
  Download resumes rather than restarting.
2026-10-04 00:30:02 +00:00
austinried 9266fc5edc request 512px cover thumbnails so the album grid stays sharp 2026-10-04 00:30:02 +00:00
austinried f8aa391717 faster star dismiss delay 2026-10-04 00:30:02 +00:00
austinried b908d90273 right align the track times within their column 2026-10-04 00:30:02 +00:00
austinried 0d39a9de72 show track times without padded minutes
Minutes read as the plain value ("4:11", "0:05") and only hours keep the
formatted MM:SS tail, so nothing is zero-padded except the seconds.
2026-10-04 00:30:02 +00:00
austinried 51ed8fdd6b address review: pre-P shadow fallback and safer notification star
- draw the play halo as an offset copy below API 28, where path
  shadow layers are ignored, and skip the inner shadow there too
- add a repository toggleStar that reads and writes under the star lock,
  so fast double taps on the notification cannot desync
- reset the star button when a track starts, so a failed source lookup
  cannot leave the previous song's state showing
2026-10-04 00:30:02 +00:00
austinried 08eace9e90 dim the playing art instead of desaturating it 2026-10-04 00:30:02 +00:00
austinried aa954ffc3e desaturate the playing row's art behind the primary indicator
Back to the primary border and glyph, and drop the playing cover's
saturation so the accent reads against its own artwork.
2026-10-04 00:30:02 +00:00
austinried 3eef4e79b6 try a white play glyph over art 2026-10-04 00:30:02 +00:00
austinried e222a76500 back to a primary play glyph with a white art border 2026-10-04 00:30:02 +00:00
austinried 077a2ced77 tint the playing indicator with the artwork's secondary 2026-10-04 00:30:02 +00:00
austinried 94c514cdd9 Revert "replace the play arrow with an animated bar indicator"
This reverts commit c67569a15a7c7150de3601b57a59e2ed2ba302ef.
2026-10-04 00:30:02 +00:00
austinried a23d9a3c31 replace the play arrow with an animated bar indicator
Three equaliser bars wave with staggered phases to draw the eye to the
playing track, keeping the soft shadow over cover art and flat bars in
the queue.
2026-10-04 00:30:02 +00:00
austinried c68b631d06 strengthen the inset border shadow 2026-10-04 00:30:02 +00:00
austinried 7555344057 draw the play indicator shadow with a framework shadow layer
Works below API 31, unlike Modifier.blur. Also give the playing cover
art an inset shadow along its border, drawn from the same layer.
2026-10-04 00:30:02 +00:00
austinried c3874ed1c3 give the playing indicator a soft halo over art
Replace the offset drop copy with a slightly scaled, blurred dark copy so
the arrow lifts off busy artwork on all sides.
2026-10-04 00:30:02 +00:00
austinried 8a279dcec2 put the artist star and more back at 14dp 2026-10-04 00:30:02 +00:00
austinried 57b15b1765 nudge the artist star and more further down 2026-10-04 00:30:02 +00:00
austinried f08d34e822 drop the artist star and more to the bio line 2026-10-04 00:30:02 +00:00
austinried 1fdbc8c28b centre the artist shuffle over the star and more buttons
Shift the pill 6dp left to align with the controls' centre and widen the
title's right reserve to keep the same gap.
2026-10-04 00:30:02 +00:00
austinried 284ccaa77b adjust artist details margins 2026-10-04 00:30:02 +00:00
austinried e0345302b6 drop the artist album controls below the shuffle
Move the bio up under the album count and drop the star and more buttons
20dp so they clear the floating shuffle with room to spare.
2026-10-04 00:30:02 +00:00
austinried f6f9648cce tuck the artist album row and its controls tight to the image
Keep the star and more pinned to the right of the row, top-align the row
so the album count sits close under the image, and let the centred
shuffle button's lower half pass just above the controls.
2026-10-04 00:30:02 +00:00
austinried 56379d4433 tighten the artist album row against the image
Bring the album count row up to a 16dp top margin and inset its controls
past the floating shuffle button's column so the two cannot overlap.
2026-10-04 00:30:02 +00:00
austinried 6f4a55b23c float the artist shuffle button on the image edge
Move the shuffle out of the title block so the wrapped name keeps an even
bottom margin, and anchor the button centred on the image's bottom edge.
The title's last line still reserves room on the right, and the album
count row starts below the button's hanging half.
2026-10-04 00:30:02 +00:00
austinried 5c3daed968 keep the artist title's top line clear of the shuffle button
Render the wrapped artist name as two rows: the first line spans the full
width on its own row above, and the last line shares a row with the
shuffle button, so the text can never run under it.
2026-10-04 00:30:02 +00:00
austinried af9b4e304c size up the artist shuffle and keep the title clear of it
- make the shuffle a filled pill matching the album/playlist controls
- wrap the artist name with a hanging indent: the first line may run the
  full width over the button, while the last line stops short of it
2026-10-04 00:30:02 +00:00
austinried 581c5e20a3 rework the artist detail header
- drop the passive star badge from the artists list
- add an album count, star, more and placeholder bio under the artist image
- move the more action down from the top bar into that row
- put a shuffle button beside the artist name, which can now wrap to two lines
- remove the now-unused StarredBadge component
2026-10-04 00:30:02 +00:00
austinried 9cb93d37e1 polish the play indicator, queue rows and detail spacing
- shadow the play indicator over album art so it reads against busy art
- drop the download indicator from the queue view
- enlarge the now playing star toggle
- leave a little more room between the detail controls and the song list
2026-10-04 00:30:02 +00:00
austinried 83d0bafeb9 note the notification star's Media3 unstable API dependency 2026-10-04 00:30:02 +00:00
austinried f037e595ed fix lint and session access from the notification star review
- opt in to the Media3 unstable API on the service and answer
  unsupported custom commands with SessionError.ERROR_NOT_SUPPORTED
- add the star command on top of the trust-aware connection defaults
  instead of granting untrusted controllers the full command set
- number tracks within their disc, not across the whole album
- leave the star button to the library flow so a failed write cannot
  leave the notification flipped
- omit the leading cell entirely when a row has no art and no track
2026-10-04 00:30:02 +00:00