diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index e0be883ca7..e543e1eec5 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -13,9 +13,9 @@ jobs: if: ${{ !github.event.pull_request.draft }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '17' distribution: 'adopt' @@ -30,9 +30,9 @@ jobs: if: ${{ !github.event.pull_request.draft }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '17' distribution: 'adopt' @@ -47,14 +47,14 @@ jobs: scripts: ${{ 'readium/navigator/src/main/assets/_scripts' }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@v4 with: package_json_file: readium/navigator/src/main/assets/_scripts/package.json run_install: false - name: Setup cache - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20 cache: 'pnpm' diff --git a/.gitignore b/.gitignore index 7ff29501cc..cb239629fc 100644 --- a/.gitignore +++ b/.gitignore @@ -91,3 +91,6 @@ lcp.patch # direnv file containing Maven Central secrets .envrc + +# Kotlin +.kotlin/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b589d56e9f..b86273d942 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 148fdd2469..c224ad564b 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000000..16660f1d80 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 371f5a73bf..ac4cfbada2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,16 @@ All notable changes to this project will be documented in this file. Take a look **Warning:** Features marked as *experimental* may change or be removed in a future release without notice. Use with caution. -## [Unreleased] + + +## [3.0.1] ### Fixed +#### Shared + +* Improved performance when accessing a publication from the Shared Storage. + #### Navigator * Fixed crash in the image navigator. @@ -895,4 +901,5 @@ progression. Now if no reading progression is set, the `effectiveReadingProgress [3.0.0-beta.1]: https://github.com/readium/kotlin-toolkit/compare/3.0.0-alpha.2...3.0.0-beta.1 [3.0.0-beta.2]: https://github.com/readium/kotlin-toolkit/compare/3.0.0-beta.1...3.0.0-beta.2 [3.0.0]: https://github.com/readium/kotlin-toolkit/compare/3.0.0-beta.2...3.0.0 +[3.0.1]: https://github.com/readium/kotlin-toolkit/compare/3.0.0...3.0.1 diff --git a/README.md b/README.md index 10663ca82d..9d77ff4fa5 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,11 @@ ## Minimum Requirements -| Readium | Android min SDK | Android compile SDK | Kotlin compiler (✻) | Gradle (✻) | -|---------|-----------------|---------------------|---------------------|------------| -| 3.0.0 | 21 | 34 | 1.9.24 | 8.6.0 | -| 2.3.0 | 21 | 33 | 1.7.10 | 6.9.3 | +| Readium | Android min SDK | Android compile SDK | Kotlin compiler (✻) | Gradle (✻) | +|-----------|-----------------|---------------------|---------------------|------------| +| `develop` | 21 | 35 | 2.0.21 | 8.10.2 | +| 3.0.0 | 21 | 34 | 1.9.24 | 8.6.0 | +| 2.3.0 | 21 | 33 | 1.7.10 | 6.9.3 | ✻ Only required if you integrate Readium as a submodule instead of using Maven Central. @@ -21,7 +22,7 @@ Readium modules are distributed with [Maven Central](https://search.maven.org/se ```groovy buildscript { - ext.readium_version = '3.0.0' + ext.readium_version = '3.0.1' } allprojects { @@ -43,6 +44,8 @@ dependencies { } ``` +:warning: If you target Android devices running below API 26, you must enable [core library desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) in your application module. + ### Using 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. diff --git a/build.gradle.kts b/build.gradle.kts index 5a6a65465e..9d79e831e0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,6 +9,7 @@ import org.jetbrains.dokka.gradle.DokkaTaskPartial plugins { alias(libs.plugins.dokka) alias(libs.plugins.ktlint) + alias(libs.plugins.compose.compiler) apply false } subprojects { diff --git a/gradle.properties b/gradle.properties index 87d64aadb5..dd882096fb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,11 +6,11 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html pom.groupId=org.readium.kotlin-toolkit -pom.version=3.0.0 +pom.version=3.0.1 android.minSdk=21 -android.compileSdk=34 -android.targetSdk=34 +android.compileSdk=35 +android.targetSdk=35 # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. @@ -27,3 +27,7 @@ android.useAndroidX=true android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official + +# FIXME: There are still a few issues with KSP and K2. It probably won't be ready until Room is +# updated to 2.7.0 (currently in alpha), and the KSP2 issue with @TypeConverters is fixed. +#ksp.useKSP2=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 715917ead8..20d7a0030b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,61 +1,56 @@ [versions] -kotlin = "1.9.24" -agp = "8.4.0" -desugar_jdk_libs = "2.0.4" +kotlin = "2.0.21" +agp = "8.7.2" +desugar_jdk_libs = "2.1.2" gradle-maven-publish-plugin = "0.28.0" -androidx-activity = "1.9.0" -androidx-appcompat = "1.6.1" +androidx-activity = "1.9.3" +androidx-annotation = "1.9.1" +androidx-appcompat = "1.7.0" androidx-browser = "1.8.0" androidx-cardview = "1.0.0" -# Make sure to align with the Kotlin version -# https://developer.android.com/jetpack/androidx/releases/compose-kotlin -androidx-compose-compiler = "1.5.14" -androidx-compose-animation = "1.7.0" -androidx-compose-foundation = "1.7.0" -androidx-compose-material = "1.7.0" -androidx-compose-material3 = "1.3.0" -androidx-compose-runtime = "1.7.0" -androidx-compose-ui = "1.7.0" -androidx-constraintlayout = "2.1.4" -androidx-core = "1.13.1" +androidx-compose-animation = "1.7.5" +androidx-compose-foundation = "1.7.5" +androidx-compose-material = "1.7.5" +androidx-compose-material3 = "1.3.1" +androidx-compose-runtime = "1.7.5" +androidx-compose-ui = "1.7.5" +androidx-constraintlayout = "2.2.0" +androidx-core = "1.15.0" androidx-datastore = "1.1.1" -androidx-expresso-core = "3.5.1" -androidx-ext-junit = "1.1.5" -androidx-fragment = "1.8.4" +androidx-fragment-ktx = "1.8.5" androidx-legacy = "1.0.0" -androidx-lifecycle = "2.8.0" -androidx-lifecycle-extensions = "2.2.0" +androidx-lifecycle = "2.8.7" androidx-media = "1.7.0" androidx-media2 = "1.3.0" -androidx-media3 = "1.3.1" -androidx-navigation = "2.7.7" -androidx-paging = "3.3.0" +androidx-media3 = "1.4.1" +androidx-navigation = "2.8.3" +androidx-paging = "3.3.2" androidx-recyclerview = "1.3.2" androidx-room = "2.6.1" androidx-viewpager2 = "1.1.0" -androidx-webkit = "1.11.0" +androidx-webkit = "1.12.1" -assertj = "3.25.3" +assertj = "3.26.3" dokka = "1.9.20" google-exoplayer = "2.19.1" google-material = "1.12.0" -joda-time = "2.12.7" -jsoup = "1.17.2" +joda-time = "2.13.0" +jsoup = "1.18.1" junit = "4.13.2" -kotlinx-coroutines = "1.8.1" -kotlinx-coroutines-test = "1.8.1" -kotlinx-datetime = "0.6.0" -kotlinx-serialization-json = "1.6.3" +kotlinx-coroutines = "1.9.0" +kotlinx-coroutines-test = "1.9.0" +kotlinx-datetime = "0.6.1" +kotlinx-serialization-json = "1.7.3" # Make sure to align with the Kotlin version. # See https://github.com/google/ksp/releases -ksp = "1.9.24-1.0.20" +ksp = "2.0.21-1.0.25" ktlint = "11.5.1" @@ -68,7 +63,7 @@ pdf-viewer = "2.8.2" picasso = "2.8" pspdfkit = "8.4.1" -robolectric = "4.12.2" +robolectric = "4.13" timber = "5.0.1" @@ -76,6 +71,7 @@ timber = "5.0.1" [libraries] androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "androidx-activity" } +androidx-annotation = { group = "androidx.annotation", name = "annotation", version.ref = "androidx-annotation" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidx-browser" } androidx-cardview = { group = "androidx.cardview", name = "cardview", version.ref = "androidx-cardview" } @@ -91,19 +87,9 @@ androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-toolin androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" } androidx-core = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core" } androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidx-datastore" } -androidx-expresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-expresso-core" } -androidx-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-ext-junit" } -androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "androidx-fragment" } -androidx-fragment-compose = { group = "androidx.fragment", name = "fragment-compose", version.ref = "androidx-fragment" } -androidx-legacy-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "androidx-legacy" } +androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "androidx-fragment-ktx" } androidx-legacy-ui = { group = "androidx.legacy", name = "legacy-support-core-ui", version.ref = "androidx-legacy" } androidx-lifecycle-common = { group = "androidx.lifecycle", name = "lifecycle-common-java8", version.ref = "androidx-lifecycle" } -androidx-lifecycle-extensions = { group = "androidx.lifecycle", name = "lifecycle-extensions", version.ref = "androidx-lifecycle-extensions" } -androidx-lifecycle-livedata = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" } -androidx-lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" } -androidx-lifecycle-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" } -androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } -androidx-lifecycle-vmsavedstate = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } androidx-media = { group = "androidx.media", name = "media", version.ref = "androidx-media" } androidx-media2-session = { group = "androidx.media2", name = "media2-session", version.ref = "androidx-media2" } androidx-media2-player = { group = "androidx.media2", name = "media2-player", version.ref = "androidx-media2" } @@ -161,12 +147,12 @@ kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } [bundles] compose = ["androidx-compose-activity", "androidx-compose-animation", "androidx-compose-foundation", "androidx-compose-material", "androidx-compose-material3", "androidx-compose-material-icons", "androidx-compose-runtime", "androidx-compose-ui", "androidx-compose-ui-tooling"] exoplayer = ["google-exoplayer-core", "google-exoplayer-ui", "google-exoplayer-mediasession", "google-exoplayer-workmanager", "google-exoplayer-extension-media2"] -lifecycle = ["androidx-lifecycle-common", "androidx-lifecycle-extensions", "androidx-lifecycle-livedata", "androidx-lifecycle-runtime", "androidx-lifecycle-viewmodel", "androidx-lifecycle-vmsavedstate", "androidx-lifecycle-viewmodel-compose"] media2 = ["androidx-media2-session", "androidx-media2-player", "google-exoplayer-core", "google-exoplayer-extension-media2"] media3 = ["androidx-media3-session", "androidx-media3-common", "androidx-media3-exoplayer"] room = ["androidx-room-runtime", "androidx-room-ktx"] diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 17655d0ef2..1e2fbf0d45 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/readium/adapters/exoplayer/audio/src/main/java/org/readium/adapter/exoplayer/audio/ExoPlayerEngine.kt b/readium/adapters/exoplayer/audio/src/main/java/org/readium/adapter/exoplayer/audio/ExoPlayerEngine.kt index 94cd4beb57..e048da9682 100644 --- a/readium/adapters/exoplayer/audio/src/main/java/org/readium/adapter/exoplayer/audio/ExoPlayerEngine.kt +++ b/readium/adapters/exoplayer/audio/src/main/java/org/readium/adapter/exoplayer/audio/ExoPlayerEngine.kt @@ -120,13 +120,13 @@ public class ExoPlayerEngine private constructor( private suspend fun prepareExoPlayer(player: ExoPlayer) { lateinit var listener: Player.Listener - suspendCancellableCoroutine { continuation -> + suspendCancellableCoroutine { continuation -> listener = object : Player.Listener { override fun onPlaybackStateChanged(playbackState: Int) { when (playbackState) { - Player.STATE_READY -> continuation.resume(Unit) {} + Player.STATE_READY -> continuation.resume(Unit) { _, _, _ -> } Player.STATE_IDLE -> if (player.playerError != null) { - continuation.resume(Unit) {} + continuation.resume(Unit) { _, _, _ -> } } else -> {} } diff --git a/readium/adapters/pdfium/document/build.gradle.kts b/readium/adapters/pdfium/document/build.gradle.kts index 93b145f568..d1eab7034c 100644 --- a/readium/adapters/pdfium/document/build.gradle.kts +++ b/readium/adapters/pdfium/document/build.gradle.kts @@ -15,13 +15,7 @@ android { dependencies { api(project(":readium:readium-shared")) - implementation(libs.androidx.core) implementation(libs.pdfium) implementation(libs.timber) implementation(libs.kotlinx.coroutines.android) - - testImplementation(libs.junit) - - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) } diff --git a/readium/adapters/pdfium/navigator/build.gradle.kts b/readium/adapters/pdfium/navigator/build.gradle.kts index 8a30470160..8243f6d3c6 100644 --- a/readium/adapters/pdfium/navigator/build.gradle.kts +++ b/readium/adapters/pdfium/navigator/build.gradle.kts @@ -28,9 +28,4 @@ dependencies { implementation(libs.timber) implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlinx.serialization.json) - - testImplementation(libs.junit) - - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) } diff --git a/readium/adapters/pspdfkit/document/build.gradle.kts b/readium/adapters/pspdfkit/document/build.gradle.kts index bbfbaadbd9..74cddccd99 100644 --- a/readium/adapters/pspdfkit/document/build.gradle.kts +++ b/readium/adapters/pspdfkit/document/build.gradle.kts @@ -15,13 +15,7 @@ android { dependencies { api(project(":readium:readium-shared")) - implementation(libs.androidx.core) implementation(libs.timber) implementation(libs.pspdfkit) implementation(libs.kotlinx.coroutines.android) - - testImplementation(libs.junit) - - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) } diff --git a/readium/adapters/pspdfkit/navigator/build.gradle.kts b/readium/adapters/pspdfkit/navigator/build.gradle.kts index 67f4dd44e8..34f1b27a23 100644 --- a/readium/adapters/pspdfkit/navigator/build.gradle.kts +++ b/readium/adapters/pspdfkit/navigator/build.gradle.kts @@ -26,9 +26,4 @@ dependencies { implementation(libs.pspdfkit) implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlinx.serialization.json) - - testImplementation(libs.junit) - - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) } diff --git a/readium/lcp/build.gradle.kts b/readium/lcp/build.gradle.kts index 8a2aec53ef..f0dd3a6f49 100644 --- a/readium/lcp/build.gradle.kts +++ b/readium/lcp/build.gradle.kts @@ -11,6 +11,11 @@ plugins { android { namespace = "org.readium.r2.lcp" + + kotlinOptions { + // See https://github.com/readium/kotlin-toolkit/pull/525#issuecomment-2300084041 + freeCompilerArgs = freeCompilerArgs + ("-Xconsistent-data-class-copy-visibility") + } } dependencies { @@ -37,7 +42,4 @@ dependencies { // Tests testImplementation(libs.junit) testImplementation(libs.kotlin.junit) - - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) } diff --git a/readium/navigator-media2/build.gradle.kts b/readium/navigator-media2/build.gradle.kts index eb8d371d5d..c1c4acc55e 100644 --- a/readium/navigator-media2/build.gradle.kts +++ b/readium/navigator-media2/build.gradle.kts @@ -27,7 +27,4 @@ dependencies { implementation(libs.bundles.media2) testImplementation(libs.junit) - - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) } diff --git a/readium/navigator/build.gradle.kts b/readium/navigator/build.gradle.kts index 4f126d7141..013535d3d1 100644 --- a/readium/navigator/build.gradle.kts +++ b/readium/navigator/build.gradle.kts @@ -15,6 +15,11 @@ android { buildFeatures { viewBinding = true } + + kotlinOptions { + // See https://github.com/readium/kotlin-toolkit/pull/525#issuecomment-2300084041 + freeCompilerArgs = freeCompilerArgs + ("-Xconsistent-data-class-copy-visibility") + } } dependencies { @@ -22,27 +27,22 @@ dependencies { implementation(files("libs/PhotoView-2.3.0.jar")) - implementation(libs.androidx.activity.ktx) implementation(libs.androidx.appcompat) implementation(libs.androidx.browser) implementation(libs.androidx.constraintlayout) implementation(libs.androidx.core) implementation(libs.androidx.fragment.ktx) implementation(libs.androidx.legacy.ui) - implementation(libs.androidx.legacy.v4) - implementation(libs.bundles.lifecycle) + implementation(libs.androidx.lifecycle.common) implementation(libs.androidx.recyclerview) implementation(libs.androidx.media) implementation(libs.bundles.media3) - implementation(libs.androidx.viewpager2) implementation(libs.androidx.webkit) implementation(libs.bundles.media2) // ExoPlayer is used by the Audio Navigator. api(libs.bundles.exoplayer) - implementation(libs.google.material) implementation(libs.timber) - implementation(libs.joda.time) implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlinx.serialization.json) implementation(libs.jsoup) @@ -50,8 +50,6 @@ dependencies { // Tests testImplementation(libs.junit) - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) testImplementation(libs.kotlin.junit) testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.robolectric) diff --git a/readium/navigator/src/main/java/org/readium/r2/navigator/R2WebView.kt b/readium/navigator/src/main/java/org/readium/r2/navigator/R2WebView.kt index a6cbda9ad7..baad948843 100644 --- a/readium/navigator/src/main/java/org/readium/r2/navigator/R2WebView.kt +++ b/readium/navigator/src/main/java/org/readium/r2/navigator/R2WebView.kt @@ -481,6 +481,7 @@ internal class R2WebView(context: Context, attrs: AttributeSet) : R2BasicWebView } } + @Deprecated("Deprecated in Java") override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { val count = childCount val width = r - l diff --git a/readium/navigators/common/build.gradle.kts b/readium/navigators/common/build.gradle.kts index 723865ffac..f74eb7a507 100644 --- a/readium/navigators/common/build.gradle.kts +++ b/readium/navigators/common/build.gradle.kts @@ -7,14 +7,12 @@ plugins { id("readium.library-conventions") alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.compose.compiler) } android { namespace = "org.readium.navigators.common" - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() - } buildFeatures { compose = true } diff --git a/readium/navigators/demo/build.gradle.kts b/readium/navigators/demo/build.gradle.kts index 4dd3f3106a..26dfc39076 100644 --- a/readium/navigators/demo/build.gradle.kts +++ b/readium/navigators/demo/build.gradle.kts @@ -3,48 +3,48 @@ plugins { kotlin("android") kotlin("plugin.parcelize") alias(libs.plugins.ksp) + alias(libs.plugins.compose.compiler) } android { - namespace = "org.readium.navigator.demo" - compileSdk = 34 + compileSdk = (property("android.compileSdk") as String).toInt() defaultConfig { + minSdk = (property("android.minSdk") as String).toInt() + targetSdk = (property("android.targetSdk") as String).toInt() + applicationId = "org.readium.navigator.demo" - minSdk = 21 - targetSdk = 34 + versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } - buildTypes { - release { - isMinifyEnabled = false - proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro" - ) - } - } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 isCoreLibraryDesugaringEnabled = true } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn" } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() - } buildFeatures { viewBinding = true compose = true buildConfig = true } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } packaging { resources.excludes.add("META-INF/*") } @@ -56,6 +56,7 @@ android { assets.srcDirs("src/main/assets") } } + namespace = "org.readium.navigator.demo" } dependencies { @@ -70,11 +71,9 @@ dependencies { implementation(libs.timber) implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlin.stdlib) - implementation(libs.androidx.legacy.v4) implementation(libs.bundles.compose) implementation(libs.androidx.core) implementation(libs.androidx.fragment.ktx) - implementation(libs.androidx.fragment.compose) implementation(libs.androidx.appcompat) implementation(libs.androidx.browser) } diff --git a/readium/navigators/media/audio/build.gradle.kts b/readium/navigators/media/audio/build.gradle.kts index cb5f55932d..b65100f7df 100644 --- a/readium/navigators/media/audio/build.gradle.kts +++ b/readium/navigators/media/audio/build.gradle.kts @@ -22,7 +22,6 @@ dependencies { implementation(libs.androidx.media3.common) implementation(libs.androidx.media3.session) - implementation(libs.androidx.core) implementation(libs.timber) implementation(libs.kotlinx.coroutines.android) } diff --git a/readium/navigators/media/tts/src/main/java/org/readium/navigator/media/tts/TtsEngineFacade.kt b/readium/navigators/media/tts/src/main/java/org/readium/navigator/media/tts/TtsEngineFacade.kt index e96eaadada..5b849f87cc 100644 --- a/readium/navigators/media/tts/src/main/java/org/readium/navigator/media/tts/TtsEngineFacade.kt +++ b/readium/navigators/media/tts/src/main/java/org/readium/navigator/media/tts/TtsEngineFacade.kt @@ -76,11 +76,11 @@ internal class TtsEngineFacade } } override fun onError(requestId: TtsEngine.RequestId, error: E) { - popTask(requestId)?.continuation?.resume(error) {} + popTask(requestId)?.continuation?.resume(error) { _, _, _ -> } } } } diff --git a/readium/navigators/web/build.gradle.kts b/readium/navigators/web/build.gradle.kts index be938e68e3..2115fd95e5 100644 --- a/readium/navigators/web/build.gradle.kts +++ b/readium/navigators/web/build.gradle.kts @@ -7,14 +7,12 @@ plugins { id("readium.library-conventions") alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.compose.compiler) } android { namespace = "org.readium.navigators.web" - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() - } buildFeatures { compose = true } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt index 05317fe60e..baf3cd1d04 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt @@ -7,6 +7,7 @@ package org.readium.navigator.web import android.app.Application +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable @@ -39,6 +40,7 @@ import org.readium.r2.shared.util.data.Container import org.readium.r2.shared.util.mediatype.MediaType import org.readium.r2.shared.util.resource.Resource +@OptIn(ExperimentalFoundationApi::class) @ExperimentalReadiumApi @Stable public class FixedWebRenditionState internal constructor( diff --git a/readium/opds/build.gradle.kts b/readium/opds/build.gradle.kts index 5a8d26219a..a65810aac4 100644 --- a/readium/opds/build.gradle.kts +++ b/readium/opds/build.gradle.kts @@ -15,16 +15,10 @@ android { dependencies { api(project(":readium:readium-shared")) - implementation(libs.androidx.appcompat) implementation(libs.timber) - implementation(libs.joda.time) implementation(libs.kotlinx.coroutines.android) // Tests testImplementation(libs.junit) - - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) - testImplementation(libs.robolectric) } diff --git a/readium/shared/build.gradle.kts b/readium/shared/build.gradle.kts index bc31c9a0ab..ee22eadb29 100644 --- a/readium/shared/build.gradle.kts +++ b/readium/shared/build.gradle.kts @@ -14,8 +14,7 @@ android { } dependencies { - implementation(libs.androidx.appcompat) - implementation(libs.androidx.browser) + implementation(libs.androidx.annotation) implementation(libs.timber) implementation(libs.kotlin.reflect) implementation(libs.kotlinx.coroutines.android) @@ -26,9 +25,6 @@ dependencies { // Tests testImplementation(libs.junit) - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) - testImplementation(libs.assertj) testImplementation(libs.kotlin.junit) testImplementation(libs.kotlinx.coroutines.test) diff --git a/readium/shared/src/main/java/org/readium/r2/shared/publication/services/content/iterators/HtmlResourceContentIterator.kt b/readium/shared/src/main/java/org/readium/r2/shared/publication/services/content/iterators/HtmlResourceContentIterator.kt index e8eea0687f..d0ee39afb0 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/publication/services/content/iterators/HtmlResourceContentIterator.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/publication/services/content/iterators/HtmlResourceContentIterator.kt @@ -392,7 +392,7 @@ public class HtmlResourceContentIterator internal constructor( if (node.isBlock) { assert(breadcrumbs.last().element == node) flushText() - breadcrumbs.removeLast() + breadcrumbs.removeAt(breadcrumbs.lastIndex) } } } diff --git a/readium/shared/src/main/java/org/readium/r2/shared/util/MemoryObserver.kt b/readium/shared/src/main/java/org/readium/r2/shared/util/MemoryObserver.kt index b839e13264..eb5435f558 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/util/MemoryObserver.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/util/MemoryObserver.kt @@ -14,14 +14,25 @@ public interface MemoryObserver { * Level of memory trim. */ public enum class Level { - Moderate, Low, Critical; + /** + * The process has gone on to the LRU list. This is a good opportunity to clean up resources + * that can efficiently and quickly be re-built if the user returns to the app. + */ + Background, + + /** + * The process had been showing a user interface, and is no longer doing so. Large + * allocations with the UI should be released at this point to allow memory to be better + * managed. + */ + UiHidden; public companion object { public fun fromLevel(level: Int): Level = - when { - level <= ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE -> Moderate - level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW -> Low - else -> Critical + when (level) { + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND -> Background + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN -> UiHidden + else -> Background } } } @@ -40,6 +51,8 @@ public interface MemoryObserver { public fun asComponentCallbacks2(observer: MemoryObserver): ComponentCallbacks2 = object : ComponentCallbacks2 { override fun onConfigurationChanged(config: Configuration) {} + + @Deprecated("Deprecated in Java") override fun onLowMemory() {} override fun onTrimMemory(level: Int) { diff --git a/readium/shared/src/main/java/org/readium/r2/shared/util/Url.kt b/readium/shared/src/main/java/org/readium/r2/shared/util/Url.kt index b404d6bf05..4cc174133f 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/util/Url.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/util/Url.kt @@ -205,7 +205,6 @@ public sealed class Url : Parcelable { * WARNING: Strict URL comparisons can be a source of bug, if the URLs are not normalized. * In most cases, you should compare using [Url.isEquivalent]. */ - @DelicateReadiumApi override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false diff --git a/readium/shared/src/main/java/org/readium/r2/shared/util/cache/Cache.kt b/readium/shared/src/main/java/org/readium/r2/shared/util/cache/Cache.kt index e55ccb6559..d9ba96765b 100644 --- a/readium/shared/src/main/java/org/readium/r2/shared/util/cache/Cache.kt +++ b/readium/shared/src/main/java/org/readium/r2/shared/util/cache/Cache.kt @@ -123,7 +123,7 @@ public class InMemoryCache : Cache { @OptIn(DelicateCoroutinesApi::class) override fun onTrimMemory(level: MemoryObserver.Level) { - if (level == MemoryObserver.Level.Critical) { + if (level == MemoryObserver.Level.Background) { GlobalScope.launch { transaction { clear() } } } } diff --git a/readium/streamer/build.gradle.kts b/readium/streamer/build.gradle.kts index 506d0951b5..2493ff3b0b 100644 --- a/readium/streamer/build.gradle.kts +++ b/readium/streamer/build.gradle.kts @@ -17,26 +17,17 @@ dependencies { api(files("libs/nanohttpd-2.3.2.jar", "libs/nanohttpd-nanolets-2.3.2.jar")) - implementation(libs.androidx.appcompat) @Suppress("GradleDependency") implementation(libs.timber) // AM NOTE: conflicting support libraries, excluding these implementation("com.mcxiaoke.koi:core:0.5.5") { exclude(module = "support-v4") } - // useful extensions (only ~100k) - implementation("com.mcxiaoke.koi:async:0.5.5") { - exclude(module = "support-v4") - } - implementation(libs.joda.time) implementation(libs.kotlinx.coroutines.android) // Tests testImplementation(libs.junit) testImplementation(libs.kotlin.junit) - - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) testImplementation(libs.assertj) testImplementation(libs.robolectric) } diff --git a/test-app/build.gradle.kts b/test-app/build.gradle.kts index 4e4186121b..bff512d1bb 100644 --- a/test-app/build.gradle.kts +++ b/test-app/build.gradle.kts @@ -9,18 +9,19 @@ plugins { kotlin("android") kotlin("plugin.parcelize") alias(libs.plugins.ksp) + alias(libs.plugins.compose.compiler) } android { - compileSdk = 34 + compileSdk = (property("android.compileSdk") as String).toInt() defaultConfig { - minSdk = 21 - targetSdk = 34 + minSdk = (property("android.minSdk") as String).toInt() + targetSdk = (property("android.targetSdk") as String).toInt() applicationId = "org.readium.r2reader" - versionName = "3.0.0" - versionCode = 300000 + versionName = "3.0.1" + versionCode = 300001 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" ndk.abiFilters.add("armeabi-v7a") @@ -37,9 +38,6 @@ android { jvmTarget = JavaVersion.VERSION_1_8.toString() freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn" } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() - } buildFeatures { viewBinding = true compose = true @@ -69,7 +67,6 @@ dependencies { coreLibraryDesugaring(libs.desugar.jdk.libs) implementation(libs.kotlin.stdlib) - implementation(libs.androidx.legacy.v4) implementation(project(":readium:readium-shared")) implementation(project(":readium:readium-streamer")) @@ -96,7 +93,7 @@ dependencies { implementation(libs.androidx.core) implementation(libs.androidx.datastore.preferences) implementation(libs.androidx.fragment.ktx) - implementation(libs.bundles.lifecycle) + implementation(libs.androidx.lifecycle.common) implementation(libs.androidx.navigation.fragment) implementation(libs.androidx.navigation.ui) implementation(libs.androidx.paging) @@ -115,10 +112,4 @@ dependencies { // Room database implementation(libs.bundles.room) ksp(libs.androidx.room.compiler) - - // Tests - testImplementation(libs.junit) - - androidTestImplementation(libs.androidx.ext.junit) - androidTestImplementation(libs.androidx.expresso.core) } diff --git a/test-app/src/main/java/org/readium/r2/testapp/MainActivity.kt b/test-app/src/main/java/org/readium/r2/testapp/MainActivity.kt index 1127436189..c7b13e7c83 100644 --- a/test-app/src/main/java/org/readium/r2/testapp/MainActivity.kt +++ b/test-app/src/main/java/org/readium/r2/testapp/MainActivity.kt @@ -7,8 +7,11 @@ package org.readium.r2.testapp import android.os.Bundle +import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.AppBarConfiguration @@ -24,7 +27,13 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableEdgeToEdge() setContentView(R.layout.activity_main) + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.container)) { v, insets -> + val statusBars = insets.getInsets(WindowInsetsCompat.Type.statusBars()) + v.setPadding(statusBars.left, statusBars.top, statusBars.right, statusBars.bottom) + insets + } val navView: BottomNavigationView = findViewById(R.id.nav_view) val navHostFragment = diff --git a/test-app/src/main/java/org/readium/r2/testapp/reader/MediaService.kt b/test-app/src/main/java/org/readium/r2/testapp/reader/MediaService.kt index e3eaaeaf43..fc51c220ba 100644 --- a/test-app/src/main/java/org/readium/r2/testapp/reader/MediaService.kt +++ b/test-app/src/main/java/org/readium/r2/testapp/reader/MediaService.kt @@ -171,7 +171,7 @@ class MediaService : MediaSessionService() { return binder.session.value?.mediaSession } - override fun onTaskRemoved(rootIntent: Intent) { + override fun onTaskRemoved(rootIntent: Intent?) { super.onTaskRemoved(rootIntent) Timber.d("Task removed. Stopping session and service.") // Close the session to allow the service to be stopped. diff --git a/test-app/src/main/java/org/readium/r2/testapp/utils/extensions/Flow.kt b/test-app/src/main/java/org/readium/r2/testapp/utils/extensions/Flow.kt index 1d2f058aae..6c3ccdc435 100644 --- a/test-app/src/main/java/org/readium/r2/testapp/utils/extensions/Flow.kt +++ b/test-app/src/main/java/org/readium/r2/testapp/utils/extensions/Flow.kt @@ -15,7 +15,14 @@ import androidx.lifecycle.flowWithLifecycle import kotlin.time.Duration import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn /** * Collects safely the [Flow] as a [State] when the local lifecycle is started.