Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge develop #406

Merged
merged 5 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ All notable changes to this project will be documented in this file. Take a look
* Scroll mode: jumping between two EPUB resources with a horizontal swipe triggers the `Navigator.Listener.onJumpToLocator()` callback.
* This can be used to allow the user to go back to their previous location if they swiped across chapters by mistake.
* Support for keyboard events in the EPUB, PDF and image navigators. See `VisualNavigator.addInputListener()`.
* Support for non-linear EPUB resources with an opt-in in reading apps (contributed by @chrfalch in [#375](https://github.com/readium/kotlin-toolkit/pull/375) and [#376](https://github.com/readium/kotlin-toolkit/pull/376)).
1. Override loading non-linear resources with `VisualNavigator.Listener.shouldJumpToLink()`.
2. Present a new `EpubNavigatorFragment` by providing a custom `readingOrder` with only this resource to the constructor.


#### Streamer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,18 @@ public interface VisualNavigator : Navigator {
public fun removeInputListener(listener: InputListener)

public interface Listener : Navigator.Listener {

/**
* Called when a link to an internal resource was clicked in the navigator.
*
* You can use this callback to perform custom navigation like opening a new window
* or other operations.
*
* By returning false the navigator wont try to open the link itself and it is up
* to the calling app to decide how to display the link.
*/
public fun shouldJumpToLink(link: Link): Boolean { return true }

@Deprecated("Use `addInputListener` instead", level = DeprecationLevel.ERROR)
public fun onTap(point: PointF): Boolean = false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package org.readium.r2.navigator.epub
import androidx.fragment.app.FragmentFactory
import org.readium.r2.navigator.ExperimentalDecorator
import org.readium.r2.shared.ExperimentalReadiumApi
import org.readium.r2.shared.publication.Link
import org.readium.r2.shared.publication.Locator
import org.readium.r2.shared.publication.Publication
import org.readium.r2.shared.publication.epub.EpubLayout
Expand Down Expand Up @@ -38,9 +39,23 @@ public class EpubNavigatorFactory(
private val layout: EpubLayout =
publication.metadata.presentation.layout ?: EpubLayout.REFLOWABLE

/**
* Creates a factory for [EpubNavigatorFragment].
*
* @param initialLocator The first location which should be visible when rendering the
* publication. Can be used to restore the last reading location.
* @param readingOrder Custom reading order to override the publication's one.
* @param initialPreferences The set of preferences that should be initially applied to the
* navigator.
* @param listener Optional listener to implement to observe navigator events.
* @param paginationListener Optional listener to implement to observe events related to
* pagination.
* @param configuration Additional configuration.
*/
@OptIn(ExperimentalDecorator::class)
public fun createFragmentFactory(
initialLocator: Locator?,
readingOrder: List<Link>? = null,
initialPreferences: EpubPreferences = EpubPreferences(),
listener: EpubNavigatorFragment.Listener? = null,
paginationListener: EpubNavigatorFragment.PaginationListener? = null,
Expand All @@ -49,6 +64,7 @@ public class EpubNavigatorFactory(
EpubNavigatorFragment(
publication = publication,
initialLocator = initialLocator,
readingOrder = readingOrder,
initialPreferences = initialPreferences,
listener = listener,
paginationListener = paginationListener,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public typealias JavascriptInterfaceFactory = (resource: Link) -> Any?
public class EpubNavigatorFragment internal constructor(
override val publication: Publication,
private val initialLocator: Locator?,
readingOrder: List<Link>?,
private val initialPreferences: EpubPreferences,
internal val listener: Listener?,
internal val paginationListener: PaginationListener?,
Expand Down Expand Up @@ -286,12 +287,21 @@ public class EpubNavigatorFragment internal constructor(
publication,
config = this.config,
initialPreferences = initialPreferences,
listener = listener,
layout = epubLayout,
defaults = defaults
)
}

internal lateinit var positionsByReadingOrder: List<List<Locator>>
private val readingOrder: List<Link> = readingOrder ?: publication.readingOrder

private val positionsByReadingOrder: List<List<Locator>> =
if (readingOrder != null) {
emptyList()
} else {
runBlocking { publication.positionsByReadingOrder() }
}

internal lateinit var positions: List<Locator>

internal lateinit var resourcePager: R2ViewPager
Expand Down Expand Up @@ -321,12 +331,11 @@ public class EpubNavigatorFragment internal constructor(
_binding = ReadiumNavigatorViewpagerBinding.inflate(inflater, container, false)
var view: View = binding.root

positionsByReadingOrder = runBlocking { publication.positionsByReadingOrder() }
positions = positionsByReadingOrder.flatten()

when (viewModel.layout) {
EpubLayout.REFLOWABLE -> {
resourcesSingle = publication.readingOrder.mapIndexed { index, link ->
resourcesSingle = readingOrder.mapIndexed { index, link ->
PageResource.EpubReflowable(
link = link,
url = viewModel.urlTo(link),
Expand All @@ -341,9 +350,9 @@ public class EpubNavigatorFragment internal constructor(

// TODO needs work, currently showing two resources for fxl, needs to understand which two resources, left & right, or only right etc.
var doublePageLeft: Link? = null
var doublePageRight: Link?
var doublePageRight: Link? = null

for ((index, link) in publication.readingOrder.withIndex()) {
for ((index, link) in readingOrder.withIndex()) {
val url = viewModel.urlTo(link)
resourcesSingle.add(PageResource.EpubFxl(leftLink = link, leftUrl = url))

Expand Down Expand Up @@ -517,7 +526,7 @@ public class EpubNavigatorFragment internal constructor(
is EpubNavigatorViewModel.Event.RunScript -> {
run(event.command)
}
is EpubNavigatorViewModel.Event.GoTo -> {
is EpubNavigatorViewModel.Event.OpenInternalLink -> {
go(event.target)
}
EpubNavigatorViewModel.Event.InvalidateViewPager -> {
Expand Down Expand Up @@ -915,7 +924,7 @@ public class EpubNavigatorFragment internal constructor(
locatorToResourceAtIndex(resourcePager.currentItem + 1)

private fun locatorToResourceAtIndex(index: Int): Locator? =
publication.readingOrder.getOrNull(index)
readingOrder.getOrNull(index)
?.let { publication.locatorFromLink(it) }

private val r2PagerAdapter: R2PagerAdapter?
Expand Down Expand Up @@ -952,8 +961,8 @@ public class EpubNavigatorFragment internal constructor(

override val currentLocator: StateFlow<Locator> get() = _currentLocator
private val _currentLocator = MutableStateFlow(
initialLocator?.let { publication.normalizeLocator(it) }
?: requireNotNull(publication.locatorFromLink(publication.readingOrder.first()))
initialLocator
?: requireNotNull(publication.locatorFromLink(this.readingOrder.first()))
)

/**
Expand All @@ -964,7 +973,7 @@ public class EpubNavigatorFragment internal constructor(
override suspend fun firstVisibleElementLocator(): Locator? {
if (!::resourcePager.isInitialized) return null

val resource = publication.readingOrder[resourcePager.currentItem]
val resource = readingOrder[resourcePager.currentItem]
return currentReflowablePageFragment?.webView?.findFirstVisibleLocator()
?.copy(
href = resource.url(),
Expand Down Expand Up @@ -1071,6 +1080,8 @@ public class EpubNavigatorFragment internal constructor(
* @param initialLocator The first location which should be visible when rendering the
* publication. Can be used to restore the last reading location.
* @param listener Optional listener to implement to observe events, such as user taps.
* @param readingOrder Custom order of resources to display. Used for example to display a
* non-linear resource on its own.
* @param config Additional configuration.
*/
@Deprecated(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ internal class EpubNavigatorViewModel(
val config: EpubNavigatorFragment.Configuration,
initialPreferences: EpubPreferences,
val layout: EpubLayout,
val listener: VisualNavigator.Listener?,
private val defaults: EpubDefaults,
private val server: WebViewServer
) : AndroidViewModel(application) {
Expand All @@ -66,7 +67,7 @@ internal class EpubNavigatorViewModel(
}

sealed class Event {
data class GoTo(val target: Link) : Event()
data class OpenInternalLink(val target: Link) : Event()
data class OpenExternalLink(val url: Url) : Event()

/** Refreshes all the resources in the view pager. */
Expand Down Expand Up @@ -177,7 +178,9 @@ internal class EpubNavigatorViewModel(
fun navigateToUrl(url: AbsoluteUrl) = viewModelScope.launch {
val link = internalLinkFromUrl(url)
if (link != null) {
_events.send(Event.GoTo(link))
if (listener == null || listener.shouldJumpToLink(link)) {
_events.send(Event.OpenInternalLink(link))
}
} else {
_events.send(Event.OpenExternalLink(url))
}
Expand Down Expand Up @@ -338,6 +341,7 @@ internal class EpubNavigatorViewModel(
application: Application,
publication: Publication,
layout: EpubLayout,
listener: VisualNavigator.Listener?,
defaults: EpubDefaults,
config: EpubNavigatorFragment.Configuration,
initialPreferences: EpubPreferences
Expand All @@ -348,6 +352,7 @@ internal class EpubNavigatorViewModel(
config,
initialPreferences,
layout,
listener,
defaults = defaults,
server = WebViewServer(
application,
Expand Down