Skip to content

Add chapter threshold logic for prev chapter button#1551

Merged
GianniCarlo merged 3 commits into
developfrom
fix/previous-chapter
Jun 7, 2026
Merged

Add chapter threshold logic for prev chapter button#1551
GianniCarlo merged 3 commits into
developfrom
fix/previous-chapter

Conversation

@GianniCarlo

Copy link
Copy Markdown
Collaborator

Purpose

  • We already guard against jumping to previous chapter if we are not inside a threshold when manually rewinding, we now extend that logic to the previous chapter button

Related tasks

#1549

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends the existing “chapter start threshold” behavior (already used for rewind clamping) to the previous chapter button so it follows the common media-player convention: when you’re mid-chapter, the first back action restarts the current chapter; when you’re already near the start, it steps to the previous chapter.

Changes:

  • Added PlayableItem.chapterStartThreshold and PlayableItem.isNearChapterStart to centralize the “near chapter start” calculation.
  • Updated PlayerManager.skipToPreviousChapter() to restart the current chapter when not near its start, otherwise step to the previous chapter (or previous item).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
Shared/CoreData/Lightweight-Models/PlayableItem.swift Centralizes the chapter-start threshold logic and reuses it for rewind clamping.
BookPlayer/Player/PlayerManager.swift Applies the threshold logic to the previous-chapter button behavior and ensures progress notifications are posted on all paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


/// Seconds from a chapter's start within which the playhead is still considered to be "at the start".
/// Shared by rewind clamping and the previous-chapter button so they stay in lockstep.
public static let chapterStartThreshold: TimeInterval = 3
Comment on lines +803 to 811
if !currentItem.isNearChapterStart {
/// First press while into the chapter goes back to its start
jumpToChapter(currentChapter)
} else if let previousChapter = currentItem.previousChapter(before: currentChapter) {
/// Already near the chapter start, so step back to the previous chapter
jumpToChapter(previousChapter)
} else {
playPreviousItem()
}
Comment on lines 793 to 809
func skipToPreviousChapter() {
if let currentChapter = currentItem?.currentChapter,
let previousChapter = currentItem?.previousChapter(before: currentChapter)
{
defer { NotificationCenter.default.post(name: .listeningProgressChanged, object: nil) }

guard let currentItem,
let currentChapter = currentItem.currentChapter
else {
playPreviousItem()
return
}

if !currentItem.isNearChapterStart {
/// First press while into the chapter goes back to its start
jumpToChapter(currentChapter)
} else if let previousChapter = currentItem.previousChapter(before: currentChapter) {
/// Already near the chapter start, so step back to the previous chapter
jumpToChapter(previousChapter)
} else {

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment on lines +241 to +252
func testSkipToPreviousChapterMidChapterRestartsCurrentChapter() {
let item = generateChapteredItem()
item.currentChapter = item.chapters[1] // chapter 2, starts at 51
item.currentTime = 100 // well past the start threshold
sut.currentItem = item

sut.skipToPreviousChapter()

// Restarts the current chapter rather than stepping back
XCTAssertEqual(sut.currentItem?.currentChapter?.index, 2)
XCTAssertEqual(playbackServiceMock.getPlayableItemBeforeParentFolderCallsCount, 0)
}
Comment on lines +254 to +265
func testSkipToPreviousChapterNearStartStepsToPreviousChapter() {
let item = generateChapteredItem()
item.currentChapter = item.chapters[1] // chapter 2, starts at 51
item.currentTime = 52 // within the start threshold
sut.currentItem = item

sut.skipToPreviousChapter()

// Steps back to the previous chapter
XCTAssertEqual(sut.currentItem?.currentChapter?.index, 1)
XCTAssertEqual(playbackServiceMock.getPlayableItemBeforeParentFolderCallsCount, 0)
}
Comment on lines +267 to +278
func testSkipToPreviousChapterFirstChapterMidChapterRestartsInstead() {
let item = generateChapteredItem()
item.currentChapter = item.chapters[0] // chapter 1, starts at 0
item.currentTime = 30 // mid-chapter, past the threshold
sut.currentItem = item

sut.skipToPreviousChapter()

// Restarts chapter 1 instead of jumping to the previous item
XCTAssertEqual(sut.currentItem?.currentChapter?.index, 1)
XCTAssertEqual(playbackServiceMock.getPlayableItemBeforeParentFolderCallsCount, 0)
}

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@GianniCarlo GianniCarlo merged commit 1eb3b9f into develop Jun 7, 2026
2 checks passed
@GianniCarlo GianniCarlo deleted the fix/previous-chapter branch June 7, 2026 14:18
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.

2 participants