diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 72b0b7829..7b95c1444 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -255,7 +255,7 @@ dependencies { dokka { moduleName.set("Meshtastic App") - dokkaSourceSets.main { + dokkaSourceSets.register("main") { sourceLink { enableJdkDocumentationLink.set(true) enableKotlinStdLibDocumentationLink.set(true) diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index a4a275724..74b92f0fa 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -40,10 +40,14 @@ kotlin { } dependencies { + // This allows the use of the 'libs' type-safe accessor in the Kotlin source of the plugins + implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) + compileOnly(libs.android.gradleApiPlugin) compileOnly(libs.serialization.gradlePlugin) compileOnly(libs.android.tools.common) compileOnly(libs.compose.gradlePlugin) + compileOnly(libs.compose.multiplatform.gradlePlugin) compileOnly(libs.datadog.gradlePlugin) compileOnly(libs.detekt.gradlePlugin) compileOnly(libs.firebase.crashlytics.gradlePlugin) @@ -103,62 +107,67 @@ detekt { gradlePlugin { plugins { register("androidApplication") { - id = libs.plugins.meshtastic.android.application.asProvider().get().pluginId + id = "meshtastic.android.application" implementationClass = "AndroidApplicationConventionPlugin" } register("androidFlavors") { - id = libs.plugins.meshtastic.android.application.flavors.get().pluginId + id = "meshtastic.android.application.flavors" implementationClass = "AndroidApplicationFlavorsConventionPlugin" } register("androidLibrary") { - id = libs.plugins.meshtastic.android.library.asProvider().get().pluginId + id = "meshtastic.android.library" implementationClass = "AndroidLibraryConventionPlugin" } register("androidLint") { - id = libs.plugins.meshtastic.android.lint.get().pluginId + id = "meshtastic.android.lint" implementationClass = "AndroidLintConventionPlugin" } register("androidLibraryCompose") { - id = libs.plugins.meshtastic.android.library.compose.get().pluginId + id = "meshtastic.android.library.compose" implementationClass = "AndroidLibraryComposeConventionPlugin" } register("androidApplicationCompose") { - id = libs.plugins.meshtastic.android.application.compose.get().pluginId + id = "meshtastic.android.application.compose" implementationClass = "AndroidApplicationComposeConventionPlugin" } register("kotlinXSerialization") { - id = libs.plugins.meshtastic.kotlinx.serialization.get().pluginId + id = "meshtastic.kotlinx.serialization" implementationClass = "KotlinXSerializationConventionPlugin" } register("meshtasticAnalytics") { - id = libs.plugins.meshtastic.analytics.get().pluginId + id = "meshtastic.analytics" implementationClass = "AnalyticsConventionPlugin" } register("meshtasticHilt") { - id = libs.plugins.meshtastic.hilt.get().pluginId + id = "meshtastic.hilt" implementationClass = "HiltConventionPlugin" } register("meshtasticDetekt") { - id = libs.plugins.meshtastic.detekt.get().pluginId + id = "meshtastic.detekt" implementationClass = "DetektConventionPlugin" } register("androidRoom") { - id = libs.plugins.meshtastic.android.room.get().pluginId + id = "meshtastic.android.room" implementationClass = "AndroidRoomConventionPlugin" } register("meshtasticSpotless") { - id = libs.plugins.meshtastic.spotless.get().pluginId + id = "meshtastic.spotless" implementationClass = "SpotlessConventionPlugin" } register("kmpLibrary") { - id = libs.plugins.meshtastic.kmp.library.get().pluginId + id = "meshtastic.kmp.library" implementationClass = "KmpLibraryConventionPlugin" } + register("kmpLibraryCompose") { + id = "meshtastic.kmp.library.compose" + implementationClass = "KmpLibraryComposeConventionPlugin" + } + register("root") { - id = libs.plugins.meshtastic.root.get().pluginId + id = "meshtastic.root" implementationClass = "RootConventionPlugin" } diff --git a/build-logic/convention/src/main/kotlin/AnalyticsConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AnalyticsConventionPlugin.kt index d1af5ddee..72a820afb 100644 --- a/build-logic/convention/src/main/kotlin/AnalyticsConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AnalyticsConventionPlugin.kt @@ -24,6 +24,8 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure +import org.meshtastic.buildlogic.libs +import org.meshtastic.buildlogic.plugin class AnalyticsConventionPlugin : Plugin { override fun apply(target: Project) { @@ -33,9 +35,9 @@ class AnalyticsConventionPlugin : Plugin { productFlavors { all { if (name == "google") { - apply(plugin = "com.google.gms.google-services") - apply(plugin = "com.google.firebase.crashlytics") - apply(plugin = "com.datadoghq.dd-sdk-android-gradle-plugin") + apply(plugin = libs.plugin("google-services").get().pluginId) + apply(plugin = libs.plugin("firebase-crashlytics").get().pluginId) + apply(plugin = libs.plugin("datadog").get().pluginId) } } } @@ -58,7 +60,7 @@ class AnalyticsConventionPlugin : Plugin { } // Disable Analytics tasks for non-google flavors - val analyticsKeywords = listOf("crashlytics", "google", "datadog","buildId") + val analyticsKeywords = listOf("crashlytics", "google", "datadog", "buildId") tasks.configureEach { val taskName = name.lowercase() val isAnalyticsTask = analyticsKeywords.any { taskName.contains(it, ignoreCase = true) } diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt index 4f8129c34..bb39b4e6f 100644 --- a/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt @@ -15,22 +15,22 @@ * along with this program. If not, see . */ -import com.android.build.api.dsl.ApplicationExtension +import com.android.build.api.dsl.CommonExtension import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure import org.meshtastic.buildlogic.configureAndroidCompose +import org.meshtastic.buildlogic.libs +import org.meshtastic.buildlogic.plugin class AndroidApplicationComposeConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { - apply(plugin = "com.android.application") - apply(plugin = "org.jetbrains.kotlin.plugin.compose") - extensions.configure { + apply(plugin = libs.plugin("compose-compiler").get().pluginId) + extensions.configure { configureAndroidCompose(this) } } } - } diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt index 4ceb8fd21..f3c8785c0 100644 --- a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt @@ -27,7 +27,6 @@ class AndroidApplicationConventionPlugin : Plugin { with(target) { apply(plugin = "com.android.application") - apply(plugin = "org.jetbrains.kotlin.android") apply(plugin = "meshtastic.android.lint") apply(plugin = "meshtastic.detekt") apply(plugin = "meshtastic.spotless") @@ -35,15 +34,14 @@ class AndroidApplicationConventionPlugin : Plugin { extensions.configure { configureKotlinAndroid(this) - defaultConfig.targetSdk = 36 - testOptions.animationsDisabled = true - + defaultConfig { - targetSdk = 36 testInstrumentationRunner = "com.geeksville.mesh.TestRunner" vectorDrawables.useSupportLibrary = true } + testOptions.animationsDisabled = true + buildTypes { getByName("release") { isMinifyEnabled = true diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt index 572f31c57..051f6b13b 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt @@ -15,22 +15,22 @@ * along with this program. If not, see . */ -import com.android.build.api.dsl.LibraryExtension +import com.android.build.api.dsl.CommonExtension import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure import org.meshtastic.buildlogic.configureAndroidCompose +import org.meshtastic.buildlogic.libs +import org.meshtastic.buildlogic.plugin class AndroidLibraryComposeConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { - apply(plugin = "com.android.library") - apply(plugin = "org.jetbrains.kotlin.plugin.compose") - extensions.configure { + apply(plugin = libs.plugin("compose-compiler").get().pluginId) + extensions.configure { configureAndroidCompose(this) } } } - } diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt index a53a3d065..682c3e45f 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt @@ -29,7 +29,6 @@ class AndroidLibraryConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { apply(plugin = "com.android.library") - apply(plugin = "org.jetbrains.kotlin.android") apply(plugin = "meshtastic.android.lint") apply(plugin = "meshtastic.detekt") apply(plugin = "meshtastic.spotless") diff --git a/build-logic/convention/src/main/kotlin/AndroidLintConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLintConventionPlugin.kt index 52e37212a..f57a287c5 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLintConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLintConventionPlugin.kt @@ -16,12 +16,14 @@ */ import com.android.build.api.dsl.ApplicationExtension +import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget import com.android.build.api.dsl.LibraryExtension import com.android.build.api.dsl.Lint import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.findByType class AndroidLintConventionPlugin : Plugin { override fun apply(target: Project) { @@ -33,6 +35,13 @@ class AndroidLintConventionPlugin : Plugin { pluginManager.hasPlugin("com.android.library") -> configure { lint { configure(project) } } + pluginManager.hasPlugin("com.android.kotlin.multiplatform.library") -> { + extensions.findByType()?.apply { + @Suppress("UnstableApiUsage") + lint { configure(project) } + } + } + else -> { apply(plugin = "com.android.lint") configure { configure(project) } diff --git a/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt index 43bc73dc9..eeecb9077 100644 --- a/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt @@ -22,6 +22,8 @@ import org.gradle.api.Project import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.meshtastic.buildlogic.library import org.meshtastic.buildlogic.libs class AndroidRoomConventionPlugin : Plugin { @@ -42,10 +44,28 @@ class AndroidRoomConventionPlugin : Plugin { schemaDirectory("$projectDir/schemas") } - dependencies { - "implementation"(libs.findLibrary("androidx.room.runtime").get()) - "ksp"(libs.findLibrary("androidx.room.compiler").get()) - "androidTestImplementation"(libs.findLibrary("androidx-room-testing").get()) + val roomRuntime = libs.library("androidx.room.runtime") + val roomCompiler = libs.library("androidx.room.compiler") + val roomTesting = libs.library("androidx-room-testing") + + pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") { + extensions.configure { + sourceSets.getByName("commonMain").dependencies { + implementation(roomRuntime) + } + } + dependencies { + "kspCommonMainMetadata"(roomCompiler) + "kspAndroid"(roomCompiler) + } + } + + pluginManager.withPlugin("org.jetbrains.kotlin.android") { + dependencies { + "implementation"(roomRuntime) + "ksp"(roomCompiler) + "androidTestImplementation"(roomTesting) + } } } } diff --git a/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt b/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt index 6fe3fec48..92680df33 100644 --- a/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt @@ -18,19 +18,18 @@ import io.gitlab.arturbosch.detekt.extensions.DetektExtension import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.kotlin.dsl.apply -import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.configure import org.meshtastic.buildlogic.configureDetekt -import org.meshtastic.buildlogic.configureKotlinJvm import org.meshtastic.buildlogic.libs +import org.meshtastic.buildlogic.plugin class DetektConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { - configureKotlinJvm() - apply(plugin = libs.findPlugin("detekt").get().get().pluginId) - val extension = extensions.getByType() - configureDetekt(extension) + pluginManager.apply(libs.plugin("detekt").get().pluginId) + extensions.configure { + configureDetekt(this) + } } } } diff --git a/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt b/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt index 15c707409..066b3ed27 100644 --- a/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt @@ -19,6 +19,7 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.dependencies +import org.meshtastic.buildlogic.library import org.meshtastic.buildlogic.libs class HiltConventionPlugin : Plugin { @@ -28,16 +29,16 @@ class HiltConventionPlugin : Plugin { dependencies { // fixme: remove when hilt supports kotlin 2.3.x - "ksp"(libs.findLibrary("kotlin-metadata-jvm").get()) + "ksp"(libs.library("kotlin-metadata-jvm")) - "ksp"(libs.findLibrary("hilt.compiler").get()) - "implementation"(libs.findLibrary("hilt-android").get()) + "ksp"(libs.library("hilt.compiler")) + "implementation"(libs.library("hilt-android")) } // Add support for Jvm Module, base on org.jetbrains.kotlin.jvm pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { dependencies { - "implementation"(libs.findLibrary("hilt.core").get()) + "implementation"(libs.library("hilt-core")) } } diff --git a/build-logic/convention/src/main/kotlin/KmpLibraryComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpLibraryComposeConventionPlugin.kt new file mode 100644 index 000000000..9578865e7 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/KmpLibraryComposeConventionPlugin.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.configure +import org.jetbrains.compose.ComposeExtension +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.meshtastic.buildlogic.libs +import org.meshtastic.buildlogic.plugin + +class KmpLibraryComposeConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + apply(plugin = libs.plugin("compose-multiplatform").get().pluginId) + apply(plugin = libs.plugin("compose-compiler").get().pluginId) + + val compose = extensions.getByType(ComposeExtension::class.java) + extensions.configure { + sourceSets.getByName("commonMain").dependencies { + implementation(compose.dependencies.runtime) + // API because consuming modules will usually need the resource types + api(compose.dependencies.components.resources) + } + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt index 30343ce66..f28e695c5 100644 --- a/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt @@ -15,29 +15,23 @@ * along with this program. If not, see . */ -import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.plugins.ExtensionAware import org.gradle.kotlin.dsl.apply -import org.gradle.kotlin.dsl.configure -import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension -import org.meshtastic.buildlogic.configProperties +import org.meshtastic.buildlogic.configureKotlinMultiplatform +import org.meshtastic.buildlogic.libs +import org.meshtastic.buildlogic.plugin class KmpLibraryConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { - apply(plugin = "org.jetbrains.kotlin.multiplatform") - apply(plugin = "com.android.kotlin.multiplatform.library") + apply(plugin = libs.plugin("kotlin-multiplatform").get().pluginId) + apply(plugin = libs.plugin("android-kotlin-multiplatform-library").get().pluginId) + apply(plugin = "meshtastic.android.lint") apply(plugin = "meshtastic.detekt") apply(plugin = "meshtastic.spotless") - extensions.configure { - (this as ExtensionAware).extensions.configure("android") { - compileSdk = this@with.configProperties.getProperty("COMPILE_SDK").toInt() - minSdk = this@with.configProperties.getProperty("MIN_SDK").toInt() - } - } + configureKotlinMultiplatform() } } } diff --git a/build-logic/convention/src/main/kotlin/KotlinXSerializationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KotlinXSerializationConventionPlugin.kt index 07b90ad5a..259ecd9c2 100644 --- a/build-logic/convention/src/main/kotlin/KotlinXSerializationConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KotlinXSerializationConventionPlugin.kt @@ -18,7 +18,10 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.meshtastic.buildlogic.library import org.meshtastic.buildlogic.libs class KotlinXSerializationConventionPlugin : Plugin { @@ -26,8 +29,26 @@ class KotlinXSerializationConventionPlugin : Plugin { with(target) { apply(plugin = "org.jetbrains.kotlin.plugin.serialization") - dependencies { - "implementation"(libs.findLibrary("kotlinx-serialization-core").get()) + val serializationLib = libs.library("kotlinx-serialization-core") + + pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") { + extensions.configure { + sourceSets.getByName("commonMain").dependencies { + implementation(serializationLib) + } + } + } + + pluginManager.withPlugin("org.jetbrains.kotlin.android") { + dependencies { + "implementation"(serializationLib) + } + } + + pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { + dependencies { + "implementation"(serializationLib) + } } } } diff --git a/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt b/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt index 5ef4318ef..94dbd32b4 100644 --- a/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt @@ -18,19 +18,18 @@ import com.diffplug.gradle.spotless.SpotlessExtension import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.kotlin.dsl.apply -import org.gradle.kotlin.dsl.getByType -import org.meshtastic.buildlogic.configureKotlinJvm +import org.gradle.kotlin.dsl.configure import org.meshtastic.buildlogic.configureSpotless import org.meshtastic.buildlogic.libs +import org.meshtastic.buildlogic.plugin class SpotlessConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { - configureKotlinJvm() - apply(plugin = libs.findPlugin("spotless").get().get().pluginId) - val extension = extensions.getByType() - configureSpotless(extension) + pluginManager.apply(libs.plugin("spotless").get().pluginId) + extensions.configure { + configureSpotless(this) + } } } } diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt index e8a4d1835..92893b53f 100644 --- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt +++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt @@ -17,7 +17,9 @@ package org.meshtastic.buildlogic +import com.android.build.api.dsl.ApplicationExtension import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.LibraryExtension import org.gradle.api.Project import org.gradle.api.provider.Provider import org.gradle.kotlin.dsl.configure @@ -28,22 +30,19 @@ import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginE * Configure Compose-specific options */ internal fun Project.configureAndroidCompose( - commonExtension: CommonExtension<*, *, *, *, *, *>, + commonExtension: CommonExtension, ) { - commonExtension.apply { - buildFeatures { - compose = true - } + (commonExtension as? ApplicationExtension)?.buildFeatures?.compose = true + (commonExtension as? LibraryExtension)?.buildFeatures?.compose = true - dependencies { - val bom = libs.findLibrary("androidx-compose-bom").get() - "implementation"(platform(bom)) - "androidTestImplementation"(platform(bom)) - "implementation"(libs.findLibrary("androidx-compose-ui-tooling").get()) - "implementation"(libs.findLibrary("androidx-compose-runtime").get()) - "runtimeOnly"(libs.findLibrary("androidx-compose-runtime-tracing").get()) - "debugImplementation"(libs.findLibrary("androidx-compose-ui-tooling").get()) - } + dependencies { + val bom = libs.library("androidx-compose-bom") + "implementation"(platform(bom)) + "androidTestImplementation"(platform(bom)) + "implementation"(libs.library("androidx-compose-ui-tooling")) + "implementation"(libs.library("androidx-compose-runtime")) + "runtimeOnly"(libs.library("androidx-compose-runtime-tracing")) + "debugImplementation"(libs.library("androidx-compose-ui-tooling")) } extensions.configure { diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Detekt.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Detekt.kt index b6fdd5c9c..40b63faa5 100644 --- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Detekt.kt +++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Detekt.kt @@ -22,21 +22,24 @@ import io.gitlab.arturbosch.detekt.extensions.DetektExtension import org.gradle.api.Project import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.named -import java.io.File internal fun Project.configureDetekt(extension: DetektExtension) = extension.apply { - extension.apply { - toolVersion = libs.findVersion("detekt").get().toString() - config.setFrom("$rootDir/config/detekt/detekt.yml") - buildUponDefaultConfig = true - allRules = false - source.setFrom( - files( - "src/main/java", - "src/main/kotlin", - ), - ) - } + toolVersion = libs.version("detekt") + config.setFrom("$rootDir/config/detekt/detekt.yml") + buildUponDefaultConfig = true + allRules = false + + // Default sources + source.setFrom( + files( + "src/main/java", + "src/main/kotlin", + "src/commonMain/kotlin", + "src/androidMain/kotlin", + "src/jvmMain/kotlin", + ), + ) + tasks.named("detekt") { reports { xml.required.set(true) @@ -45,14 +48,15 @@ internal fun Project.configureDetekt(extension: DetektExtension) = extension.app sarif.required.set(true) md.required.set(true) } - reports.xml.outputLocation.set(File("$rootDir/build/reports/detekt/detekt.xml")) - reports.html.outputLocation.set(File("$rootDir/build/reports/detekt/detekt.html")) - reports.txt.outputLocation.set(File("$rootDir/build/reports/detekt/detekt.txt")) - reports.sarif.outputLocation.set(File("$rootDir/build/reports/detekt/detekt.sarif")) - reports.md.outputLocation.set(File("$rootDir/build/reports/detekt/detekt.md")) + // Use project-specific build directory for reports to avoid conflicts + reports.xml.outputLocation.set(layout.buildDirectory.file("reports/detekt/detekt.xml")) + reports.html.outputLocation.set(layout.buildDirectory.file("reports/detekt/detekt.html")) + reports.txt.outputLocation.set(layout.buildDirectory.file("reports/detekt/detekt.txt")) + reports.sarif.outputLocation.set(layout.buildDirectory.file("reports/detekt/detekt.sarif")) + reports.md.outputLocation.set(layout.buildDirectory.file("reports/detekt/detekt.md")) } dependencies { - "detektPlugins"(libs.findLibrary("detekt-formatting").get()) - "detektPlugins"(libs.findLibrary("detekt-compose").get()) + "detektPlugins"(libs.library("detekt-formatting")) + "detektPlugins"(libs.library("detekt-compose")) } } diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt index 1100ef547..f40bf669e 100644 --- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt +++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt @@ -17,43 +17,42 @@ package org.meshtastic.buildlogic +import com.android.build.api.dsl.ApplicationExtension import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget import org.gradle.api.JavaVersion import org.gradle.api.Project import org.gradle.api.plugins.JavaPluginExtension import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.findByType import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinBaseExtension import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import java.io.FileInputStream -import java.util.Properties /** * Configure base Kotlin with Android options */ internal fun Project.configureKotlinAndroid( - commonExtension: CommonExtension<*, *, *, *, *, *>, + commonExtension: CommonExtension, ) { - val configPropertiesFile = rootProject.file("config.properties") - val configProperties = Properties() - - if (configPropertiesFile.exists()) { - FileInputStream(configPropertiesFile).use { configProperties.load(it) } - } commonExtension.apply { - compileSdk = configProperties.get("COMPILE_SDK").toString().toInt() + compileSdk = configProperties.getProperty("COMPILE_SDK").toInt() - defaultConfig { - minSdk = configProperties.get("MIN_SDK").toString().toInt() + defaultConfig.apply { + minSdk = configProperties.getProperty("MIN_SDK").toInt() + if (commonExtension is ApplicationExtension) { + commonExtension.defaultConfig.targetSdk = configProperties.getProperty("TARGET_SDK").toInt() + } } - compileOptions { + compileOptions.apply { sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 isCoreLibraryDesugaringEnabled = true @@ -63,10 +62,33 @@ internal fun Project.configureKotlinAndroid( configureKotlin() dependencies { - "coreLibraryDesugaring"(libs.findLibrary("android.desugarJdkLibs").get()) + "coreLibraryDesugaring"(libs.library("android.desugarJdkLibs")) } } +/** + * Configure Kotlin Multiplatform options + */ +internal fun Project.configureKotlinMultiplatform() { + extensions.configure { + // Configure the Android target if the plugin is applied + pluginManager.withPlugin("com.android.kotlin.multiplatform.library") { + extensions.findByType()?.apply { + compileSdk = configProperties.getProperty("COMPILE_SDK").toInt() + minSdk = configProperties.getProperty("MIN_SDK").toInt() + + // Set the namespace automatically if not already set + if (namespace == null) { + val pkg = this@configureKotlinMultiplatform.path.removePrefix(":").replace(":", ".") + namespace = "org.meshtastic.$pkg" + } + } + } + } + + configureKotlin() +} + /** * Configure base Kotlin options for JVM (non-Android) */ diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/MeshtasticFlavor.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/MeshtasticFlavor.kt index f4267a836..f251e4592 100644 --- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/MeshtasticFlavor.kt +++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/MeshtasticFlavor.kt @@ -20,6 +20,7 @@ package org.meshtastic.buildlogic import com.android.build.api.dsl.ApplicationExtension import com.android.build.api.dsl.ApplicationProductFlavor import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.LibraryExtension import com.android.build.api.dsl.ProductFlavor @Suppress("EnumEntryName") @@ -29,15 +30,34 @@ enum class FlavorDimension { @Suppress("EnumEntryName") enum class MeshtasticFlavor(val dimension: FlavorDimension, val default: Boolean = false) { - fdroid(FlavorDimension.marketplace, ), + fdroid(FlavorDimension.marketplace), google(FlavorDimension.marketplace, default = true), } fun configureFlavors( - commonExtension: CommonExtension<*, *, *, *, *, *>, + commonExtension: CommonExtension, flavorConfigurationBlock: ProductFlavor.(flavor: MeshtasticFlavor) -> Unit = {}, ) { - commonExtension.apply { + (commonExtension as? ApplicationExtension)?.apply { + FlavorDimension.entries.forEach { flavorDimension -> + flavorDimensions += flavorDimension.name + } + + productFlavors { + MeshtasticFlavor.entries.forEach { meshtasticFlavor -> + register(meshtasticFlavor.name) { + dimension = meshtasticFlavor.dimension.name + flavorConfigurationBlock(this, meshtasticFlavor) + if (this@apply is ApplicationExtension && this is ApplicationProductFlavor) { + if (meshtasticFlavor.default) { + isDefault = true + } + } + } + } + } + } + (commonExtension as? LibraryExtension)?.apply { FlavorDimension.entries.forEach { flavorDimension -> flavorDimensions += flavorDimension.name } diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/ProjectExtensions.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/ProjectExtensions.kt index bed3a40f2..8d5889e13 100644 --- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/ProjectExtensions.kt +++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/ProjectExtensions.kt @@ -18,15 +18,31 @@ package org.meshtastic.buildlogic import org.gradle.api.Project +import org.gradle.api.artifacts.ExternalModuleDependencyBundle +import org.gradle.api.artifacts.MinimalExternalModuleDependency import org.gradle.api.artifacts.VersionCatalog import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.api.provider.Provider import org.gradle.kotlin.dsl.getByType +import org.gradle.plugin.use.PluginDependency import java.io.FileInputStream import java.util.Properties val Project.libs get(): VersionCatalog = extensions.getByType().named("libs") +fun VersionCatalog.library(alias: String): Provider = + findLibrary(alias).get() + +fun VersionCatalog.bundle(alias: String): Provider = + findBundle(alias).get() + +fun VersionCatalog.plugin(alias: String): Provider = + findPlugin(alias).get() + +fun VersionCatalog.version(alias: String): String = + findVersion(alias).get().requiredVersion + val Project.configProperties: Properties get() { val properties = Properties() @@ -35,4 +51,4 @@ val Project.configProperties: Properties FileInputStream(propertiesFile).use { properties.load(it) } } return properties - } \ No newline at end of file + } diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Spotless.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Spotless.kt index 59d432444..1d61d1e4b 100644 --- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Spotless.kt +++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Spotless.kt @@ -20,21 +20,22 @@ package org.meshtastic.buildlogic import com.diffplug.gradle.spotless.SpotlessExtension import org.gradle.api.Project -internal fun Project.configureSpotless(extension: SpotlessExtension) = extension.apply { +internal fun Project.configureSpotless(extension: SpotlessExtension) { + val ktlintVersion = libs.version("ktlint") extension.apply { ratchetFrom("origin/main") kotlin { target("src/*/kotlin/**/*.kt", "src/*/java/**/*.kt") targetExclude("**/build/**/*.kt") ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) } - ktlint(libs.findVersion("ktlint").get().requiredVersion) + ktlint(ktlintVersion) .setEditorConfigPath(rootProject.file("config/spotless/.editorconfig").path) licenseHeaderFile(rootProject.file("config/spotless/copyright.kt")) } kotlinGradle { target("**/*.gradle.kts") ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) } - ktlint(libs.findVersion("ktlint").get().requiredVersion) + ktlint(ktlintVersion) .setEditorConfigPath(rootProject.file("config/spotless/.editorconfig").path) licenseHeaderFile( rootProject.file("config/spotless/copyright.kts"), diff --git a/build.gradle.kts b/build.gradle.kts index 93ec64ba0..db68d49d6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,7 +20,6 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.kotlin.multiplatform.library) apply false - alias(libs.plugins.android.library) apply false alias(libs.plugins.compose.compiler) apply false alias(libs.plugins.compose.multiplatform) apply false alias(libs.plugins.datadog) apply false diff --git a/core/analytics/build.gradle.kts b/core/analytics/build.gradle.kts index e590d3aa7..c19f95a56 100644 --- a/core/analytics/build.gradle.kts +++ b/core/analytics/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -43,7 +61,7 @@ dependencies { googleApi(libs.firebase.crashlytics) } -android { +configure { buildFeatures { buildConfig = true } namespace = "org.meshtastic.core.analytics" } diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index 87460fda7..35acab069 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -22,7 +22,7 @@ plugins { kotlin { @Suppress("UnstableApiUsage") - androidLibrary { namespace = "org.meshtastic.core.common" } + androidLibrary {} sourceSets { androidMain.dependencies { implementation(libs.androidx.core.ktx) } } } diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index 99331456b..220af53c9 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.kover) } -android { namespace = "org.meshtastic.core.data" } +configure { namespace = "org.meshtastic.core.data" } dependencies { implementation(projects.core.analytics) @@ -38,6 +56,8 @@ dependencies { implementation(libs.androidx.room.runtime) implementation(libs.androidx.room.paging) + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime) implementation(libs.androidx.core.location.altitude) implementation(libs.androidx.paging.common) implementation(libs.kotlinx.serialization.json) diff --git a/core/database/build.gradle.kts b/core/database/build.gradle.kts index a324c2cae..2b4dae22d 100644 --- a/core/database/build.gradle.kts +++ b/core/database/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.meshtastic.kotlinx.serialization) } -android { +configure { namespace = "org.meshtastic.core.database" sourceSets { // Adds exported schema location as test app assets. @@ -39,6 +57,8 @@ dependencies { implementation(libs.kotlinx.serialization.json) implementation(libs.timber) + ksp(libs.androidx.room.compiler) + androidTestImplementation(libs.androidx.test.runner) androidTestImplementation(libs.androidx.test.ext.junit) } diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index f2b9d6459..03397aa88 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.kover) } -android { namespace = "org.meshtastic.core.datastore" } +configure { namespace = "org.meshtastic.core.datastore" } dependencies { implementation(projects.core.proto) diff --git a/core/di/build.gradle.kts b/core/di/build.gradle.kts index 1442d4962..ef82c29a4 100644 --- a/core/di/build.gradle.kts +++ b/core/di/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -20,6 +38,6 @@ plugins { alias(libs.plugins.meshtastic.hilt) } -android { namespace = "org.meshtastic.core.di" } +configure { namespace = "org.meshtastic.core.di" } dependencies {} diff --git a/core/model/build.gradle.kts b/core/model/build.gradle.kts index 6171ec8cb..bb2de5bdb 100644 --- a/core/model/build.gradle.kts +++ b/core/model/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.kotlin.parcelize) } -android { +configure { buildFeatures { buildConfig = true aidl = true diff --git a/core/navigation/build.gradle.kts b/core/navigation/build.gradle.kts index 5356b3c01..8ac94db34 100644 --- a/core/navigation/build.gradle.kts +++ b/core/navigation/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -21,6 +39,6 @@ plugins { alias(libs.plugins.kover) } -android { namespace = "org.meshtastic.core.navigation" } +configure { namespace = "org.meshtastic.core.navigation" } -dependencies {} +dependencies { implementation(libs.kotlinx.serialization.core) } diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 7a16b0557..d1c4414ad 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -24,7 +42,7 @@ plugins { alias(libs.plugins.protobuf) } -android { +configure { buildFeatures { buildConfig = true } namespace = "org.meshtastic.core.network" } diff --git a/core/prefs/build.gradle.kts b/core/prefs/build.gradle.kts index da10d51bd..8238c6b27 100644 --- a/core/prefs/build.gradle.kts +++ b/core/prefs/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -21,6 +39,6 @@ plugins { alias(libs.plugins.kover) } -android { namespace = "org.meshtastic.core.prefs" } +configure { namespace = "org.meshtastic.core.prefs" } dependencies { googleImplementation(libs.maps.compose) } diff --git a/core/proto/build.gradle.kts b/core/proto/build.gradle.kts index b7f71dbce..217e5c018 100644 --- a/core/proto/build.gradle.kts +++ b/core/proto/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -20,7 +38,7 @@ plugins { alias(libs.plugins.protobuf) } -android { namespace = "org.meshtastic.core.proto" } +configure { namespace = "org.meshtastic.core.proto" } // per protobuf-gradle-plugin docs, this is recommended for android protobuf { diff --git a/core/service/build.gradle.kts b/core/service/build.gradle.kts index 27ad58481..3e0453957 100644 --- a/core/service/build.gradle.kts +++ b/core/service/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -17,7 +35,7 @@ plugins { alias(libs.plugins.meshtastic.android.library) } -android { +configure { buildFeatures { aidl = true } namespace = "org.meshtastic.core.service" } diff --git a/core/strings/build.gradle.kts b/core/strings/build.gradle.kts index 2a24987d4..90d7db8b2 100644 --- a/core/strings/build.gradle.kts +++ b/core/strings/build.gradle.kts @@ -14,28 +14,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -import com.android.build.api.dsl.androidLibrary plugins { alias(libs.plugins.meshtastic.kmp.library) - alias(libs.plugins.compose.multiplatform) - alias(libs.plugins.compose.compiler) + id("meshtastic.kmp.library.compose") } kotlin { @Suppress("UnstableApiUsage") - androidLibrary { - namespace = "org.meshtastic.core.strings" - androidResources.enable = true - } - - sourceSets { - commonMain.dependencies { - implementation(compose.runtime) - // API because consuming modules will always need this dependency - api(compose.components.resources) - } - } + androidLibrary { androidResources.enable = true } } compose.resources { diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 1789ede6f..772f8aba7 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.kover) } -android { namespace = "org.meshtastic.core.ui" } +configure { namespace = "org.meshtastic.core.ui" } dependencies { implementation(projects.core.data) diff --git a/feature/firmware/build.gradle.kts b/feature/firmware/build.gradle.kts index b9ed4a228..7a3ddcc96 100644 --- a/feature/firmware/build.gradle.kts +++ b/feature/firmware/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.meshtastic.hilt) } -android { namespace = "org.meshtastic.feature.firmware" } +configure { namespace = "org.meshtastic.feature.firmware" } dependencies { implementation(projects.core.common) diff --git a/feature/intro/build.gradle.kts b/feature/intro/build.gradle.kts index 2f930e7e7..84fb5f4f5 100644 --- a/feature/intro/build.gradle.kts +++ b/feature/intro/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.meshtastic.kotlinx.serialization) } -android { namespace = "org.meshtastic.feature.intro" } +configure { namespace = "org.meshtastic.feature.intro" } dependencies { implementation(projects.core.strings) diff --git a/feature/map/build.gradle.kts b/feature/map/build.gradle.kts index 1affe72b8..4c175dab4 100644 --- a/feature/map/build.gradle.kts +++ b/feature/map/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.meshtastic.hilt) } -android { namespace = "org.meshtastic.feature.map" } +configure { namespace = "org.meshtastic.feature.map" } dependencies { implementation(projects.core.common) diff --git a/feature/messaging/build.gradle.kts b/feature/messaging/build.gradle.kts index 9c5c4a8ac..9f80e291d 100644 --- a/feature/messaging/build.gradle.kts +++ b/feature/messaging/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.meshtastic.hilt) } -android { namespace = "org.meshtastic.feature.messaging" } +configure { namespace = "org.meshtastic.feature.messaging" } dependencies { implementation(projects.core.data) diff --git a/feature/node/build.gradle.kts b/feature/node/build.gradle.kts index f9e00c072..a7f89e78b 100644 --- a/feature/node/build.gradle.kts +++ b/feature/node/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.meshtastic.hilt) } -android { namespace = "org.meshtastic.feature.node" } +configure { namespace = "org.meshtastic.feature.node" } dependencies { implementation(projects.core.data) diff --git a/feature/settings/build.gradle.kts b/feature/settings/build.gradle.kts index fd8fffe5f..7246ee0d4 100644 --- a/feature/settings/build.gradle.kts +++ b/feature/settings/build.gradle.kts @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import com.android.build.api.dsl.LibraryExtension + /* * Copyright (c) 2025 Meshtastic LLC * @@ -22,7 +40,7 @@ plugins { alias(libs.plugins.meshtastic.hilt) } -android { namespace = "org.meshtastic.feature.settings" } +configure { namespace = "org.meshtastic.feature.settings" } dependencies { implementation(projects.core.common) diff --git a/gradle.properties b/gradle.properties index 92bc26c59..dc97717fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -60,4 +60,6 @@ org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true dependency.analysis.print.build.health=true ksp.incremental=true -ksp.incremental.classpath=true \ No newline at end of file +ksp.incremental.classpath=true + +android.newDsl=false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4d06aad12..ac0e4acbd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Android -agp = "8.13.2" +agp = "9.0.0-rc01" appcompat = "1.7.1" accompanist = "0.37.3" @@ -20,6 +20,9 @@ kotlinx-coroutines-android = "1.10.2" kotlinx-serialization = "1.9.0" ktlint = "1.7.1" +# Compose Multiplatform +compose-multiplatform = "1.9.3" + # Google hilt = "2.57.2" maps-compose = "7.0.0" @@ -41,7 +44,7 @@ protobuf = "4.33.2" [libraries] # AndroidX androidx-activity = { module = "androidx.activity:activity" } -androidx-activity-compose = { module = "androidx.activity:activity-compose" } +androidx-activity-compose = { module = "androidx.activity:activity-compose", version = "1.12.2" } androidx-annotation = { module = "androidx.annotation:annotation", version = "1.9.1" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.2.1" } @@ -54,6 +57,7 @@ androidx-emoji2-emojipicker = { module = "androidx.emoji2:emoji2-emojipicker", v androidx-hilt-lifecycle-viewmodel-compose = { module = "androidx.hilt:hilt-lifecycle-viewmodel-compose", version = "1.3.0" } androidx-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycle" } androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "lifecycle" } +androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime", version.ref = "lifecycle" } androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" } androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" } androidx-navigation-common = { module = "androidx.navigation:navigation-common", version.ref = "navigation" } @@ -71,7 +75,6 @@ androidx-room-testing = { module = "androidx.room:room-testing", version.ref = " androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version = "2.11.0" } # AndroidX Compose -accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" } androidx-compose-bom = { module = "androidx.compose:compose-bom-alpha", version = "2025.12.01" } androidx-compose-material-iconsExtended = { module = "androidx.compose.material:material-icons-extended" } androidx-compose-material3 = { module = "androidx.compose.material3:material3" } @@ -97,6 +100,7 @@ guava = { module = "com.google.guava:guava", version = "33.5.0-jre" } hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", version.ref = "hilt" } hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } +hilt-core = { module = "com.google.dagger:hilt-core", version.ref = "hilt" } location-services = { module = "com.google.android.gms:play-services-location", version = "21.3.0" } maps-compose = { module = "com.google.maps.android:maps-compose", version.ref = "maps-compose" } maps-compose-utils = { module = "com.google.maps.android:maps-compose-utils", version.ref = "maps-compose" } @@ -132,6 +136,7 @@ junit = { module = "junit:junit", version = "4.13.2" } # Other aboutlibraries-compose-m3 = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutlibraries" } +accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" } coil = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } coil-network-core = { module = "io.coil-kt.coil3:coil-network-core", version.ref = "coil" } coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } @@ -168,6 +173,7 @@ android-gradleApiPlugin = { module = "com.android.tools.build:gradle-api", versi android-tools-common = { module = "com.android.tools:common", version = "31.13.2" } androidx-room-gradlePlugin = { module = "androidx.room:room-gradle-plugin", version.ref = "room" } compose-gradlePlugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" } +compose-multiplatform-gradlePlugin = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "compose-multiplatform" } datadog-gradlePlugin = { module = "com.datadoghq.dd-sdk-android-gradle-plugin:com.datadoghq.dd-sdk-android-gradle-plugin.gradle.plugin", version = "1.21.0" } detekt-compose = { module = "io.nlopez.compose.rules:detekt", version = "0.5.3" } detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } @@ -184,7 +190,6 @@ spotless-gradlePlugin = { module = "com.diffplug.spotless:spotless-plugin-gradle # Android android-application = { id = "com.android.application", version.ref = "agp" } android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" } -android-library = { id = "com.android.library", version.ref = "agp" } android-lint = { id = "com.android.lint", version.ref = "agp" } # Jetbrains @@ -231,5 +236,6 @@ meshtastic-detekt = { id = "meshtastic.detekt" } meshtastic-hilt = { id = "meshtastic.hilt" } meshtastic-kotlinx-serialization = { id = "meshtastic.kotlinx.serialization" } meshtastic-kmp-library = { id = "meshtastic.kmp.library" } +meshtastic-kmp-library-compose = { id = "meshtastic.kmp.library.compose" } meshtastic-root = { id = "meshtastic.root" } meshtastic-spotless = { id = "meshtastic.spotless" }