Skip to content

Commit 5b718ad

Browse files
authored
Update the documentation for Readium 3.0.0-alpha.1 (readium#441)
1 parent 4bd2893 commit 5b718ad

File tree

41 files changed

+872
-255
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+872
-255
lines changed

CHANGELOG.md

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,65 @@ All notable changes to this project will be documented in this file. Take a look
66

77
## [Unreleased]
88

9+
:warning: Please consult [the migration guide](docs/migration-guide.md#300-alpha1) to assist you in handling the breaking changes in this latest major release.
10+
911
### Added
1012

13+
#### Shared
14+
15+
* A new `Format` type was introduced to augment `MediaType` with more precise information about the format specifications of an `Asset`.
16+
* The `DownloadManager` interface handles HTTP downloads. Components like the `LcpService` rely on it for downloading publications. Readium v3 ships with two implementations:
17+
* `ForegroundDownloadManager` uses an `HttpClient` to download files while the app is running.
18+
* `AndroidDownloadManager` is built upon [Android's `DownloadManager`](https://developer.android.com/reference/android/app/DownloadManager) to manage HTTP downloads, even when the application is closed. It allows for resuming downloads after losing connection.
19+
* The default `ZipArchiveOpener` now supports streaming ZIP archives, which enables opening a packaged publication (e.g. EPUB or LCP protected audiobook):
20+
* served by a remote HTTP server,
21+
* accessed through an Android `ContentProvider`, such as the shared storage.
22+
1123
#### Navigator
1224

1325
* Support for keyboard events in the EPUB, PDF and image navigators. See `VisualNavigator.addInputListener()`.
1426

15-
### Fixed
27+
#### LCP
1628

17-
#### OPDS
29+
* You can now stream an LCP protected publication using its LCP License Document. This is useful for example to read a large audiobook without downloading it on the device first.
30+
* The hash of protected publications is now verified upon download.
31+
32+
### Changed
33+
34+
* :warning: To avoid conflicts when merging your app resources, all resources declared in the Readium toolkit now have the prefix `readium_`. This means that you must rename any layouts or strings you have overridden. Some resources were removed from the toolkit. Please consult [the migration guide](docs/migration-guide.md#300-alpha1).
35+
* Most APIs now return an `Error` instance instead of an `Exception` in case of failure, as these objects are not thrown by the toolkit but returned as values
36+
37+
#### Shared
38+
39+
* :warning: To improve the interoperability with other Readium toolkits (in particular the Readium Web Toolkits, which only work in a streaming context) **Readium v3 now generates and expects valid URLs** for `Locator` and `Link`'s `href`. **You must migrate the HREFs or Locators stored in your database**, please consult [the migration guide](docs/migration-guide.md#300-alpha1).
40+
* `Link.href` and `Locator.href` are now respectively `Href` and `Url` objects. If you still need the string value, you can call `toString()`
41+
* `MediaType` no longer has static helpers for sniffing it from a file or URL. Instead, you can use an `AssetRetriever` to retrieve the format of a file.
42+
43+
#### Navigator
44+
45+
* Version 3 includes a new component called `DirectionalNavigationAdapter` that replaces `EdgeTapNavigation`. This helper enables users to navigate between pages using arrow and space keys on their keyboard or by tapping the edge of the screen.
46+
* The `onTap` and `onDrag` events of `VisualNavigator.Listener` have been deprecated. You can now use multiple implementations of `InputListener` with `VisualNavigator.addInputListener()`.
47+
48+
#### Streamer
49+
50+
* The `Streamer` object has been deprecated in favor of components with smaller responsibilities: `AssetRetriever` and `PublicationOpener`.
51+
52+
#### LCP
53+
54+
* `LcpService.acquirePublication()` is deprecated in favor of `LcpService.publicationRetriever()`, which provides greater flexibility thanks to the `DownloadManager`.
55+
* The way the host view of a `LcpDialogAuthentication` is retrieved was changed to support Android configuration changes.
56+
57+
### Deprecated
58+
59+
* Both the Fuel and Kovenant libraries have been completely removed from the toolkit. With that, several deprecated functions have also been removed.
60+
61+
#### Shared
62+
63+
* The `putPublication` and `getPublication` helpers in `Intent` are deprecated. Now, it is the application's responsibility to pass `Publication` objects between activities and reopen them when necessary.
64+
65+
#### Navigator
1866

19-
* Fixed race conditions causing `ConcurrentModificationException` to be thrown when parsing an OPDS 2 feed.
67+
* EPUB external links are no longer handled by the navigator. You need to open the link in your own Web View or Chrome Custom Tab.
2068

2169

2270
## [2.4.0]

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ A [Test App](test-app) demonstrates how to integrate the Readium Kotlin toolkit
1919

2020
## Minimum Requirements
2121

22-
| Readium | Android min SDK | Android compile SDK | Kotlin compiler | Gradle |
23-
|---------|-----------------|---------------------|-----------------|--------|
24-
| 3.0.0 | 21 | 34 | 1.9.0 | 8.0.0 |
25-
| 2.3.0 | 21 | 33 | 1.7.10 | 6.9.3 |
22+
| Readium | Android min SDK | Android compile SDK | Kotlin compiler (✻) | Gradle (✻) |
23+
|---------|-----------------|---------------------|---------------------|------------|
24+
| 3.0.0 | 21 | 34 | 1.9.0 | 8.0.0 |
25+
| 2.3.0 | 21 | 33 | 1.7.10 | 6.9.3 |
26+
27+
✻ Only required if you integrate Readium as a submodule instead of using Maven Central.
2628

2729
## Setting Up Readium
2830

docs/guides/media-navigator.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ navigator.playback
3838

3939
val playingItem = navigator.readingOrder.items[playback.index]
4040

41-
if (playback.state is MediaNavigator.State.Error) {
41+
if (playback.state is MediaNavigator.State.Failure) {
4242
// Alert
4343
}
4444
}

docs/guides/open-publication.md

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,58 @@
11
# Opening a publication
22

3-
:warning: The described components are is still experimental.
3+
:warning: The APIs described here may still undergo changes before the stable 3.0 release.
44

5-
Readium requires you to instantiate a few components before you can actually open a publication.
5+
To open a publication with Readium, you need to instantiate a couple of components: an `AssetRetriever` and a `PublicationOpener`.
66

7-
## Constructing an `AssetRetriever`
7+
## `AssetRetriever`
88

9-
First, you need to instantiate an `HttpClient` to provide the toolkit the ability to do HTTP requests.
10-
You can use the Readium `DefaultHttpClient` or a custom implementation. In the former case, its callback will
11-
enable you to perform authentication when required.
12-
Then, you can create an `AssetRetriever` which will enable you to read content through different schemes and guess its format.
13-
In addition to an `HttpClient`, the `AssetRetriever` constructor takes a `ContentResolver` to support data access through the `content` scheme.
9+
The `AssetRetriever` grants access to the content of an asset located at a given URL, such as a publication package, manifest, or LCP license.
10+
11+
### Constructing an `AssetRetriever`
12+
13+
You can create an instance of `AssetRetriever` with:
14+
15+
* A `ContentResolver` to support data access through the `content` URL scheme.
16+
* An `HttpClient` to enable the toolkit to perform HTTP requests and support the `http` and `https` URL schemes. You can use `DefaultHttpClient` which provides callbacks for handling authentication when needed.
1417

1518
```kotlin
1619
val httpClient = DefaultHttpClient()
17-
1820
val assetRetriever = AssetRetriever(context.contentResolver, httpClient)
1921
```
2022

21-
## Constructing a `PublicationOpener`
23+
### Retrieving an `Asset`
2224

23-
The component which can parse an `Asset` giving access to a publication to build a `Publication`
24-
object is the `PublicationOpener`. Its constructor requires you to pass in:
25+
With your fresh instance of `AssetRetriever`, you can open an `Asset` from an `AbsoluteUrl`.
2526

26-
* a `PublicationParser` it delegates the parsing work to.
27-
* a list of `ContentProtection`s which will deal with DRMs.
27+
```kotlin
28+
// From a `File`
29+
val url = File("...").toUrl()
30+
// or from a content:// `Uri`
31+
val url = contentUri.toAbsoluteUrl()
32+
// or from a raw URL string
33+
val url = AbsoluteUrl("https://domain/book.epub")
34+
35+
val asset = assetRetriever.retrieve(url)
36+
.getOrElse { /* Failed to retrieve the Asset */ }
37+
```
2838

29-
The easiest way to get a `PublicationParser` is to use the `DefaultPublicationParser` class. As to
30-
`ContentProtection`s, you can get one to support LCP publications through your `LcpService` if you have one.
39+
The `AssetRetriever` will sniff the media type of the asset, which you can store in your bookshelf database to speed up the process next time you retrieve the `Asset`. This will improve performance, especially with HTTP URL schemes.
40+
41+
```kotlin
42+
val mediaType = asset.format.mediaType
43+
44+
// Speed up the retrieval with a known media type.
45+
val asset = assetRetriever.retrieve(url, mediaType)
46+
```
47+
48+
## `PublicationOpener`
49+
50+
`PublicationOpener` builds a `Publication` object from an `Asset` using:
51+
52+
* A `PublicationParser` to parse the asset structure and publication metadata.
53+
* The `DefaultPublicationParser` handles all the formats supported by Readium out of the box.
54+
* An optional list of `ContentProtection` to decrypt DRM-protected publications.
55+
* If you support Readium LCP, you can get one from the `LcpService`.
3156

3257
```kotlin
3358
val contentProtections = listOf(lcpService.contentProtection(authentication))
@@ -37,34 +62,25 @@ val publicationParser = DefaultPublicationParser(context, httpClient, assetRetri
3762
val publicationOpener = PublicationOpener(publicationParser, contentProtections)
3863
```
3964

40-
## Bringing the pieces together
65+
### Opening a `Publication`
4166

42-
Once you have got an `AssetRetriever` and a `PublicationOpener`, you can eventually open a publication as follows:
43-
```kotlin
44-
val asset = assetRetriever.open(url, mediaType)
45-
.getOrElse { return error }
67+
Now that you have a `PublicationOpener` ready, you can use it to create a `Publication` from an `Asset` that was previously obtained using the `AssetRetriever`.
4668

47-
val publication = publicationOpener.open(asset)
48-
.getOrElse { return error }
49-
```
69+
The `allowUserInteraction` parameter is useful when supporting Readium LCP. When enabled and using a `LcpDialogAuthentication`, the toolkit will prompt the user if the passphrase is missing.
5070

51-
Persisting the asset media type on the device can significantly improve performance as it is strong hint
52-
for the content format, especially in case of remote publications.
71+
```kotlin
72+
val publication = publicationOpener.open(asset, allowUserInteraction = true)
73+
.getOrElse { /* Failed to access or parse the publication */ }
74+
```
5375

5476
## Supporting additional formats or URL schemes
5577

56-
`DefaultPublicationParser` accepts additional parsers. You can also use your own parser list
57-
with `CompositePublicationParser` or implement [PublicationParser] in the way you like.
58-
59-
`AssetRetriever` offers an alternative constructor providing better extensibility in a similar way.
60-
This constructor takes several parameters with different responsibilities.
61-
62-
* `ResourceFactory` determines which schemes you will be able to access content through.
63-
* `ArchiveOpener` which kinds of archives your `AssetRetriever` will be able to open.
64-
* `FormatSniffer` which file formats your `AssetRetriever` will be able to identify.
78+
`DefaultPublicationParser` accepts additional parsers. You also have the option to use your own parser list by using `CompositePublicationParser` or create your own `PublicationParser` for a fully customized parsing resolution strategy.
6579

66-
For each of these components, you can either use the default implementations or implement yours
67-
with the composite pattern. `CompositeResourceFactory`, `CompositeArchiveOpener` and `CompositeFormatSniffer`
68-
provide simple implementations trying every item of a list in turns.
80+
The `AssetRetriever` offers an additional constructor that provides greater extensibility options, using:
6981

82+
* `ResourceFactory` which handles the URL schemes through which you can access content.
83+
* `ArchiveOpener` which determines the types of archives (ZIP, RAR, etc.) that can be opened by the `AssetRetriever`.
84+
* `FormatSniffer` which identifies the file formats that `AssetRetriever` can recognize.
7085

86+
You can use either the default implementations or implement your own for each of these components using the composite pattern. The toolkit's `CompositeResourceFactory`, `CompositeArchiveOpener`, and `CompositeFormatSniffer` provide a simple resolution strategy.

docs/guides/tts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ If the device lacks the data necessary for the chosen voice, the user needs to m
115115
```kotlin
116116
navigator.playback
117117
.onEach { playback ->
118-
(playback?.state as? TtsNavigator.State.Error.EngineError<*>)
118+
(playback?.state as? TtsNavigator.State.Failure.EngineError<*>)
119119
?.let { it.error as? AndroidTtsEngine.Error.LanguageMissingData }
120120
?.let { error ->
121121
Timber.e("Missing data for language ${error.language}")

0 commit comments

Comments
 (0)