Skip to content
This repository has been archived by the owner on Jul 29, 2022. It is now read-only.

Commit

Permalink
Merge pull request #130 from readium/feature/pdf
Browse files Browse the repository at this point in the history
Add a PDF navigator
  • Loading branch information
mickael-menu committed Jun 22, 2020
2 parents 1ad17cf + e3ce19b commit a88dad4
Show file tree
Hide file tree
Showing 13 changed files with 392 additions and 118 deletions.
21 changes: 17 additions & 4 deletions r2-navigator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,27 +51,40 @@ dependencies {
implementation 'androidx.webkit:webkit:1.1.0'
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "com.google.android.material:material:1.2.0-alpha03"
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation 'joda-time:joda-time:2.9.9'
implementation "androidx.legacy:legacy-support-core-ui:1.0.0"

implementation 'com.duolingo.open:rtl-viewpager:1.0.3'
implementation 'androidx.viewpager2:viewpager2:1.0.0'

implementation 'com.jakewharton.timber:timber:4.7.1'

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'

implementation 'org.zeroturnaround:zt-zip:1.13'

implementation 'org.jsoup:jsoup:1.10.3'
api 'com.github.barteksc:android-pdf-viewer:2.8.2'

testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"

implementation "androidx.activity:activity-ktx:1.1.0"
implementation "androidx.appcompat:appcompat:1.2.0-beta01"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "androidx.core:core-ktx:1.2.0"
implementation "androidx.fragment:fragment-ktx:1.2.4"
implementation "androidx.legacy:legacy-support-core-ui:1.0.0"
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0"
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'androidx.webkit:webkit:1.1.0'

// ChrisBane/PhotoView ( for the Zoom handling )
implementation 'com.github.chrisbanes:PhotoView:2.1.4'
}
3 changes: 3 additions & 0 deletions r2-navigator/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
<activity
android:name=".divina.R2DiViNaActivity"
android:theme="@style/AppTheme" />
<activity
android:name=".pdf.R2PdfActivity"
android:theme="@style/AppTheme" />

</application>

Expand Down
67 changes: 16 additions & 51 deletions r2-navigator/src/main/java/org/readium/r2/navigator/IR2Activity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
package org.readium.r2.navigator

import android.content.SharedPreferences
import android.graphics.PointF
import android.view.View
import androidx.lifecycle.LiveData
import org.readium.r2.navigator.pager.R2ViewPager
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.ReadingProgression
import java.net.URL

interface IR2Activity {

Expand Down Expand Up @@ -51,59 +52,32 @@ interface IR2TTS {


interface Navigator {
val currentLocation: Locator?
fun go(locator: Locator, animated: Boolean, completion: () -> Unit): Boolean
fun go(link: Link, animated: Boolean, completion: () -> Unit): Boolean
fun goForward(animated: Boolean, completion: () -> Unit): Boolean
fun goBackward(animated: Boolean, completion: () -> Unit): Boolean

}

fun Navigator.go(locator: Locator, animated: Boolean = false, completion: () -> Unit = {}): Boolean =
go(locator = locator, animated = animated, completion = completion)
val currentLocator: LiveData<Locator?>

fun Navigator.go(link: Link, animated: Boolean = false, completion: () -> Unit = {}): Boolean =
go(link = link, animated = animated, completion = completion)
fun go(locator: Locator, animated: Boolean = false, completion: () -> Unit = {}): Boolean
fun go(link: Link, animated: Boolean = false, completion: () -> Unit = {}): Boolean
fun goForward(animated: Boolean = false, completion: () -> Unit = {}): Boolean
fun goBackward(animated: Boolean = false, completion: () -> Unit = {}): Boolean

fun Navigator.goForward(animated: Boolean = false, completion: () -> Unit = {}): Boolean =
goForward(animated = animated, completion = completion)
@Deprecated("Use [currentLocator] instead", ReplaceWith("currentLocator.value"))
val currentLocation: Locator? get() = currentLocator.value

fun Navigator.goBackward(animated: Boolean = false, completion: () -> Unit = {}): Boolean =
goBackward(animated = animated, completion = completion)
interface Listener {
}

interface VisualListener : Listener {
fun onTap(point: PointF): Boolean = false
}
}

interface NavigatorDelegate {
@Deprecated("Observe [currentLocator] instead")
fun locationDidChange(navigator: Navigator? = null, locator: Locator)

// present error message
fun presentError(navigator: Navigator? = null, error: NavigatorError) {}

// present external url
fun presentExternalURL(navigator: Navigator? = null, url: URL) {}
}


//public fun NavigatorDelegate.navigator(navigator: Navigator, url: URL) {
// if (UIApplication.shared.canOpenURL(url)) {
// UIApplication.shared.openURL(url)
// }
//}


sealed class NavigatorError : Exception() {
object copyForbidden : NavigatorError()

val errorDescription: String?
get() {
return when (this) {
is copyForbidden -> "NavigatorError.copyForbidden"
}
}
}


interface VisualNavigator : Navigator {
// val view: UIView
val readingProgression: ReadingProgression

fun goLeft(animated: Boolean, completion: () -> Unit): Boolean
Expand All @@ -130,12 +104,3 @@ fun VisualNavigator.goRight(animated: Boolean = false, completion: () -> Unit =
goBackward(animated = animated, completion = completion)
}
}


//public interface VisualNavigatorDelegate: NavigatorDelegate {
// fun navigator(navigator: VisualNavigator, point: CGPoint)
//}

//public fun VisualNavigatorDelegate.navigator(navigator: VisualNavigator, point: CGPoint) {}


Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Module: r2-navigator-kotlin
* Developers: Mickaël Menu
*
* Copyright (c) 2020. Readium Foundation. All rights reserved.
* Use of this source code is governed by a BSD-style license which is detailed in the
* LICENSE file present in the project repository where this source code is maintained.
*/

package org.readium.r2.navigator

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import org.readium.r2.navigator.pdf.PdfNavigatorFragment
import org.readium.r2.shared.publication.Locator
import org.readium.r2.shared.publication.Publication

class NavigatorFragmentFactory(
private val publication: Publication,
private val initialLocator: Locator? = null,
private val listener: Navigator.Listener? = null
) : FragmentFactory() {

override fun instantiate(classLoader: ClassLoader, className: String): Fragment =
when (className) {
PdfNavigatorFragment::class.java.name -> PdfNavigatorFragment(publication, initialLocator, listener)
else -> super.instantiate(classLoader, className)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import kotlinx.android.synthetic.main.activity_r2_audiobook.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.readium.r2.navigator.*
import org.readium.r2.navigator.BuildConfig.*
import org.readium.r2.navigator.BuildConfig.DEBUG
import org.readium.r2.navigator.IR2Activity
import org.readium.r2.navigator.NavigatorDelegate
import org.readium.r2.navigator.R
import org.readium.r2.navigator.VisualNavigator
import org.readium.r2.shared.extensions.destroyPublication
import org.readium.r2.shared.extensions.getPublication
import org.readium.r2.shared.publication.*
Expand All @@ -24,8 +29,11 @@ import kotlin.coroutines.CoroutineContext

open class R2AudiobookActivity : AppCompatActivity(), CoroutineScope, IR2Activity, MediaPlayerCallback, VisualNavigator {

override val currentLocation: Locator? get() =
publication.readingOrder[currentResource].let { resource ->
override val currentLocator: LiveData<Locator?> get() = _currentLocator
private val _currentLocator = MutableLiveData<Locator?>(null)

private fun notifyCurrentLocation() {
val locator = publication.readingOrder[currentResource].let { resource ->
val progression = mediaPlayer
?.let { it.currentPosition / it.duration }
?: 0.0
Expand All @@ -44,6 +52,14 @@ open class R2AudiobookActivity : AppCompatActivity(), CoroutineScope, IR2Activit
)
}

if (locator == currentLocator.value) {
return
}

_currentLocator.postValue(locator)
navigatorDelegate?.locationDidChange(navigator = this, locator = locator)
}

override fun go(locator: Locator, animated: Boolean, completion: () -> Unit): Boolean {
val resourceIndex = publication.readingOrder.indexOfFirstWithHref(locator.href)
?: return false
Expand Down Expand Up @@ -135,9 +151,9 @@ open class R2AudiobookActivity : AppCompatActivity(), CoroutineScope, IR2Activit

mediaPlayer?.goTo(currentResource)

currentLocation?.locations?.progression?.let { progression ->
currentLocator.value?.locations?.progression?.let { progression ->
mediaPlayer?.seekTo(progression)
seekLocation = currentLocation?.locations
seekLocation = currentLocator.value?.locations
isSeekNeeded = true
}

Expand Down Expand Up @@ -270,12 +286,7 @@ open class R2AudiobookActivity : AppCompatActivity(), CoroutineScope, IR2Activit

seekBar!!.progress = startTime.toInt()

val resource = publication.readingOrder[currentResource]
val resourceHref = resource.href
val resourceType = resource.type ?: ""

navigatorDelegate?.locationDidChange(locator = Locator(resourceHref, resourceType, publication.metadata.title, Locator.Locations(progression = seekBar!!.progress.toDouble())))

notifyCurrentLocation()
}

private var seekLocation: Locator.Locations? = null
Expand Down Expand Up @@ -337,11 +348,7 @@ open class R2AudiobookActivity : AppCompatActivity(), CoroutineScope, IR2Activit
TimeUnit.MILLISECONDS.toSeconds(startTime.toLong()) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(startTime.toLong())))
seekBar!!.progress = startTime.toInt()

val resource = publication.readingOrder[currentResource]
val resourceHref = resource.href
val resourceType = resource.type ?: ""

navigatorDelegate?.locationDidChange(locator = Locator(resourceHref, resourceType, publication.metadata.title, Locator.Locations(progression = seekBar!!.progress.toDouble())))
notifyCurrentLocation()

Handler().postDelayed(this, 100)
}
Expand Down Expand Up @@ -375,9 +382,6 @@ open class R2AudiobookActivity : AppCompatActivity(), CoroutineScope, IR2Activit
if (data != null) {
val locator = data.getParcelableExtra("locator") as Locator

// Set the progression fetched
navigatorDelegate?.locationDidChange(locator = locator)

// href is the link to the page in the toc
var href = locator.href

Expand All @@ -403,6 +407,7 @@ open class R2AudiobookActivity : AppCompatActivity(), CoroutineScope, IR2Activit

chapterView!!.text = publication.readingOrder[currentResource].title

notifyCurrentLocation()
}
}

Expand Down
Loading

0 comments on commit a88dad4

Please sign in to comment.