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

Replace Date with Instant #506

Merged
merged 2 commits into from
Apr 30, 2024
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 @@ -12,6 +12,10 @@ All notable changes to this project will be documented in this file. Take a look

* All the `completion` parameters of the `Navigator` APIs are removed.

### Changed

* All the APIs using or returning a `Date` objects are now using a custom `Instant` type.

### Fixed

#### Navigator
Expand Down
6 changes: 6 additions & 0 deletions docs/migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ All migration steps necessary in reading apps to upgrade to major versions of th

If you target Android devices running below API 26, you now must enable [core library desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) in your application module.

### Removing JVM dependencies

To reduce our depency to the JVM, we no longer use `Date` objects in the toolkit. Instead, we added a custom `Instant` type.

You can still translate from and to a `Date` object with `Instant.fromJavaDate()` and `instant.toJavaDate()`.


## 3.0.0-alpha.2

Expand Down
14 changes: 7 additions & 7 deletions readium/lcp/src/main/java/org/readium/r2/lcp/LcpError.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
package org.readium.r2.lcp

import java.net.SocketTimeoutException
import java.util.*
import kotlinx.coroutines.CancellationException
import org.readium.r2.lcp.service.NetworkException
import org.readium.r2.shared.util.DebugError
import org.readium.r2.shared.util.Error
import org.readium.r2.shared.util.ErrorException
import org.readium.r2.shared.util.Instant
import org.readium.r2.shared.util.ThrowableError
import org.readium.r2.shared.util.Url

Expand Down Expand Up @@ -72,16 +72,16 @@ public sealed class LcpError(
cause: Error? = null
) : LcpError(message, cause) {

public class Cancelled(public val date: Date) :
public class Cancelled(public val date: Instant) :
LicenseStatus("This license was cancelled on $date")

public class Returned(public val date: Date) :
public class Returned(public val date: Instant) :
LicenseStatus("This license has been returned on $date")

public class NotStarted(public val start: Date) :
public class NotStarted(public val start: Instant) :
LicenseStatus("This license starts on $start")

public class Expired(public val end: Date) :
public class Expired(public val end: Instant) :
LicenseStatus("This license expired on $end")

/**
Expand All @@ -90,7 +90,7 @@ public sealed class LcpError(
* in the status document. If no event is logged in the status document, no such message should
* appear (certainly not "The license was registered by 0 devices").
*/
public class Revoked(public val date: Date, public val devicesCount: Int) :
public class Revoked(public val date: Instant, public val devicesCount: Int) :
LicenseStatus(
"This license was revoked by its provider on $date. It was registered by $devicesCount device(s)."
)
Expand All @@ -109,7 +109,7 @@ public sealed class LcpError(
Renew("Publication could not be renewed properly")

/** Incorrect renewal period, your publication could not be renewed. */
public class InvalidRenewalPeriod(public val maxRenewDate: Date?) :
public class InvalidRenewalPeriod(public val maxRenewDate: Instant?) :
Renew("Incorrect renewal period, your publication could not be renewed")

/** An unexpected error has occurred on the licensing server. */
Expand Down
8 changes: 4 additions & 4 deletions readium/lcp/src/main/java/org/readium/r2/lcp/LcpLicense.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
package org.readium.r2.lcp

import java.net.URL
import java.util.*
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.StateFlow
Expand All @@ -18,6 +17,7 @@ import org.readium.r2.lcp.license.model.LicenseDocument
import org.readium.r2.lcp.license.model.StatusDocument
import org.readium.r2.shared.publication.services.ContentProtectionService
import org.readium.r2.shared.util.Closeable
import org.readium.r2.shared.util.Instant
import org.readium.r2.shared.util.Try
import org.readium.r2.shared.util.Url
import org.readium.r2.shared.util.toDebugDescription
Expand Down Expand Up @@ -59,15 +59,15 @@ public interface LcpLicense : ContentProtectionService.UserRights, Closeable {
* The maximum potential date to renew to.
* If null, then the renew date might not be customizable.
*/
public val maxRenewDate: Date?
public val maxRenewDate: Instant?

/**
* Renews the loan by starting a renew LSD interaction.
*
* @param prefersWebPage Indicates whether the loan should be renewed through a web page if
* available, instead of programmatically.
*/
public suspend fun renewLoan(listener: RenewListener, prefersWebPage: Boolean = false): Try<Date?, LcpError>
public suspend fun renewLoan(listener: RenewListener, prefersWebPage: Boolean = false): Try<Instant?, LcpError>

/**
* Can the user return the loaned publication?
Expand Down Expand Up @@ -98,7 +98,7 @@ public interface LcpLicense : ContentProtectionService.UserRights, Closeable {
*
* The returned date can't exceed [maximumDate].
*/
public suspend fun preferredEndDate(maximumDate: Date?): Date?
public suspend fun preferredEndDate(maximumDate: Instant?): Instant?

/**
* Called when the renew interaction uses an HTML web page.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.browser.customtabs.CustomTabsIntent
import androidx.fragment.app.FragmentManager
import com.google.android.material.datepicker.*
import java.util.*
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.suspendCancellableCoroutine
import org.readium.r2.shared.util.Instant
import org.readium.r2.shared.util.Url

/**
Expand All @@ -37,9 +37,9 @@ public class MaterialRenewListener(
private val fragmentManager: FragmentManager
) : LcpLicense.RenewListener {

override suspend fun preferredEndDate(maximumDate: Date?): Date? = suspendCancellableCoroutine { cont ->
val start = (license.license.rights.end ?: Date()).time
val end = maximumDate?.time
override suspend fun preferredEndDate(maximumDate: Instant?): Instant? = suspendCancellableCoroutine { cont ->
val start = (license.license.rights.end ?: Instant.now()).toEpochMilliseconds()
val end = maximumDate?.toEpochMilliseconds()

MaterialDatePicker.Builder.datePicker()
.setCalendarConstraints(
Expand Down Expand Up @@ -67,7 +67,7 @@ public class MaterialRenewListener(
addOnNegativeButtonClickListener { cont.cancel() }

addOnPositiveButtonClickListener { selection ->
cont.resume(Date(selection))
cont.resume(Instant.fromEpochMilliseconds(selection))
}
}
.show(fragmentManager, "MaterialRenewListener.DatePicker")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
package org.readium.r2.lcp.license

import java.net.HttpURLConnection
import java.util.Date
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -30,8 +29,8 @@ import org.readium.r2.lcp.service.DeviceService
import org.readium.r2.lcp.service.LcpClient
import org.readium.r2.lcp.service.LicensesRepository
import org.readium.r2.lcp.service.NetworkService
import org.readium.r2.shared.extensions.toIso8601String
import org.readium.r2.shared.extensions.tryOrNull
import org.readium.r2.shared.util.Instant
import org.readium.r2.shared.util.Try
import org.readium.r2.shared.util.getOrElse
import org.readium.r2.shared.util.getOrThrow
Expand Down Expand Up @@ -144,10 +143,10 @@ internal class License private constructor(
override val canRenewLoan: Boolean
get() = status?.link(StatusDocument.Rel.Renew) != null

override val maxRenewDate: Date?
override val maxRenewDate: Instant?
get() = status?.potentialRights?.end

override suspend fun renewLoan(listener: LcpLicense.RenewListener, prefersWebPage: Boolean): Try<Date?, LcpError> {
override suspend fun renewLoan(listener: LcpLicense.RenewListener, prefersWebPage: Boolean): Try<Instant?, LcpError> {
// Finds the renew link according to `prefersWebPage`.
fun findRenewLink(): Link? {
val status = documents.status ?: return null
Expand Down Expand Up @@ -179,7 +178,7 @@ internal class License private constructor(

val parameters = this.device.asQueryParameters.toMutableMap()
if (endDate != null) {
parameters["end"] = endDate.toIso8601String()
parameters["end"] = endDate.toString()
}

val url = link.url(parameters = parameters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.readium.r2.lcp.service.DeviceService
import org.readium.r2.lcp.service.LcpClient
import org.readium.r2.lcp.service.NetworkService
import org.readium.r2.lcp.service.PassphrasesService
import org.readium.r2.shared.util.Instant
import org.readium.r2.shared.util.getOrElse
import org.readium.r2.shared.util.mediatype.MediaType
import timber.log.Timber
Expand Down Expand Up @@ -388,7 +389,7 @@ internal class LicenseValidation(
statusDocumentTakesPrecedence: Boolean
) {
var error: LcpError.LicenseStatus? = null
val now = Date()
val now = Instant.now()
val start = license.rights.start ?: now
val end = license.rights.end ?: now
val isLicenseExpired = (start > now || now > end)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
package org.readium.r2.lcp.license.model

import java.nio.charset.Charset
import java.util.*
import org.json.JSONObject
import org.readium.r2.lcp.LcpError
import org.readium.r2.lcp.LcpException
Expand All @@ -21,9 +20,9 @@ import org.readium.r2.lcp.license.model.components.lcp.Rights
import org.readium.r2.lcp.license.model.components.lcp.Signature
import org.readium.r2.lcp.license.model.components.lcp.User
import org.readium.r2.lcp.service.URLParameters
import org.readium.r2.shared.extensions.iso8601ToDate
import org.readium.r2.shared.extensions.optNullableString
import org.readium.r2.shared.util.AbsoluteUrl
import org.readium.r2.shared.util.Instant
import org.readium.r2.shared.util.Try
import org.readium.r2.shared.util.Url
import org.readium.r2.shared.util.mediatype.MediaType
Expand Down Expand Up @@ -63,14 +62,14 @@ public class LicenseDocument internal constructor(public val json: JSONObject) {
json.optNullableString("id")
?: throw LcpException(LcpError.Parsing.LicenseDocument)

public val issued: Date =
public val issued: Instant =
json.optNullableString("issued")
?.iso8601ToDate()
?.let { Instant.parse(it) }
?: throw LcpException(LcpError.Parsing.LicenseDocument)

public val updated: Date =
public val updated: Instant =
json.optNullableString("updated")
?.iso8601ToDate()
?.let { Instant.parse(it) }
?: issued

public val encryption: Encryption =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ import org.readium.r2.lcp.license.model.components.Links
import org.readium.r2.lcp.license.model.components.lsd.Event
import org.readium.r2.lcp.license.model.components.lsd.PotentialRights
import org.readium.r2.lcp.service.URLParameters
import org.readium.r2.shared.extensions.iso8601ToDate
import org.readium.r2.shared.extensions.mapNotNull
import org.readium.r2.shared.extensions.optNullableString
import org.readium.r2.shared.util.Instant
import org.readium.r2.shared.util.Url
import org.readium.r2.shared.util.mediatype.MediaType

public class StatusDocument(public val data: ByteArray) {
public val id: String
public val status: Status
public val message: String
public val licenseUpdated: Date
public val statusUpdated: Date
public val licenseUpdated: Instant
public val statusUpdated: Instant
public val links: Links
public val potentialRights: PotentialRights?
public val events: List<Event>
Expand All @@ -49,7 +49,7 @@ public class StatusDocument(public val data: ByteArray) {
public val rawValue: String get() = value

public companion object {
public operator fun invoke(value: String): Status? = values().firstOrNull { it.value == value }
public operator fun invoke(value: String): Status? = entries.firstOrNull { it.value == value }
}
}

Expand All @@ -63,7 +63,7 @@ public class StatusDocument(public val data: ByteArray) {
public val rawValue: String get() = value

public companion object {
public operator fun invoke(value: String): Rel? = values().firstOrNull { it.value == value }
public operator fun invoke(value: String): Rel? = entries.firstOrNull { it.value == value }
Copy link
Member Author

Choose a reason for hiding this comment

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

That was a deprecation notice in Android Studio.

}
}

Expand All @@ -83,10 +83,10 @@ public class StatusDocument(public val data: ByteArray) {
)

val updated = json.optJSONObject("updated") ?: JSONObject()
licenseUpdated = updated.optNullableString("license")?.iso8601ToDate() ?: throw LcpException(
licenseUpdated = updated.optNullableString("license")?.let { Instant.parse(it) } ?: throw LcpException(
LcpError.Parsing.StatusDocument
)
statusUpdated = updated.optNullableString("status")?.iso8601ToDate() ?: throw LcpException(
statusUpdated = updated.optNullableString("status")?.let { Instant.parse(it) } ?: throw LcpException(
LcpError.Parsing.StatusDocument
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,25 @@

package org.readium.r2.lcp.license.model.components.lcp

import java.util.*
import org.json.JSONObject
import org.readium.r2.shared.extensions.iso8601ToDate
import org.readium.r2.shared.extensions.optNullableInt
import org.readium.r2.shared.extensions.optNullableString
import org.readium.r2.shared.util.Instant

public data class Rights(val json: JSONObject) {
val print: Int?
val copy: Int?
val start: Date?
val end: Date?
val start: Instant?
val end: Instant?
val extensions: JSONObject

init {
val clone = JSONObject(json.toString())

print = clone.optNullableInt("print", remove = true)
copy = clone.optNullableInt("copy", remove = true)
start = clone.optNullableString("start", remove = true)?.iso8601ToDate()
end = clone.optNullableString("end", remove = true)?.iso8601ToDate()
start = clone.optNullableString("start", remove = true)?.let { Instant.parse(it) }
end = clone.optNullableString("end", remove = true)?.let { Instant.parse(it) }

extensions = clone
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@

package org.readium.r2.lcp.license.model.components.lsd

import java.util.*
import org.json.JSONObject
import org.readium.r2.shared.extensions.iso8601ToDate
import org.readium.r2.shared.extensions.optNullableString
import org.readium.r2.shared.util.Instant

public data class Event(val json: JSONObject) {
val type: String = json.optNullableString("type") ?: ""
val name: String = json.optNullableString("name") ?: ""
val id: String = json.optNullableString("id") ?: ""
val date: Date? = json.optNullableString("timestamp")?.iso8601ToDate()
val date: Instant? = json.optNullableString("timestamp")?.let { Instant.parse(it) }

public enum class EventType(public val value: String) {
Register("register"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@

package org.readium.r2.lcp.license.model.components.lsd

import java.util.*
import org.json.JSONObject
import org.readium.r2.shared.extensions.iso8601ToDate
import org.readium.r2.shared.extensions.optNullableString
import org.readium.r2.shared.util.Instant

public data class PotentialRights(val json: JSONObject) {
val end: Date? = json.optNullableString("end")?.iso8601ToDate()
val end: Instant? = json.optNullableString("end")?.let { Instant.parse(it) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -237,12 +237,12 @@ public class ImageNavigatorFragment private constructor(

@Suppress("DEPRECATION")
@Deprecated(
"Use `presentation.value.readingProgression` instead",
replaceWith = ReplaceWith("presentation.value.readingProgression"),
"Use `overflow.value.readingProgression` instead",
replaceWith = ReplaceWith("overflow.value.readingProgression"),
level = DeprecationLevel.ERROR
)
override val readingProgression: PublicationReadingProgression =
publication.metadata.effectiveReadingProgression
throw NotImplementedError()

@ExperimentalReadiumApi
override val overflow: StateFlow<OverflowableNavigator.Overflow> =
Expand Down
Loading
Loading