Skip to content

Mark a whole playlist finished or not finished, and show series on its rows - #1221

Merged
r0adkll merged 2 commits into
mainfrom
issue-1188-playlist-mark-finished-series
Oct 8, 2026
Merged

r0adkll merged 2 commits into
mainfrom
issue-1188-playlist-mark-finished-series

Conversation

@r0adkll

@r0adkll r0adkll commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Adds the two playlist improvements from #1188: each book's series and number on its playlist row, and a ⋮ menu that marks the whole playlist as finished or not finished. The issue's use case is re-listening to a 16-book series, which today means un-finishing every book one at a time before playing the first.

The menu works like the series screen's menu from #1219 (merged while this PR was open): it counts the items in the confirmation, is disabled while an update runs, and runs the update in the user-wide scope so leaving the screen part way through doesn't stop it.

Closes #1188

What changed

Playlist screen (features/playlists/ui)

  • PlaylistProgressMenu adds a ⋮ to the top bar with Mark all as finished (shown while any item is unfinished) and Mark all as not finished (shown while any item is finished). ConfirmPlaylistProgressDialog confirms first and says how many items will change. Both mirror SeriesProgressMenu / ConfirmSeriesProgressDialog.
  • PlaylistDetailPresenter handles MarkAllFinished / MarkAllNotFinished:
    • Finished targets every item not yet finished. Like the book screen and the series menu, it stops playback when the current session is one of them, marks those sessions deleted and clears their playback history.
    • Not finished targets only finished items. Partly played books keep their position.
    • The work runs in the @ForScope(UserScope::class) CoroutineScopeHolder, and isUpdatingProgress disables the menu until it completes.
  • Rows now read progress live from MediaProgressRepository.observeAllProgress(), keyed by MediaProgressKey (the same pattern as HomePresenter). Before, they used the userMediaProgress copied into the playlist item, which went stale until the playlist reloaded. Finished checks now update as soon as an item changes, podcast episodes show their own progress, and the playing book's bar moves while the screen is open.
  • PlaylistListItem shows the series as "Name These are the only states now so this is effectively always true. We should eval... #2", comma-joined for books in several series, and just the name when there's no sequence. It falls back to the server's seriesName when the structured list is empty. Podcast episodes and books outside a series get no line. LibraryItemListItem gains an optional supportingText line for this; other callers are unchanged.

Progress repository (features/user)

  • MediaProgressRepository.markAllFinished(keys) sends one PATCH /api/me/progress/batch/update. Afterwards it updates the local rows in a single transaction, including rows still holding the placeholder id from playback, the case Show series book numbers and mark a whole series finished #1219 fixed for single books. For any item that had no local progress, it fetches the server's new row, so those rows carry their server id.
  • markAllNotFinished(keys) runs the existing per-item markNotFinished concurrently. The server has no batch delete, and un-finishing through the batch update leaves a 0% row behind (it resets currentTime but keeps the record). That row would draw an empty progress bar on every row, unlike the single-book action, which deletes the progress. The HTTP engines cap per-host connections (OkHttp 5, Darwin 6), so a large playlist doesn't flood the server.
  • The series menu still marks books one request at a time. It could switch to markAllFinished later, but this PR leaves it alone.

Verification

  • ./scripts/ktlint --check: clean.
  • ./gradlew :app:desktop:compileKotlin :app:android:compileAlphaDebugKotlin :app:ios:compileKotlinIosSimulatorArm64 jvmTest test -x :infra:audioplayer:engine-tests:test: passes after rebasing onto main. I excluded the desktop FFmpeg engine tests because the native library doesn't load on this machine (UnsatisfiedLinkError: no jniavutil). This PR doesn't touch the audio player.
  • New tests:
    • StoreMediaProgressRepositoryTest, merged with Show series book numbers and mark a whole series finished #1219's tests in the same file, runs against an in-memory database and the fake API. It checks one batch request, tracked rows finished locally (including a placeholder-id row), an untracked row fetched with its server id, a failed batch leaving local rows alone, and un-finishing deleting each row.
    • PlaylistDetailPresenterTest checks that only unfinished items are finished, playback stops only when the current item is affected, only finished items are un-finished, and the counts follow progress.
  • On device (Android emulator against the throwaway testbed server), two runs.
    • The first run, before the rebase, used a playlist with two Dungeon Crawler Carl books and Atomic Habits:
      • Series lines showed, both actions worked, and the server matched after each.
      • Leaving and re-entering matched the server.
    • The second run, after the rebase and alignment, used four books: one finished, one at 38%, and two never started.
      • The dialogs counted correctly ("3 items…", "1 finished item…", "4 finished items…"), and Cancel left the server unchanged.
      • "Mark all as not finished" removed only the finished book's progress. The 38% book kept its progress.
      • Confirm, then Back right away: after "Mark all as finished", all four books were finished on the server, including the two with no prior progress, and re-entering showed all four checked. After "Mark all as not finished", all four progress rows were deleted.
    • Logcat had no progress errors in either run.
  • Not covered on device:
    • The disabled ⋮ while an update runs: the update finished too quickly to catch.
    • The comma-joined line for a book in several series.

🤖 Generated with Claude Code

Adds a ⋮ menu to the playlist screen with Mark all as finished and Mark all
as not finished, each behind a confirmation. Finishing sends one batch
progress update to the server; un-finishing removes each item's progress
the same way the single-item action does, since the server has no batch
delete. Playlist rows now show the book's series and number, and read
progress live so finished badges update as soon as an item changes.
Run the playlist's mark-all updates in the user scope so leaving the screen
part way through doesn't leave the playlist half updated, disable the menu
while an update runs, and say how many items will change in the
confirmation, as the series screen from #1219 does.
@r0adkll
r0adkll force-pushed the issue-1188-playlist-mark-finished-series branch from 710c2ee to 840aee7 Compare October 8, 2026 14:00
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Warnings
⚠️ Big PR, try to keep changes smaller if you can
⚠️ This PR is original Xbox Huge! Consider breaking into smaller PRs
Messages
📖 This PR has been checked by Danger

Generated by 🚫 Danger Kotlin against 840aee7

@r0adkll
r0adkll enabled auto-merge (squash) October 8, 2026 14:11
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

Android APK @ 16e3343

@r0adkll
r0adkll merged commit 086cae7 into main Oct 8, 2026
6 of 7 checks passed
@r0adkll
r0adkll deleted the issue-1188-playlist-mark-finished-series branch October 8, 2026 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Playlist View Improvements

1 participant