diff --git a/android/.idea/kotlinc.xml b/android/.idea/kotlinc.xml index fe63bb677..6d0ee1c2a 100644 --- a/android/.idea/kotlinc.xml +++ b/android/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/android/build-logic/convention/build.gradle.kts b/android/build-logic/convention/build.gradle.kts index 8e9c57990..4f87fb775 100644 --- a/android/build-logic/convention/build.gradle.kts +++ b/android/build-logic/convention/build.gradle.kts @@ -1,4 +1,4 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { `kotlin-dsl` @@ -12,14 +12,15 @@ java { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } -tasks.withType().configureEach { - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_17 } } dependencies { compileOnly(libs.android.gradlePlugin) + compileOnly(libs.compose.gradlePlugin) compileOnly(libs.kotlin.gradlePlugin) compileOnly(libs.ksp.gradlePlugin) } diff --git a/android/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt b/android/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt index c9804f9a6..2e07a4590 100644 --- a/android/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt +++ b/android/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt @@ -2,12 +2,15 @@ import ca.josephroque.bowlingcompanion.configureAndroidCompose import com.android.build.api.dsl.ApplicationExtension import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.getByType class AndroidApplicationComposeConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { - pluginManager.apply("com.android.application") + apply(plugin = "com.android.application") + apply(plugin = "org.jetbrains.kotlin.plugin.compose") + val extension = extensions.getByType() configureAndroidCompose(extension) } diff --git a/android/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt b/android/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt index ec1ad1c3b..e8e8e53e3 100644 --- a/android/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt +++ b/android/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt @@ -2,12 +2,15 @@ import ca.josephroque.bowlingcompanion.configureAndroidCompose import com.android.build.gradle.LibraryExtension import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.getByType class AndroidLibraryComposeConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { - pluginManager.apply("com.android.library") + apply(plugin = "com.android.library") + apply(plugin = "org.jetbrains.kotlin.plugin.compose") + val extension = extensions.getByType() configureAndroidCompose(extension) } diff --git a/android/build-logic/convention/src/main/kotlin/ca/josephroque/bowlingcompanion/AndroidCompose.kt b/android/build-logic/convention/src/main/kotlin/ca/josephroque/bowlingcompanion/AndroidCompose.kt index 6238feb5a..bcdf5546e 100644 --- a/android/build-logic/convention/src/main/kotlin/ca/josephroque/bowlingcompanion/AndroidCompose.kt +++ b/android/build-logic/convention/src/main/kotlin/ca/josephroque/bowlingcompanion/AndroidCompose.kt @@ -2,7 +2,11 @@ package ca.josephroque.bowlingcompanion import com.android.build.api.dsl.CommonExtension import org.gradle.api.Project +import org.gradle.api.provider.Provider +import org.gradle.kotlin.dsl.assign +import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies +import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension /** * Configure Compose-specific options @@ -13,14 +17,39 @@ internal fun Project.configureAndroidCompose(commonExtension: CommonExtension<*, compose = true } - composeOptions { - kotlinCompilerExtensionVersion = libs.findVersion("androidxComposeCompiler").get().toString() - } - dependencies { val bom = libs.findLibrary("androidx-compose-bom").get() add("implementation", platform(bom)) add("androidTestImplementation", platform(bom)) + add("implementation", libs.findLibrary("androidx-compose-ui-tooling-preview").get()) + add("debugImplementation", libs.findLibrary("androidx-compose-ui-tooling").get()) } + + testOptions { + unitTests { + // For Robolectric + isIncludeAndroidResources = true + } + } + } + + extensions.configure { + fun Provider.onlyIfTrue() = flatMap { provider { it.takeIf(String::toBoolean) } } + fun Provider<*>.relativeToRootProject(dir: String) = flatMap { + rootProject.layout.buildDirectory.dir(projectDir.toRelativeString(rootDir)) + }.map { it.dir(dir) } + + project.providers.gradleProperty("enableComposeCompilerMetrics").onlyIfTrue() + .relativeToRootProject("compose-metrics") + .let(metricsDestination::set) + + project.providers.gradleProperty("enableComposeCompilerReports").onlyIfTrue() + .relativeToRootProject("compose-reports") + .let(reportsDestination::set) + + stabilityConfigurationFile = + rootProject.layout.projectDirectory.file("compose_compiler_config.conf") + + enableStrongSkippingMode = true } } diff --git a/android/build-logic/convention/src/main/kotlin/ca/josephroque/bowlingcompanion/KotlinAndroid.kt b/android/build-logic/convention/src/main/kotlin/ca/josephroque/bowlingcompanion/KotlinAndroid.kt index a0402f69f..73f11c266 100644 --- a/android/build-logic/convention/src/main/kotlin/ca/josephroque/bowlingcompanion/KotlinAndroid.kt +++ b/android/build-logic/convention/src/main/kotlin/ca/josephroque/bowlingcompanion/KotlinAndroid.kt @@ -4,10 +4,13 @@ import com.android.build.api.dsl.CommonExtension import org.gradle.api.JavaVersion import org.gradle.api.Project import org.gradle.api.plugins.JavaPluginExtension +import org.gradle.kotlin.dsl.assign import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.provideDelegate -import org.gradle.kotlin.dsl.withType -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension +import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension /** * Configure base Kotlin with Android options @@ -26,7 +29,7 @@ internal fun Project.configureKotlinAndroid(commonExtension: CommonExtension<*, } } - configureKotlin() + configureKotlin() } /** @@ -38,28 +41,26 @@ internal fun Project.configureKotlinJvm() { targetCompatibility = JavaVersion.VERSION_17 } - configureKotlin() + configureKotlin() } /** * Configure base Kotlin options */ -private fun Project.configureKotlin() { - // Use withType to workaround https://youtrack.jetbrains.com/issue/KT-55947 - tasks.withType().configureEach { - kotlinOptions { - // Set JVM target to 17 - jvmTarget = JavaVersion.VERSION_17.toString() - // Treat all Kotlin warnings as errors (disabled by default) - // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties - val warningsAsErrors: String? by project - allWarningsAsErrors = warningsAsErrors.toBoolean() - freeCompilerArgs = freeCompilerArgs + listOf( - "-opt-in=kotlin.RequiresOptIn", - // Enable experimental coroutines APIs, including Flow - "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", - "-opt-in=kotlinx.coroutines.FlowPreview", - ) - } +private inline fun Project.configureKotlin() = configure { + // Treat all Kotlin warnings as errors (disabled by default) + // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties + val warningsAsErrors: String? by project + when (this) { + is KotlinAndroidProjectExtension -> compilerOptions + is KotlinJvmProjectExtension -> compilerOptions + else -> TODO("Unsupported project extension $this ${T::class}") + }.apply { + jvmTarget = JvmTarget.JVM_17 + allWarningsAsErrors = warningsAsErrors.toBoolean() + freeCompilerArgs.add( + // Enable experimental coroutines APIs, including Flow + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", + ) } } diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 87d599684..4d7ea0ad2 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -8,6 +8,7 @@ buildscript { plugins { alias(libs.plugins.android.application) apply false + alias(libs.plugins.compose.compiler) apply false alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.hilt) apply false alias(libs.plugins.ksp) apply false diff --git a/android/compose_compiler_config.conf b/android/compose_compiler_config.conf new file mode 100644 index 000000000..6f312d932 --- /dev/null +++ b/android/compose_compiler_config.conf @@ -0,0 +1,7 @@ +// This file contains classes (with possible wildcards) that the Compose Compiler will treat as stable. +// It allows us to define classes that our not part of our codebase without wrapping them in a stable class. +// For more information, check https://developer.android.com/jetpack/compose/performance/stability/fix#configuration-file + +// We always use immutable classes for our data model, to avoid running the Compose compiler +// in the module we declare it to be stable here. +ca.josephroque.bowlingcompanion.core.model.* diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 51160c5fa..85d379a96 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -7,7 +7,6 @@ accompanist = "0.34.0" androidGradlePlugin = "8.5.1" androidxActivity = "1.9.0" androidxComposeBom = "2024.06.00" -androidxComposeCompiler = "1.5.11" androidxCore = "1.13.1" androidxDataStore = "1.1.1" androidxHiltNavigationCompose = "1.2.0" @@ -20,8 +19,8 @@ hilt = "2.51.1" junit4 = "4.13.2" kotlinxCoroutines = "1.8.1" kotlinxDatetime = "0.5.0" -kotlin = "1.9.23" -ksp = "1.9.23-1.0.19" +kotlin = "2.0.0" +ksp = "2.0.0-1.0.21" ktlint = "12.1.0" navigationCompose = "2.7.7" paging = "3.3.0" @@ -72,6 +71,7 @@ vico-compose-m3 = { group = "com.patrykandpatrick.vico", name = "compose-m3", ve # Dependencies of the included build-logic android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } +compose-gradlePlugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" } kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } @@ -79,10 +79,12 @@ ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devto android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } android-test = { id = "com.android.test", version.ref = "androidGradlePlugin" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } +org-jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" } gradle-versions = { id = "se.ascp.gradle.gradle-versions-filter", version.ref = "gradleVersions" } \ No newline at end of file