Skip to content

Add EPUBNavigatorDelegate.navigatorDidLoadSpread(_:) - #838

Draft
raphi011 wants to merge 2 commits into
readium:developfrom
raphi011:feat/epub-spread-loaded-delegate
Draft

Add EPUBNavigatorDelegate.navigatorDidLoadSpread(_:)#838
raphi011 wants to merge 2 commits into
readium:developfrom
raphi011:feat/epub-spread-loaded-delegate

Conversation

@raphi011

Copy link
Copy Markdown
Contributor

Summary

Adds a new EPUBNavigatorDelegate.navigatorDidLoadSpread(_:) delegate method, called when the currently visible spread has finished loading its content and is about to be revealed (the navigator's per-spread activity indicator stops right after it returns).

Motivation

A host app that shows its own loading cover currently has no precise signal for when the visible content is ready. Dismissing on locationDidChange is too early — it fires while the spread is still loading, briefly exposing the navigator's own activity indicator and the scroll to the initial location. This callback fires exactly when the visible content appears, so the host can dismiss its cover without any flash.

Behavior

  • Fired at the end of spreadViewDidLoad, one beat before showSpread() stops the activity indicator and fades the content in.
  • Current spread only (spreadView === paginationView.currentView), not the adjacent spreads preloaded around it. Adjacent spreads load concurrently with the current spread's trailing settle delay (see PaginationView.loadNextPage); a fast neighbour can otherwise reach spreadViewDidLoad first, and firing for it would let a host dismiss its cover a beat before the visible spread is actually revealed.
  • Fires once on open and again after each page turn (whenever the visible spread changes).

API

public protocol EPUBNavigatorDelegate {
    // ...
    func navigatorDidLoadSpread(_ navigator: EPUBNavigatorViewController)
}

public extension EPUBNavigatorDelegate {
    func navigatorDidLoadSpread(_ navigator: EPUBNavigatorViewController) {}
}

Default empty implementation — existing conformers are unaffected, purely additive.

Testing

  • Builds for the iOS Simulator SDK (ReadiumNavigator scheme → BUILD SUCCEEDED); make format reports no changes.
  • The callback has been running in production in a downstream reader app to dismiss a custom loading cover, with no flash of the navigator's indicator.

Notes

  • Swift-only — no JavaScript bundle changes.
  • No unit test: the trigger is a UIKit/WebKit load-timing event on the spread view that the existing suite has no harness for; verified manually + in production.

raphi011 and others added 2 commits June 28, 2026 11:18
Add EPUBNavigatorDelegate.navigatorDidLoadSpread(_:), fired at the end of
spreadViewDidLoad — one beat before the spread view's showSpread() stops the
activity indicator and fades the content in. Default-empty extension impl so
existing conformers are unaffected.

Fires for the current spread only (spreadView === paginationView.currentView),
not the adjacent spreads preloaded around it. PaginationView.loadNextPage
resumes the current spread's `go` continuation before its trailing `delayed`
settle sleep, so neighbours load concurrently with that tail; a short
neighbour skips the delay and can reach spreadViewDidLoad first. Firing for it
would let a host dismiss its loading cover a beat before the visible spread's
showSpread() runs, briefly exposing that spread's activity indicator.

Lets a host that shows its own loading cover dismiss it exactly when the
visible content appears, rather than on locationDidChange (which fires while
the spread is still loading, briefly exposing the navigator's own indicator
and the scroll to the initial location).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@mickael-menu mickael-menu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @raphi011

After a quick test, it looks like this is only called when the publication first loads, but not when navigating to other locations (e.g. from the table of contents). Was this the intended behavior? If so, we might want to consider a different name for it. There's also an opportunity to generalize it to VisualNavigatorDelegate.

Also, how does this behave when two resources are displayed side by side, such as with a fixed-layout EPUB in spread mode?

Currently we're focusing on migrating the toolkit to Swift 6 with strict concurrency support in the swift6 branch. We accept bug fixes but new features are frozen until this is done (we're almost there). I'm putting your PR as a draft for now.

Thank you for your understanding 🙏

@mickael-menu
mickael-menu marked this pull request as draft July 1, 2026 09:03
@mickael-menu
mickael-menu requested a review from Copilot July 1, 2026 09:06

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

Adds a new EPUB navigator delegate callback to let host apps know precisely when the currently visible spread has finished loading and is about to be revealed, enabling custom loading overlays to be dismissed without flashing the navigator’s own activity indicator.

Changes:

  • Added EPUBNavigatorDelegate.navigatorDidLoadSpread(_:) with a default empty implementation to preserve source compatibility.
  • Triggered the new callback at the end of the visible spread’s spreadViewDidLoad, just before the spread is revealed.
  • Documented the new API in CHANGELOG.md under Unreleased → Added → Navigator.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
Sources/Navigator/EPUB/EPUBNavigatorViewController.swift Introduces the new delegate method and invokes it when the current spread finishes loading.
CHANGELOG.md Adds an Unreleased changelog entry describing the new delegate callback and its intended use.

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

Comment on lines +23 to +26
/// Called when the current spread has finished loading and is about to be
/// revealed: once when the publication opens, and again after each page turn.
/// Only the visible spread triggers it, not the preloaded adjacent ones.
///
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.

3 participants