A toolkit for ebooks, audiobooks and comics written in Kotlin

Overview

Readium Kotlin Toolkit

Readium Mobile is a toolkit for ebooks, audiobooks and comics written in Swift & Kotlin.

This toolkit is a modular project, which follows the Readium Architecture. The different modules are found under readium/.

  • shared – Shared Publication models and utilities
  • streamer – Publication parsers and local HTTP server
  • navigator – Plain Fragment and Activity classes rendering publications
  • opds – Parsers for OPDS catalog feeds
  • lcp – Service and models for Readium LCP

A Test App demonstrates how to integrate the Readium Kotlin toolkit in your own reading app

Using Readium

Find documentation and API reference at readium.org/kotlin-toolkit.

Readium modules are distributed through JitPack. It's also possible to clone the repository (or a fork) and depend on the modules locally.

From the JitPack Maven repository

Make sure that you have the $readium_version property set in your root build.gradle and add the JitPack repository.

buildscript {
    ext.readium_version = '2.1.1'
}

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

Then, add the dependencies to the Readium modules you need in your app's build.gradle.

dependencies {
    implementation "com.github.readium.kotlin-toolkit:readium-shared:$readium_version"
    implementation "com.github.readium.kotlin-toolkit:readium-streamer:$readium_version"
    implementation "com.github.readium.kotlin-toolkit:readium-navigator:$readium_version"
    implementation "com.github.readium.kotlin-toolkit:readium-opds:$readium_version"
    implementation "com.github.readium.kotlin-toolkit:readium-lcp:$readium_version"
}

From a local Git clone

You may prefer to use a local Git clone if you want to contribute to Readium, or if you are using your own fork.

First, add the repository as a Git submodule of your app repository, then checkout the desired branch or tag:

git submodule add https://github.com/readium/kotlin-toolkit.git

Next, declare the Kotlin version used in your root build.gradle.

buildscript {
    ext.kotlin_version = '1.5.31'
}

Then, add the following to your project's settings.gradle file, altering the paths if needed. Keep only the modules you want to use.

include ':readium:shared'
project(':readium:shared').projectDir = file('kotlin-toolkit/readium/shared')

include ':readium:streamer'
project(':readium:streamer').projectDir = file('kotlin-toolkit/readium/streamer')

include ':readium:navigator'
project(':readium:navigator').projectDir = file('kotlin-toolkit/readium/navigator')

include ':readium:opds'
project(':readium:opds').projectDir = file('kotlin-toolkit/readium/opds')

include ':readium:lcp'
project(':readium:lcp').projectDir = file('kotlin-toolkit/readium/lcp')

You should now see the Readium modules appear as part of your project. You can depend on them as you would on any other local module:

dependencies {
    implementation project(':readium:shared')
    implementation project(':readium:streamer')
    implementation project(':readium:navigator')
    implementation project(':readium:opds')
    implementation project(':readium:lcp')
}

Building with Readium LCP

Using the toolkit with Readium LCP requires additional dependencies, including the binary liblcp provided by EDRLab. Contact EDRLab to request your private liblcp and the setup instructions.

Comments
  • EPUB navigator does not work on Android 6 (API <= 23)

    EPUB navigator does not work on Android 6 (API <= 23)

    open any epub file the epub webview has layout errors(no margin)

    webview console error info: Uncaught SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

    bug help wanted 
    opened by dotmonkey 22
  • EPub is rendered different in Readium 2 than with Readium 1

    EPub is rendered different in Readium 2 than with Readium 1

    Bug Report

    We have an epub that was rendered fine with Readium 1, but after upgrading to Readium 2 it renders really strange.

    What happened?

    Rendered in Readium 1: image

    Rendered i Readium 2: image

    The publication has been shared through private channel

    bug 
    opened by chrfalch 20
  • App Removed From PlayStore

    App Removed From PlayStore

    Hi, Has the demo app been removed from play store? Whenever I try to access the url it says We're sorry, the requested URL was not found on this server. Url :-

    PlayStore Link


    Edit from moderator: Jump to official answer

    question 
    opened by nidhinprathap 15
  • EPUB navigator: internal links replace the whole web view context

    EPUB navigator: internal links replace the whole web view context

    Bug Report

    What happened?

    When opening an epub which has a table of contents inside the publication, taping on any of the links takes me to the correct location, however the currentLocator observer is not triggered and the progression of the publication is altered, navigating one page back takes me to the first page in the publication, and navigating forward restarts the publication from page 1 after the selected chapter from the ToC has endend. It was observed that on iOS this does not happen and there the behaviour is normal.

    Expected behavior

    When taping on a hyperlink of an entry in the ToC, the locator observer should be triggered and the progression / page order of the publication should not be altered in any way.

    How to reproduce?

    Inconjurat_de_idioti.epub.zip

    1. Open the publication with an observer set on the currentLocator of the navigator
    2. Tap on any of the hyperlinks in the ToC
    3. Observe that the locator observer is not called
    4. Observe that the page progression is altered when navigating back and forth

    Environment

    • Readium version: 2.1.0

    Development environment

    • OS: macOS 11.2
    • IDE: Android Studio Arctic Fox 2020.3.1 Patch 2

    Testing

    • Android version: 10

    • Model: OnePlus 5T

    • Is it an emulator? No

    Additional context

    • Are you willing to fix the problem and contribute a pull request? Yes
    bug 
    opened by mihai-wolfpack 13
  • Overlapping phrases

    Overlapping phrases

    Running the latest (2.2.0) on a real device (Huawei P20pro) Also reproduced in the test app

    Please see the attached video

    1. Open book
    2. Activate scroll mode
    3. Scroll down to the end of the chapter
    4. Disable scroll mode
    5. Navigate between pages horizontally
    6. See error

    https://user-images.githubusercontent.com/56269361/191031671-e8b2b3be-27b9-4ece-b9b2-935f49acda2e.mp4

    opened by mricgar 12
  • Various reflowable EPUB columns shift issues

    Various reflowable EPUB columns shift issues

    On some books, when swiping through the content, the EPUB columns are shifting and are not aligned anymore. This reverts by tapping on the edges.

    I could reproduce this on oryel_1984.zip from this issue: https://github.com/readium/kotlin-toolkit/issues/167

    Screenshot_20200629-101320

    bug 
    opened by mickael-menu 12
  • [EPUB reflow] We can move the offset by pinching the page

    [EPUB reflow] We can move the offset by pinching the page

    We can move the offset of a page by pinching it, then dragging it in a single gesture.

    @johanpoirier wrote in https://github.com/readium/kotlin-toolkit/issues/166:

    This is caused by those lines of code: https://github.com/readium/r2-navigator-kotlin/blob/develop/r2-navigator/src/main/java/org/readium/r2/navigator/R2WebView.kt#L735-L738

    The mLastMotionX is set by the second finger down, so the xDiff is almost never greater than mTouchSlop: https://github.com/readium/r2-navigator-kotlin/blob/develop/r2-navigator/src/main/java/org/readium/r2/navigator/R2WebView.kt#L677

    My question is: why are we mixing touch pointers values into mLastMotionX?

    90648045-58db4600-e239-11ea-8e33-ebad3ab4492c

    bug 
    opened by mickael-menu 12
  • R2WebWiew instanciation error on Android 5

    R2WebWiew instanciation error on Android 5

    Reproduction : Launch the app on Android 5.0 or 5.1 emulator and open ebook. The app crash while initializing the R2WebView This works fine on emulators with API >= 23. I don't have an Android 5 device to test to see if it is an emulator bug.

    android.view.InflateException: Binary XML file line readium/r2-navigator-kotlin#28: Error inflating class org.readium.r2.navigator.R2WebView
            at android.view.LayoutInflater.createView(LayoutInflater.java:633)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:743)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
            at org.readium.r2.navigator.pager.R2EpubPageFragment.onCreateView(R2EpubPageFragment.kt:52)
            at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
            at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
            at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
            at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
            at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
            at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
            at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
            at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
            at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManagerImpl.java:1696)
            at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:299)
            at org.readium.r2.navigator.pager.R2FragmentPagerAdapter.finishUpdate(R2FragmentPagerAdapter.kt:109)
            at com.duolingo.open.rtlviewpager.DelegatingPagerAdapter.finishUpdate(DelegatingPagerAdapter.java:61)
            at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1244)
            at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1092)
            at androidx.viewpager.widget.ViewPager.onMeasure(ViewPager.java:1622)
            at org.readium.r2.navigator.pager.R2RTLViewPager.onMeasure(R2RTLViewPager.java:229)
            at android.view.View.measure(View.java:17547)
            at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1676)
            at android.view.View.measure(View.java:17547)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:146)
            at android.view.View.measure(View.java:17547)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)
            at androidx.appcompat.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:403)
            at android.view.View.measure(View.java:17547)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at android.view.View.measure(View.java:17547)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)
            at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
            at android.view.View.measure(View.java:17547)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:436)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2615)
            at android.view.View.measure(View.java:17547)
            at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2015)
            at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1173)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1379)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
            at android.view.Choreographer.doCallbacks(Choreographer.java:580)
            at android.view.Choreographer.doFrame(Choreographer.java:550)
    
    bug 
    opened by Judas 11
  • Byte range requests are decrypting the whole resource

    Byte range requests are decrypting the whole resource

    I'm opening this issue here but the code is actually in the streamer.

    When transforming an input stream through the DRMDecoder, the whole resource is read and decrypted in memory, no matter the size of the requested range. This will be a problem for large media files.

    https://github.com/readium/r2-streamer-kotlin/blob/develop/r2-streamer/src/main/java/org/readium/r2/streamer/fetcher/DrmDecoder.kt

    bug 
    opened by mickael-menu 10
  • MultilanguageString

    MultilanguageString

    I can't fully understand the intent behind MultilanguageString objects, used for example for titles. In the Readium manifest specification, a title is either a String, or a map from language to title, not both. In the Epub Metadata Parsing Guide one can't find any mention of "singleString" either. Since, content from dc:title is put into the map after determining the tag language, what is singleString for? Should it contain a copy of the title in the default language for metadata, computed as specified in the Epub Metadata Parsing Guide?

    enhancement 
    opened by qnga 10
  • JavaScript preventDefault

    JavaScript preventDefault

    Hello, I am working on an interactive book for visually impaired children. I'm looking for an epub reader on android that would allow me to interact without being disturbed by the default actions of the reader. iBooks does it very well (see below). image

    Would it be possible to integrate this possibility in your application when using preventDefault ?

    Thank you very much for the work you do.

    bug 
    opened by civodulab 10
  • Full vertical scroll (or less internal components)

    Full vertical scroll (or less internal components)

    I'm using Readium with a specific requirement: full vertical scroll, instead of the existing mix of vertical scroll + swipe to switch chapters. This currently requires skipping a lot of the library UI code and managing my own RecyclerView of chapters with R2WebView items inside. With the version currently in develop this kind of usage becomes harder because a lot of important navigator components are internal like EpubNavigatorViewModel and WebViewServer.

    a) Could the visibility of those components be revised? b) A ViewPager is currently being used for displaying chapter resources. Could a RecyclerView with a PagerSnapHelper be an interesting alternative? That way switching between all pages, scroll + chapter pages, or full scroll would be way easier.

    opened by sdsantos 9
  • Publication Restricted Readium Error

    Publication Restricted Readium Error

    In brief: a valid LCP license, used with the proper passphrase, is ok on some Android devices, but ko on others.

    Details (from a kotlin toolkit + LCP integrator): We have some customers who on opening an ebook, on various Android OS ranging from v6 to v11, receive a Publication restricted flag set as true which leads to org.readium.r2.lcp_r2.LcpException$Unknown. This prevents the individual customer from ever opening the ebook successfully whilst allowing other customers to always open the same ebook without an issue. When we review the customer license file no restriction is found and the license opens the ebook correctly. We have validated our code for the passphrase being used for acquiring License. The passphrase is neither missing or wrong as the same passphrase works for the same book on Android 11 but doesn’t works on Android 7. So, the issue is inconsistent and it behaves differently on different devices and OS.

    How to reproduce the issue: We can replicate this issue in emulators but have not been able to determine the root cause.

    opened by llemeurfr 10
  • Error: org.readium.r2.shared.fetcher.Resource$Exception$NotFound: java.lang.Exception:

    Error: org.readium.r2.shared.fetcher.Resource$Exception$NotFound: java.lang.Exception:

    Bug Report

    we are really stuck after migrated the readium with new version.. In QA team.. they are found one of the book is not getting open in Android but the iOS version is working fine... Please refer the log below.

    The book name: Mustard: Sowing seeds of Fun and Faith Vol 14. Issue 1 It's paid book

    • iOS works fine (attached video demo)
    • Android is incorrect (attached video demo) Readium version on Android
    • val READIUM_VERSION = "2.2.0"
    • readium:liblcp:2.0.5 The log: 2022-11-04 17:17:00.086 24292-25354/com.education.comic.ebook E/PublicationResourceHandler$get: org.readium.r2.shared.fetcher.Resource$Exception$NotFound: java.lang.Exception: No file entry at path OEBPS/fonts/g_font_10.ttf?reload=1664860278828. at org.readium.r2.shared.fetcher.ArchiveFetcher$EntryResource.entry(ArchiveFetcher.kt:63) at org.readium.r2.shared.fetcher.ArchiveFetcher$EntryResource.link(ArchiveFetcher.kt:71) at org.readium.r2.lcp.LcpDecryptor$transform$1.invokeSuspend(LcpDecryptor.kt:36) at org.readium.r2.lcp.LcpDecryptor$transform$1.invoke(Unknown Source:8) at org.readium.r2.lcp.LcpDecryptor$transform$1.invoke(Unknown Source:2) at org.readium.r2.shared.fetcher.LazyResource.resource(Resource.kt:329) at org.readium.r2.shared.fetcher.LazyResource.link(Resource.kt:334) at org.readium.r2.shared.fetcher.ProxyResource.link$suspendImpl(Resource.kt:207) at org.readium.r2.shared.fetcher.ProxyResource.link(Unknown Source:0) at org.readium.r2.streamer.fetcher.HtmlInjector$transform$1.invokeSuspend(HtmlInjector.kt:35) at org.readium.r2.streamer.fetcher.HtmlInjector$transform$1.invoke(Unknown Source:8) at org.readium.r2.streamer.fetcher.HtmlInjector$transform$1.invoke(Unknown Source:2) at org.readium.r2.shared.fetcher.LazyResource.resource(Resource.kt:329) at org.readium.r2.shared.fetcher.LazyResource.link(Resource.kt:334) at org.readium.r2.streamer.server.handler.PublicationResourceHandler.serveResponse(PublicationResourceHandler.kt:79) at org.readium.r2.streamer.server.handler.PublicationResourceHandler.access$serveResponse(PublicationResourceHandler.kt:30) at org.readium.r2.streamer.server.handler.PublicationResourceHandler$get$1.invokeSuspend(PublicationResourceHandler.kt:54) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284) at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85) at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59) at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1) at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38) at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1) at org.readium.r2.streamer.server.handler.PublicationResourceHandler.get(PublicationResourceHandler.kt:45) at org.nanohttpd.router.RouterNanoHTTPD$UriResource.process(RouterNanoHTTPD.java:385) at org.nanohttpd.router.RouterNanoHTTPD$UriRouter.process(RouterNanoHTTPD.java:597) at org.nanohttpd.router.RouterNanoHTTPD.serve(RouterNanoHTTPD.java:672) at org.nanohttpd.protocols.http.NanoHTTPD$1.handle(NanoHTTPD.java:376) at org.nanohttpd.protocols.http.NanoHTTPD$1.handle(NanoHTTPD.java:372) at org.nanohttpd.protocols.http.NanoHTTPD.handle(NanoHTTPD.java:535) at org.nanohttpd.protocols.http.HTTPSession.execute(HTTPSession.java:418) at org.nanohttpd.protocols.http.ClientHandler.run(ClientHandler.java:75) at java.lang.Thread.run(Thread.java:919) Caused by: java.lang.Exception: No file entry at path OEBPS/fonts/g_font_10.ttf?reload=1664860278828. at org.readium.r2.shared.util.archive.JavaZip.entry(JavaZip.kt:91) ios recorded video of working fine. Android showign error..?

    What happened?

    Books open and then showing error

    Expected behavior

    How to reproduce?

    In Android

    Environment

    • Readium version:

    Development environment

    • OS: Android Mobile

    https://user-images.githubusercontent.com/9216373/200786076-b65fa501-d587-4dc6-967e-22356dc4751e.mp4 iOS working App 👍 https://user-images.githubusercontent.com/9216373/200786123-3f218f52-21a5-4ff3-9600-9668a44812e2.mp4

    Testing device

    • Android version:
    • Model: ANy
    • Is it an emulator? Yes or No

    Additional context

    • Are you willing to fix the problem and contribute a pull request? Yes or No
    opened by ajay9889 6
  • Empty Table of Contents List for PDF LCP

    Empty Table of Contents List for PDF LCP

    Bug Report

    What happened?

    We tried to open PDF (LCP) file both in our app and test app. We were able to successfully open it. However, we experienced an empty Table of Contents . We tried the same file without the LCP, we were able to get the Table of Contents successfully.

    mediaType : application/pdf+lcp Extension: lcpdf

    Sample PDF LCP https://tuxedo-preprod-icdp.yondu.net/api/ebook/mobile/lcp/get-book-lcp/be7ec450-4617-4b53-bc92-d910951636ea/293 [passphrase: 293]

    Screenshot of PDF with LCP with table of contents image

    Sample PDF without LCP https://document.desiringgod.org/providence-en.pdf?ts=1614698206

    Screenshot of PDF without LCP with table of contents image

    We tried to view the PDF with LCP in Thorium it can fetch the publication's table contents, however in the test app and Android app, we can't retrieve it. Hope you can assist us on how to fetch it thanks!

    My teammate also notified me that this is also experienced in iOS as well.

    Expected behavior

    We expected to view the table of content list same with the PDF without the LCP. image

    How to reproduce?

    To test Sample PDF with LCP

    1. Press the floating "+" button and select Enter a URL.
    2. Enter https://tuxedo-preprod-icdp.yondu.net/api/ebook/mobile/lcp/get-book-lcp/be7ec450-4617-4b53-bc92-d910951636ea/293
    3. Enter 293 as passphrase.
    4. View Table of Contents (from the Option Hamburger menu).

    To test Sample PDF without LCP

    1. Press the floating "+" button and select Enter a URL.
    2. Enter https://document.desiringgod.org/providence-en.pdf?ts=1614698206
    3. View Table of Contents (from the Option Hamburger menu).

    Environment

    • Readium version: I'm not sure what the Readium version is. We imported the whole project from Github. I tried to get the maven repository for this instead however we are experiencing error when integrating with LCP.

    implementation "readium:liblcp:1.0.0@aar"

    so we copy and pasted the whole library code instead. image

    Development environment

    • OS: Windows 10
    • IDE:

    Android Studio Chipmunk | 2021.2.1 Patch 1 Build #AI-212.5712.43.2112.8609683, built on May 19, 2022 Runtime version: 11.0.12+7-b1504.28-7817840 amd64 VM: OpenJDK 64-Bit Server VM by Oracle Corporation Windows 10 10.0 GC: G1 Young Generation, G1 Old Generation Memory: 1280M Cores: 8 Registry: external.system.auto.import.disabled=true

    Testing device

    • Android version: 10
    • Model: Huawei P20 Pro
    • Is it an emulator? No, However we tested this in an emulator as well. We also tested this from other android devices too.

    Additional context

    • Are you willing to fix the problem and contribute a pull request? Yes or No Sorry I can't right now. But to be transparent, we updated the saving of Highlight DB's primary key to String (generate UUID) to be the same with iOS, so we can sync it with iOS.

    Output logs

    I added Logs to view Table of Content list in PdfReaderFragment (org.readium.r2.testapp.reader) image

    Sample PDF without LCP 2022-09-19 17:34:41.515 12617-12617/org.readium.r2reader D/Readium: publication tableOfContents = [Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=14, type=application/pdf, templated=false, title=Introduction: Four Invitations, rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=28, type=application/pdf, templated=false, title=Part 1: A Definition and a Difficulty , rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=30, type=application/pdf, templated=false, title= 1 What Is Divine Providence?, rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=40, type=application/pdf, templated=false, title= 2 Is Divine Self-Exaltation Good News?, rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=48, type=application/pdf, templated=false, title=Part 2: The Ultimate Goal of Providence , rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=50, type=application/pdf, templated=false, title=Section 1: The Ultimate Goal of Providence before Creation and in Creation , rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=52, type=application/pdf, templated=false, title= 3 Before Creation, rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=60, type=application/pdf, templated=false, title= 4 The Act of Creation, rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=70, type=application/pdf, templated=false, title=Section 2: The Ultimate Goal of Providence in the History of Israel , rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=72, type=application/pdf, templated=false, title= 5 Overview: From Abraham to the Age to Come, rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=88, type=application/pdf, templated=false, title= 6 The Exodus Unfolds, rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=100, type=application/pdf, templated=false, title= 7 Remembering the Exodus, rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=112, type=application/pdf, templated=false, title= 8 The Law, the Wilderness, and the Conquest of Canaan, rels=[], properties=Properties(otherProperties={}), height=null, width=null, bitrate=null, duration=null, languages=[], alternates=[], children=[]), Link(href=/4d144c50-84e2-4323-87c6-ae388d0d47c5.pdf#page=126, type=application/pdf, templated=false, title= 9 The Time of the Judges and the Days of the Monarchy, rels=[], propertie

    Sample PDF LCP 2022-09-19 17:34:36.615 12617-12617/org.readium.r2reader D/Readium: publication tableOfContents = []

    enhancement 
    opened by charchiang14 1
  • Evaluate a media3 navigator

    Evaluate a media3 navigator

    Although it's currently in beta at the time of opening this, media3 is basically replacing media and media2 at this point. media2 hasn't been updated since February 2022. I started playing around with it in the Navigator, which you can find in my media3 branch. I basically took everything in media2 and converted it to use media3 APIs, functions, etc.

    Couple of notes:

    1. The Media3/ExoPlayer counterpart to Media2's SessionPlayer. In playing around, it seems like Player is the right one. However it's missing a few things such as getting the playlist, buffering states, and player state.
    2. Media3/ExoPlayer counterpart to SessionPlayer.PlayerCallback(). Again, it seems like Player.Listener is the right one, but we'll have to see if all of the on methods cover everything. onEvents is also the only one that has a Player passed into it

    Current issues with my branch (actually easier to list what does it work than what doesn't, but oh well)

    1. I haven't quite figured out the APIs to determine whether media is being played, paused, etc. The Player's PlaybackState (which is different than the media PlaybackState) doesn't have states for playing, paused, etc. It has STATE_IDLE, STATE_BUFFERING, STATE_READY, STATE_ENDED. It does have onIsPlayingChanged(boolean isPlaying) and there are comments like "The player will be playing if {@link #getPlayWhenReady()} is true, and paused otherwise" for STATE_READY, but haven't quite figured it all out yet. So none of the playback controls work right now.
    2. The MediaMetadata basically requires you to set a Uri of the file being played. It requires localConfiguration to be set, otherwise it won't play anything, and from what I can tell that can only be set via that Uri
    enhancement 
    opened by stevenzeck 0
Releases(2.3.0)
  • 2.3.0(Dec 28, 2022)

    Resources

    Changelog

    Added

    Shared

    • Extract the raw content (text, images, etc.) of a publication. Take a look at the user guide.
    • Add support for unsafe HTTP redirections with DefaultHttpClient.
      • You will need to opt-in explicitly by implementing DefaultHttpClient.Callback.onFollowUnsafeRedirect.

    Navigator

    • Improved Javascript support in the EPUB navigator:
      • Register custom JavascriptInterface objects to inject native Kotlin code in the EPUB web views.
        EpubNavigatorFragment.createFactory(
            publication = publication,
            …,
            config = EpubNavigatorFragment.Configuration().apply {
                registerJavascriptInterface("customInterface") { link ->
                    MyCustomApi(link)
                }
            }
        )
        
        class MyCustomApi(val link: Link) {
            @JavascriptInterface
            fun api(arg: String): String {
                return "API called from the resource ${link.href} with argument $arg")
            }
        }
        
      • Evaluate JavaScript on the currently visible HTML resource with EpubNavigatorFragment.evaluateJavascript().
        val result = navigator.evaluateJavascript("customInterface.api('argument')")
        
    • New PSPDFKit adapter for rendering PDF documents. Take a look at the user guide.
    • A brand new text-to-speech implementation.
    • Support for custom fonts with the EPUB navigator.
    • New EPUB user preferences, as part of the revamped Settings API:
      • backgroundColor - Default page background color.
      • fontWeight - Base text font weight.
      • textColor - Default page text color.
      • textNormalization - Normalize font style, weight and variants, which improves accessibility.
      • imageFilter - Filter applied to images in dark theme (darken, invert colors)
      • language - Language of the publication content.
      • readingProgression - Direction of the reading progression across resources, e.g. RTL.
      • typeScale - Scale applied to all element font sizes.
      • paragraphIndent - Text indentation for paragraphs.
      • paragraphSpacing - Vertical margins for paragraphs.
      • hyphens - Enable hyphenation.
      • ligatures - Enable ligatures in Arabic.
    • Fixed scroll inertia when scrolling an EPUB.
    • EPUB decorations can now be attached to Locator objects containing only an HTML ID (locations.fragments) or a CSS selector (locations.cssSelector).

    Changed

    Shared

    • TransformingResource now caches its content by default, as it is the correct behavior in most cases. Set cacheBytes = false explicitly to revert to the previous behavior.
    • The previous PDF navigator was extracted in its own package to support third-party PDF engines. This is a breaking change if your app supported PDF, take a look at the migration guide.

    Navigator

    • The EPUB and PDF user preferences API got revamped. Take a look at the user guide and the migration guide to learn how to use it.
    • Decoration.extras is now a Map<String, Any> instead of Bundle. You will need to update your app if you were storing custom data in extras, for example:
      val decoration = Decoration(...,
          extras = mapOf("id" to id)
      )
      
      val id = decoration.extras["id"] as? Long
      

    Deprecated

    Streamer

    Fixed

    Streamer

    • Fixed parsing the table of contents of an EPUB 3 using NCX instead of a Navigation Document.

    Navigator

    • swift-toolkit#61 Fixed serving EPUB resources when the HREF contains an anchor or query parameters.
    • Fixed emitting currentLocator with fixed layout EPUBs.
    • Prevent refreshing an already loaded EPUB resource when jumping to a Locator in it.
    • #86 Fixed page swipes while selecting text in an EPUB resource.
    • The onTap event is not sent when an EPUB text selection is active anymore, to prevent showing the app bar while dismissing a selection.
    • #76 Fixed EPUB fixed layout font size affected by device settings.
    • Decoration objects are now properly comparable with equals().
    • #292 Fix broken pagination when an EPUB uses overflow-x: hidden.
    Source code(tar.gz)
    Source code(zip)
    test-app-2.3.0.apk(35.92 MB)
  • 2.2.1(Oct 24, 2022)

    Resources

    Changelog

    Fixed

    Streamer

    • #286 Fixed broken dependency to NanoHTTPD.

    Migration Guide

    This hotfix release fixes an issue pulling a third-party dependency (NanoHTTPD) from JitPack.

    After upgrading, make sure to remove the dependency to NanoHTTPD from your app's build.gradle file before building:

    -implementation("com.github.edrlab.nanohttpd:nanohttpd:master-SNAPSHOT") {
    -    exclude(group = "org.parboiled")
    -}
    -implementation("com.github.edrlab.nanohttpd:nanohttpd-nanolets:master-SNAPSHOT") {
    -    exclude(group = "org.parboiled")
    -}
    

    :point_up: If you are stuck with an older version of Readium, you can use this workaround in your root build.gradle, as an alternative.

    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Apr 22, 2022)

    Resources

    Changelog

    Added

    Shared

    • A new Publication.conformsTo() API to identify the profile of a publication.
    • Support for the conformsTo RWPM metadata, to identify the profile of a Publication.

    Navigator

    • The PDF navigator now honors the publication reading progression with support for right-to-left and horizontal scrolling.
      • The default (auto) reading progression for PDF is top-to-bottom, which is vertical scrolling.
    • A new convenience utility EdgeTapNavigation to trigger page turns while tapping the screen edges.
      • It takes into account the navigator reading progression to move into the right direction.
      • Call it from the VisualNavigator.Listener.onTap() callback as demonstrated below:
      override fun onTap(point: PointF): Boolean {
          val navigated = edgeTapNavigation.onTap(point, requireView())
          if (!navigated) {
              // Fallback action, for example toggling the app bar.
          }
          return true
      }
      
    • The new Navigator.Listener.onJumpToLocator() API is called every time the navigator jumps to an explicit location, which might break the linear reading progression.
      • For example, it is called when clicking on internal links or programmatically calling Navigator.go(), but not when turning pages.
      • You can use this callback to implement a navigation history by differentiating between continuous and discontinuous moves.
    • You can now disable the display cutouts padding in the EPUB navigator (contributed by @szymn).
      • This is useful when the navigator is not laid out full screen.
    • (experimental) A new audiobook navigator based on Jetpack media2.
      • See the pull request #80 for the differences with the previous audiobook navigator.
      • This navigator is located in its own module readium-navigator-media2. You will need to add it to your dependencies to use it.
      • The Test App demonstrates how to use the new audiobook navigator, see MediaService and AudioReaderFragment.
    • (experimental) The EPUB navigator now supports overridable drag gestures. See VisualNavigator.Listener.

    Deprecated

    Shared

    • Publication.type is now deprecated in favor of the new Publication.conformsTo() API which is more accurate.
      • For example, replace publication.type == Publication.TYPE.EPUB with publication.conformsTo(Publication.Profile.EPUB) before opening a publication with the EpubNavigatorFragment.
    • Link.toLocator() is deprecated as it may create an incorrect Locator if the link type is missing.
      • Use publication.locatorFromLink() instead.

    Fixed

    • Fix building with Kotlin 1.6.

    Streamer

    • Fixed the rendering of PDF covers in some edge cases.
    • Fixed reading ranges of obfuscated EPUB resources.

    Navigator

    • Fixed turning pages of an EPUB reflowable resource with an odd number of columns. A virtual blank trailing column is appended to the resource when displayed as two columns.
    • EPUB: Fallback on reflowable if the presentation.layout hint is missing from a manifest.
    • EPUB: Offset of the current selection's rect to take into account the vertical padding.
    • Improve backward compatibility of JavaScript files using Babel.
    • #193 Fixed invisible <audio> elements.
    Source code(tar.gz)
    Source code(zip)
    test-app-2.2.0.apk(26.57 MB)
  • 2.1.1(Oct 27, 2021)

    Resources

    Changelog

    Changed

    Navigator

    • Improve loading of EPUB reflowable resources.
      • Resources are hidden until fully loaded and positioned.
      • Intermediary locators are not broadcasted as currentLocator anymore while loading a resource.
      • Improved accuracy when jumping to the middle of a large resource.
      • EpubNavigatorFragment.PaginationListener.onPageLoaded() is now called only a single time, for the currently visible page.
      • VisualNavigator.Listener.onTap() is called even when a resource is not fully loaded.

    Fixed

    Navigator

    • EpubNavigatorFragment's goForward() and goBackward() are now jumping to the previous or next pages instead of resources.
    • #20 EPUB navigator stuck between two pages with vertical swipes.
    • #27 Internal links break the EPUB navigator (contributed by @mihai-wolfpack).
    Source code(tar.gz)
    Source code(zip)
    test-app-2.1.1.apk(25.77 MB)
  • 2.1.0(Sep 24, 2021)

    Take a look at the migration guide

    Added

    Shared

    • (alpha) A new Publication SearchService to search through the resources' content, with a default implementation StringSearchService.
    • ContentProtection.Scheme can be used to identify protection technologies using unique URI identifiers.
    • Link objects from archive-based publication assets (e.g. an EPUB/ZIP) have additional properties for entry metadata.
      "properties" {
          "archive": {
              "entryLength": 8273,
              "isEntryCompressed": true
          }
      }
      

    Streamer

    • EPUB publications implement a SearchService to search through the content.
    • Known DRM schemes (LCP and Adobe ADEPT) are now sniffed by the Streamer, when no registered ContentProtection supports them.
      • This is helpful to present an error message when the user attempts to open a protected publication not supported by the app.

    Navigator

    • The EPUB navigator is now able to navigate to a Locator using its text context. This is useful for search results or highlights missing precise locations.
    • Get or clear the current user selection of the navigators implementing SelectableNavigator.
    • (alpha) Support for the Decorator API to draw user interface elements over a publication's content.
      • This can be used to render highlights over a text selection, for example.
      • For now, only the EPUB navigator implements DecorableNavigator, for reflowable publications. You can implement custom decoration styles with HtmlDecorationTemplate.
    • Customize the EPUB selection context menu by providing a custom ActionMode.Callback implementation with EpubNavigatorFragment.Configuration.selectionActionModeCallback.
      • This is an alternative to overriding Activity.onActionModeStarted() which does not seem to work anymore with Android 12.
    • (alpha) A new audiobook navigator based on Android's MediaSession.
      • It supports out-of-the-box media style notifications and background playback.
      • ExoPlayer is used by default for the actual playback, but you can use a custom player by implementing MediaPlayer.

    OPDS

    • New APIs using coroutines and R2's HttpClient instead of Fuel and kovenant (contributed by @stevenzeck).

    Changed

    • Upgraded to Kotlin 1.5.31 and Gradle 7.1.1

    Streamer

    • The default EPUB positions service now uses the archive entry length when available. This is similar to how Adobe RMSDK generates page numbers.
      • To use the former strategy, create the Streamer with: Streamer(parsers = listOf(EpubParser(reflowablePositionsStrategy = OriginalLength(pageLength = 1024))))

    Navigator

    • The order of precedence of Locator locations in the reflowable EPUB navigator is: text, HTML ID, then progression. The navigator will now fallback on less precise locations in case of failure.

    LCP

    • Migrated to Jetpack Room for the SQLite database storing rights and passphrases (contributed by @stevenzeck).
      • Note that the internal SQL schema changed. You will need to update your app if you were querying the database manually.

    Fixed

    Shared

    • Crash with HttpRequest.setPostForm() on Android 6.
    • HREF normalization when a resource path contains special characters.

    Streamer

    • EPUB style injection when a resource has a <head> tag with attributes.

    Navigator

    • When restoring a Locator, The PDF navigator now falls back on locations.position if the page= fragment identifier is missing.

    OPDS

    • Links in an OPDS 2 feed are normalized to the feed base URL.
    Source code(tar.gz)
    Source code(zip)
    r2-testapp-2.1.0.apk(60.94 MB)
Owner
Readium
Our mission is to foster the development of an open and modern collaborative playground for digital reading technologies.
Readium
Android app built with MVP architectural approach and uses Marvel Comics API that allows developers everywhere to access information about Marvel's vast library of comics. :zap:

Villains & Heroes Android app built with MVP architectural approach and uses Marvel Comics API that allows developers everywhere to access information

André Mion 53 Jul 13, 2022
ComicsShow app: Display comics and search for any favourites one

ComicsShow app: Display comics and search for any favourites one. Technologies used: Koin: For injecting class and providing modules on runtime :). Vi

Ahmed Gamal Yousef 1 Nov 21, 2021
A powerful cross-platform UI toolkit for building native-quality iOS, Android, and Progressive Web Apps with HTML, CSS, and JavaScript.

Ionic Ionic is an open source app development toolkit for building modern, fast, top-quality cross-platform native and Progressive Web Apps from a sin

Ionic 48.4k Jan 3, 2023
Sample app demonstrating interop between Jetpack Compose and the Android UI toolkit, including SurfaceView

Wake Me Up Wake Me Up is a sample app showcased in the Google I/O 2021 Developer Keynote that demonstrates interoperability between Jetpack Compose an

Romain Guy 174 Dec 5, 2022
WalletConnect Kit is the Swiss Army toolkit for WalletConnect!

WalletConnectKit WalletConnectKit is the Swiss Army toolkit for WalletConnect! It will allow you to connect your DApp with an Ethereum Wallet in a few

Pink Room 52 Nov 24, 2022
Samples demonstrating the features and use of Koala Plot, a Compose Multiplatform based charting and plotting library written in Kotlin.

Koala Plot Samples This repository houses samples demonstrating the use and features of Koala Plot libraries. How to run Build koalaplot-core with the

Koala Plot 6 Oct 18, 2022
A full-stack application showing the power 💪 of KOTLIN. Entire android app + backend Apis written in Kotlin 🔥

Gamebaaz ?? A full-stack application showing the power ?? of KOTLIN. Entire android app + backend Apis written in Kotlin ?? Android Backend Jetpack Co

Sarnava Konar 85 Nov 17, 2022
Episodie is a TV show time tracker app with unusual design written in kotlin and clean architecture approach. Get to know how much time you spent watching tv shows.

Episodie Episodie is a TV show time tracker app with unusual design. Get to know how much time you spent watching tv shows. Track easily overall progr

Przemek 126 Dec 7, 2022
📚 Sample Android Components Architecture on a modular word focused on the scalability, testability and maintainability written in Kotlin, following best practices using Jetpack.

Android Components Architecture in a Modular Word Android Components Architecture in a Modular Word is a sample project that presents modern, 2020 app

Madalin Valceleanu 2.3k Jan 3, 2023
An application to manage SSH and GPG keys on GitHub written in Kotlin.

KeyManager An application to manage SSH and GPG keys on GitHub written in Kotlin. Thanks to FreePik for the app icon. Screenshots Building You will ne

Yash Garg 28 Dec 21, 2022
Movie Android App written in Kotlin, MVVM, RxJava, Coroutine (Upcoming), Android Architecture Components and Jetpack Compose (Upcoming).

MovieHunt MovieHunt is a sample Android project using The Movie DB API based on MVVM architecture. It showcases the latest Android tech stacks with we

Engine Bai 596 Dec 31, 2022
A Tip Calculator app written in Kotlin that takes Total cost as an input and calculate tip according to the feedbacks.

Create a Tip Calculator App Code for the Android Basics in Kotlin: Create a Tip Calculator app codelab. In this codelab, you will be writing code for

Hemant Sachdeva 1 Dec 4, 2021
🚀 Sample Android Clean Architecture on Rorty App focused on the scalability, testability and maintainability written in Kotlin, following best practices using Jetpack.

Android Clean Architecture Android Clean Architecture in Rorty is a sample project that presents modern, approach to Android application development u

Mr.Sanchez 0 Dec 28, 2021
A simple login and logout Android application written in Kotlin

A simple login and logout Android application written in Kotlin. It authorizes user using an api and shows profile screen.

Emre Uysal 4 Aug 2, 2022
Simple Notes app, MVVM with Google Architectural components Room database, LiveData and ViewModel. Written in Kotlin using androidx libraries

Simple Notes app, MVVM with Google Architectural components Room database, LiveData and ViewModel. Written in Kotlin using androidx libraries. Implemented Firebase Auth and Database, and used Room database

Javokhir Jambulov 3 Aug 1, 2022
A modular and portable open source XMPP client library written in Java for Android and Java (SE) VMs

Smack About Smack is an open-source, highly modular, easy to use, XMPP client library written in Java for Java SE compatible JVMs and Android. Being a

Ignite Realtime 2.3k Dec 28, 2022
A modular and portable open source XMPP client library written in Java for Android and Java (SE) VMs

Smack About Smack is an open-source, highly modular, easy to use, XMPP client library written in Java for Java SE compatible JVMs and Android. Being a

Ignite Realtime 2.3k Dec 21, 2021
A showcase music app for Android entirely written using Kotlin language

Bandhook Kotlin This project is a small replica of the app I developed some time ago. Bandhook can still be found on Play Store At the moment it will

Antonio Leiva 1.9k Dec 23, 2022
Utility Android app for generating color palettes of images using the Palette library. Written in Kotlin.

Palette Helper is a simple utility app made to generate color palettes of images using Google's fantastic Palette library. It's mostly a for-fun pet p

Zac Sweers 154 Nov 18, 2022