From 269d6b7ef18c8d733a236de48445b83d45cdf234 Mon Sep 17 00:00:00 2001 From: Hans-Peter Lehmann Date: Thu, 28 May 2026 10:58:21 +0200 Subject: [PATCH] Fix chapter buttons in new playback service (#8488) ### Description Fix chapter buttons in new playback service. They still tried to use the old service controls. Closes #8483 ### Checklist - [x] I have read the contribution guidelines: https://github.com/AntennaPod/AntennaPod/blob/develop/CONTRIBUTING.md#submit-a-pull-request - [x] I have performed a self-review of my code, going through my changes line by line and carefully considering why this line change is necessary - [x] I have run the automated code checks using `./gradlew checkstyle lint` - [x] My code follows the style guidelines of the AntennaPod project: https://antennapod.org/contribute/develop/app/code-style - [x] I have mentioned the corresponding issue and the relevant keyword (e.g., "Closes: #xy") in the description (see https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) - [x] If it is a core feature, I have added automated tests --- AGENTS.md | 2 ++ .../ui/screen/chapter/ChaptersFragment.java | 9 ++++----- .../screen/playback/TranscriptDialogFragment.java | 15 +++++++-------- .../ui/screen/playback/audio/CoverFragment.java | 14 +++++++------- playback/service/README.md | 4 ++++ 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c264f9de9..5793d26b4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,6 +11,8 @@ AntennaPod uses a highly modularized Gradle architecture with modules organized Each module is stored in a folder of the same name (for example `:net:discovery` in `./net/discovery`) and contains a `README.md` file with a brief explanation of the module's purpose and internal structure. Before looking at code in a module, always read its `README.md` first. +When you discover something broadly useful about a module, such as the correct API to use, or a pattern all callers should follow, update that module's `README.md` proactively. +Only add information that is long-term stable and generic (patterns, APIs, conventions), not task-specific details or things already obvious from reading the code. Several functional areas follow a service-interface/service split: the interface module is depended on by consumers, and the implementation is registered at app startup via `ClientConfigurator`. - `:app` - Main application module that integrates all features - `:event` - EventBus events used for cross-component communication throughout the app diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/chapter/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/chapter/ChaptersFragment.java index f5af81c17..361a1ebbc 100644 --- a/app/src/main/java/de/danoeh/antennapod/ui/screen/chapter/ChaptersFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/chapter/ChaptersFragment.java @@ -24,7 +24,6 @@ import de.danoeh.antennapod.event.playback.PlaybackPositionEvent; import de.danoeh.antennapod.model.feed.Chapter; import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.model.playback.Playable; -import de.danoeh.antennapod.playback.base.PlayerStatus; import de.danoeh.antennapod.playback.service.PlaybackController; import de.danoeh.antennapod.storage.database.DBReader; import de.danoeh.antennapod.storage.preferences.PlaybackPreferences; @@ -79,11 +78,11 @@ public class ChaptersFragment extends AppCompatDialogFragment { adapter = new ChaptersListAdapter(getActivity(), pos -> { Chapter chapter = adapter.getItem(pos); - PlaybackController.bindToService(getActivity(), playbackService -> { - if (playbackService.getStatus() != PlayerStatus.PLAYING) { - playbackService.resume(); + PlaybackController.bindToMedia3Service(getActivity(), controller -> { + if (!controller.isPlaying()) { + controller.play(); } - playbackService.seekTo((int) chapter.getStart()); + controller.seekTo(chapter.getStart()); }); updateChapterSelection(pos, true); }); diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/TranscriptDialogFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/TranscriptDialogFragment.java index 9886685b6..60d16a4ad 100644 --- a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/TranscriptDialogFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/TranscriptDialogFragment.java @@ -30,7 +30,6 @@ import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.model.feed.Transcript; import de.danoeh.antennapod.model.feed.TranscriptSegment; import de.danoeh.antennapod.model.playback.Playable; -import de.danoeh.antennapod.playback.base.PlayerStatus; import de.danoeh.antennapod.playback.service.PlaybackController; import de.danoeh.antennapod.storage.database.DBReader; import de.danoeh.antennapod.storage.preferences.PlaybackPreferences; @@ -126,14 +125,14 @@ public class TranscriptDialogFragment extends DialogFragment long endTime = segment.getEndTime(); scrollToPosition(pos); - PlaybackController.bindToService(getActivity(), playbackService -> { - if (!(playbackService.getCurrentPosition() >= startTime - && playbackService.getCurrentPosition() <= endTime)) { - playbackService.seekTo((int) startTime); - } else if (playbackService.getStatus() == PlayerStatus.PLAYING) { - playbackService.pause(false, false); + PlaybackController.bindToMedia3Service(getActivity(), controller -> { + if (!(controller.getCurrentPosition() >= startTime + && controller.getCurrentPosition() <= endTime)) { + controller.seekTo(startTime); + } else if (controller.isPlaying()) { + controller.pause(); } else { - playbackService.resume(); + controller.play(); } }); adapter.notifyItemChanged(pos); diff --git a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/CoverFragment.java index 5757369fc..2bbfdbac1 100644 --- a/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/CoverFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/ui/screen/playback/audio/CoverFragment.java @@ -237,15 +237,15 @@ public class CoverFragment extends Fragment { return; } - PlaybackController.bindToService(getActivity(), playbackService -> { + PlaybackController.bindToMedia3Service(getActivity(), controller -> { if (displayedChapterIndex < 1) { - playbackService.seekTo(0); - } else if ((playbackService.getCurrentPosition() - 10000 * playbackService.getCurrentPlaybackSpeed()) + controller.seekTo(0); + } else if ((controller.getCurrentPosition() - 10000 * controller.getPlaybackParameters().speed) < curr.getStart()) { refreshChapterData(displayedChapterIndex - 1); - playbackService.seekTo((int) media.getChapters().get(displayedChapterIndex).getStart()); + controller.seekTo(media.getChapters().get(displayedChapterIndex).getStart()); } else { - playbackService.seekTo((int) curr.getStart()); + controller.seekTo(curr.getStart()); } }); } @@ -257,8 +257,8 @@ public class CoverFragment extends Fragment { } refreshChapterData(displayedChapterIndex + 1); - PlaybackController.bindToService(getActivity(), playbackService -> - playbackService.seekTo((int) media.getChapters().get(displayedChapterIndex).getStart())); + PlaybackController.bindToMedia3Service(getActivity(), controller -> + controller.seekTo(media.getChapters().get(displayedChapterIndex).getStart())); } @Override diff --git a/playback/service/README.md b/playback/service/README.md index 8ef3fb5b4..b66a4b6ed 100644 --- a/playback/service/README.md +++ b/playback/service/README.md @@ -7,3 +7,7 @@ The main service doing media playback. External callers should interact with the service through `PlaybackController`, which provides a `bindToMedia3Service()` helper that connects a `MediaController` and runs a callback on it. +The `MediaController` exposes the standard Media3 `Player` interface: `seekTo(positionMs)`, +`play()`, `pause()`, `getCurrentPosition()`, `getPlaybackParameters()`, etc. +Each call to `bindToMedia3Service()` creates a short-lived connection that is released after the +callback returns.