Repository navigation
Mark a whole playlist finished or not finished, and show series on its rows - #1221
Merged
Merged
Conversation
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
force-pushed
the
issue-1188-playlist-mark-finished-series
branch
from
October 8, 2026 14:00
710c2ee to
840aee7
Compare
Generated by 🚫 Danger Kotlin against 840aee7 |
r0adkll
enabled auto-merge (squash)
October 8, 2026 14:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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)PlaylistProgressMenuadds 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).ConfirmPlaylistProgressDialogconfirms first and says how many items will change. Both mirrorSeriesProgressMenu/ConfirmSeriesProgressDialog.PlaylistDetailPresenterhandlesMarkAllFinished/MarkAllNotFinished:@ForScope(UserScope::class)CoroutineScopeHolder, andisUpdatingProgressdisables the menu until it completes.MediaProgressRepository.observeAllProgress(), keyed byMediaProgressKey(the same pattern asHomePresenter). Before, they used theuserMediaProgresscopied 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.PlaylistListItemshows 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'sseriesNamewhen the structured list is empty. Podcast episodes and books outside a series get no line.LibraryItemListItemgains an optionalsupportingTextline for this; other callers are unchanged.Progress repository (
features/user)MediaProgressRepository.markAllFinished(keys)sends onePATCH /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-itemmarkNotFinishedconcurrently. The server has no batch delete, and un-finishing through the batch update leaves a 0% row behind (it resetscurrentTimebut 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.markAllFinishedlater, 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 ontomain. 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.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.PlaylistDetailPresenterTestchecks 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.🤖 Generated with Claude Code