diff --git a/.github/workflows/scheduled-updates.yml b/.github/workflows/scheduled-updates.yml
index dc39620ac..5ff6a3f12 100644
--- a/.github/workflows/scheduled-updates.yml
+++ b/.github/workflows/scheduled-updates.yml
@@ -78,19 +78,24 @@ jobs:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
+ - name: Update Graphs
+ run: ./gradlew graphUpdate
+ continue-on-error: true
+
- name: Create Pull Request if changes occurred
uses: peter-evans/create-pull-request@v8
with:
token: ${{ secrets.CROWDIN_GITHUB_TOKEN }}
commit-message: |
- chore: Scheduled updates (Firmware, Hardware, Translations)
+ chore: Scheduled updates (Firmware, Hardware, Translations, Graphs)
Automated updates for:
- Firmware releases list
- Device hardware list
- Crowdin source string uploads
- Crowdin translation downloads
- title: 'chore: Scheduled updates (Firmware, Hardware, Translations)'
+ - Module dependency graphs
+ title: 'chore: Scheduled updates (Firmware, Hardware, Translations, Graphs)'
body: |
This PR includes automated updates from the scheduled workflow:
@@ -98,6 +103,7 @@ jobs:
- Updated `device_hardware.json` from the Meshtastic API (if changed).
- Source strings were uploaded to Crowdin.
- Latest translations were downloaded from Crowdin (if available).
+ - Updated module dependency graphs in README.md files (if changed).
Please review the changes.
branch: 'scheduled-updates'
diff --git a/app/README.md b/app/README.md
new file mode 100644
index 000000000..7c5d9c29e
--- /dev/null
+++ b/app/README.md
@@ -0,0 +1,179 @@
+# `${projectPath.get()}`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :feature
+ direction TB
+ :feature:firmware[firmware]:::android-library
+ :feature:intro[intro]:::android-library
+ :feature:map[map]:::android-library
+ :feature:messaging[messaging]:::android-library
+ :feature:node[node]:::android-library
+ :feature:settings[settings]:::android-library
+ end
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::kmp-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:di[di]:::android-library
+ :core:model[model]:::android-library
+ :core:navigation[navigation]:::android-library
+ :core:network[network]:::android-library
+ :core:prefs[prefs]:::android-library
+ :core:proto[proto]:::android-library
+ :core:service[service]:::android-library
+ :core:strings[strings]:::kmp-library
+ :core:ui[ui]:::android-library
+ end
+ :app[app]:::android-application
+
+ :app -.-> :core:analytics
+ :app -.-> :core:common
+ :app -.-> :core:data
+ :app -.-> :core:database
+ :app -.-> :core:datastore
+ :app -.-> :core:di
+ :app -.-> :core:model
+ :app -.-> :core:navigation
+ :app -.-> :core:network
+ :app -.-> :core:prefs
+ :app -.-> :core:proto
+ :app -.-> :core:service
+ :app -.-> :core:strings
+ :app -.-> :core:ui
+ :app -.-> :feature:firmware
+ :app -.-> :feature:intro
+ :app -.-> :feature:map
+ :app -.-> :feature:messaging
+ :app -.-> :feature:node
+ :app -.-> :feature:settings
+ :core:analytics -.-> :core:prefs
+ :core:data -.-> :core:analytics
+ :core:data -.-> :core:database
+ :core:data -.-> :core:datastore
+ :core:data -.-> :core:di
+ :core:data -.-> :core:model
+ :core:data -.-> :core:network
+ :core:data -.-> :core:prefs
+ :core:data -.-> :core:proto
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:datastore -.-> :core:proto
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:network -.-> :core:model
+ :core:service -.-> :core:database
+ :core:service -.-> :core:model
+ :core:service -.-> :core:proto
+ :core:ui -.-> :core:data
+ :core:ui -.-> :core:database
+ :core:ui -.-> :core:model
+ :core:ui -.-> :core:prefs
+ :core:ui -.-> :core:proto
+ :core:ui -.-> :core:service
+ :core:ui -.-> :core:strings
+ :feature:firmware -.-> :core:common
+ :feature:firmware -.-> :core:data
+ :feature:firmware -.-> :core:database
+ :feature:firmware -.-> :core:datastore
+ :feature:firmware -.-> :core:model
+ :feature:firmware -.-> :core:navigation
+ :feature:firmware -.-> :core:prefs
+ :feature:firmware -.-> :core:proto
+ :feature:firmware -.-> :core:service
+ :feature:firmware -.-> :core:strings
+ :feature:firmware -.-> :core:ui
+ :feature:intro -.-> :core:strings
+ :feature:map -.-> :core:common
+ :feature:map -.-> :core:data
+ :feature:map -.-> :core:database
+ :feature:map -.-> :core:datastore
+ :feature:map -.-> :core:model
+ :feature:map -.-> :core:navigation
+ :feature:map -.-> :core:prefs
+ :feature:map -.-> :core:proto
+ :feature:map -.-> :core:service
+ :feature:map -.-> :core:strings
+ :feature:map -.-> :core:ui
+ :feature:messaging -.-> :core:data
+ :feature:messaging -.-> :core:database
+ :feature:messaging -.-> :core:model
+ :feature:messaging -.-> :core:prefs
+ :feature:messaging -.-> :core:proto
+ :feature:messaging -.-> :core:service
+ :feature:messaging -.-> :core:strings
+ :feature:messaging -.-> :core:ui
+ :feature:node -.-> :core:data
+ :feature:node -.-> :core:database
+ :feature:node -.-> :core:datastore
+ :feature:node -.-> :core:di
+ :feature:node -.-> :core:model
+ :feature:node -.-> :core:navigation
+ :feature:node -.-> :core:proto
+ :feature:node -.-> :core:service
+ :feature:node -.-> :core:strings
+ :feature:node -.-> :core:ui
+ :feature:node -.-> :feature:map
+ :feature:settings -.-> :core:common
+ :feature:settings -.-> :core:data
+ :feature:settings -.-> :core:database
+ :feature:settings -.-> :core:datastore
+ :feature:settings -.-> :core:model
+ :feature:settings -.-> :core:navigation
+ :feature:settings -.-> :core:prefs
+ :feature:settings -.-> :core:proto
+ :feature:settings -.-> :core:service
+ :feature:settings -.-> :core:strings
+ :feature:settings -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 0dae07d1c..72b0b7829 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -15,9 +15,11 @@
* along with this program. If not, see .
*/
-import com.geeksville.mesh.buildlogic.GitVersionValueSource
+import com.android.build.api.dsl.ApplicationExtension
import com.mikepenz.aboutlibraries.plugin.DuplicateMode
import com.mikepenz.aboutlibraries.plugin.DuplicateRule
+import org.meshtastic.buildlogic.GitVersionValueSource
+import org.meshtastic.buildlogic.configProperties
import java.io.FileInputStream
import java.util.Properties
@@ -43,16 +45,8 @@ if (keystorePropertiesFile.exists()) {
FileInputStream(keystorePropertiesFile).use { keystoreProperties.load(it) }
}
-val configPropertiesFile = rootProject.file("config.properties")
-val configProperties = Properties()
-
-if (configPropertiesFile.exists()) {
- FileInputStream(configPropertiesFile).use { configProperties.load(it) }
-}
-
-android {
+configure {
namespace = configProperties.getProperty("APPLICATION_ID")
- compileSdk = configProperties.getProperty("COMPILE_SDK").toInt()
signingConfigs {
create("release") {
@@ -64,8 +58,6 @@ android {
}
defaultConfig {
applicationId = configProperties.getProperty("APPLICATION_ID")
- minSdk = configProperties.getProperty("MIN_SDK").toInt()
- targetSdk = configProperties.getProperty("TARGET_SDK").toInt()
val vcOffset = configProperties.getProperty("VERSION_CODE_OFFSET")?.toInt() ?: 0
println("Version code offset: $vcOffset")
@@ -167,7 +159,6 @@ secrets {
propertiesFileName = "secrets.properties"
}
-// workaround for https://github.com/google/ksp/issues/1590
androidComponents {
onVariants(selector().all()) { variant ->
if (variant.name == "fdroidDebug") {
diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts
index 3860338eb..a4a275724 100644
--- a/build-logic/convention/build.gradle.kts
+++ b/build-logic/convention/build.gradle.kts
@@ -20,12 +20,11 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
`kotlin-dsl`
alias(libs.plugins.android.lint)
- alias(libs.plugins.dependency.analysis)
alias(libs.plugins.spotless)
alias(libs.plugins.detekt)
}
-group = "com.geeksville.mesh.buildlogic"
+group = "org.meshtastic.buildlogic"
// Configure the build-logic plugins to target JDK 21
// This matches the JDK used to build the project, and is not related to what is running on device.
@@ -158,5 +157,10 @@ gradlePlugin {
implementationClass = "KmpLibraryConventionPlugin"
}
+ register("root") {
+ id = libs.plugins.meshtastic.root.get().pluginId
+ implementationClass = "RootConventionPlugin"
+ }
+
}
}
diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt
index 59d0863ee..4f8129c34 100644
--- a/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt
@@ -16,20 +16,20 @@
*/
import com.android.build.api.dsl.ApplicationExtension
-import com.geeksville.mesh.buildlogic.configureAndroidCompose
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.configureAndroidCompose
class AndroidApplicationComposeConventionPlugin : Plugin {
override fun apply(target: Project) {
with(target) {
apply(plugin = "com.android.application")
apply(plugin = "org.jetbrains.kotlin.plugin.compose")
-
- val extension = extensions.getByType()
- configureAndroidCompose(extension)
+ 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 7fed93657..4ceb8fd21 100644
--- a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt
@@ -16,11 +16,11 @@
*/
import com.android.build.api.dsl.ApplicationExtension
-import com.geeksville.mesh.buildlogic.configureKotlinAndroid
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.configureKotlinAndroid
class AndroidApplicationConventionPlugin : Plugin {
override fun apply(target: Project) {
@@ -32,7 +32,6 @@ class AndroidApplicationConventionPlugin : Plugin {
apply(plugin = "meshtastic.detekt")
apply(plugin = "meshtastic.spotless")
apply(plugin = "meshtastic.analytics")
- apply(plugin = "com.autonomousapps.dependency-analysis")
extensions.configure {
configureKotlinAndroid(this)
diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationFlavorsConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationFlavorsConventionPlugin.kt
index 879df99a2..7407e91fd 100644
--- a/build-logic/convention/src/main/kotlin/AndroidApplicationFlavorsConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidApplicationFlavorsConventionPlugin.kt
@@ -16,15 +16,10 @@
*/
import com.android.build.api.dsl.ApplicationExtension
-import com.geeksville.mesh.buildlogic.MeshtasticFlavor
-import com.geeksville.mesh.buildlogic.configureFlavors
-import com.geeksville.mesh.buildlogic.libs
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.gradle.kotlin.dsl.exclude
+import org.meshtastic.buildlogic.configureFlavors
class AndroidApplicationFlavorsConventionPlugin : Plugin {
override fun apply(target: Project) {
diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
index 1b668c5c0..572f31c57 100644
--- a/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt
@@ -16,20 +16,20 @@
*/
import com.android.build.api.dsl.LibraryExtension
-import com.geeksville.mesh.buildlogic.configureAndroidCompose
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.configureAndroidCompose
class AndroidLibraryComposeConventionPlugin : Plugin {
override fun apply(target: Project) {
with(target) {
apply(plugin = "com.android.library")
apply(plugin = "org.jetbrains.kotlin.plugin.compose")
-
- val extension = extensions.getByType()
- configureAndroidCompose(extension)
+ 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 128ccd98e..a53a3d065 100644
--- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
@@ -17,15 +17,13 @@
import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.variant.LibraryAndroidComponentsExtension
-import com.geeksville.mesh.buildlogic.configureFlavors
-import com.geeksville.mesh.buildlogic.configureKotlinAndroid
-import com.geeksville.mesh.buildlogic.disableUnnecessaryAndroidTests
-import com.geeksville.mesh.buildlogic.libs
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.meshtastic.buildlogic.configureFlavors
+import org.meshtastic.buildlogic.configureKotlinAndroid
+import org.meshtastic.buildlogic.disableUnnecessaryAndroidTests
class AndroidLibraryConventionPlugin : Plugin {
override fun apply(target: Project) {
@@ -35,12 +33,9 @@ class AndroidLibraryConventionPlugin : Plugin {
apply(plugin = "meshtastic.android.lint")
apply(plugin = "meshtastic.detekt")
apply(plugin = "meshtastic.spotless")
- apply(plugin = "com.autonomousapps.dependency-analysis")
extensions.configure {
configureKotlinAndroid(this)
- testOptions.targetSdk = 36
- lint.targetSdk = 36
defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testOptions.animationsDisabled = true
configureFlavors(this)
diff --git a/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt
index 9606318ba..43bc73dc9 100644
--- a/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/AndroidRoomConventionPlugin.kt
@@ -16,13 +16,13 @@
*/
import androidx.room.gradle.RoomExtension
-import com.geeksville.mesh.buildlogic.libs
import com.google.devtools.ksp.gradle.KspExtension
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.meshtastic.buildlogic.libs
class AndroidRoomConventionPlugin : Plugin {
diff --git a/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt b/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt
index 28e9484c6..6fe3fec48 100644
--- a/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt
@@ -1,11 +1,28 @@
-import com.geeksville.mesh.buildlogic.configureDetekt
-import com.geeksville.mesh.buildlogic.configureKotlinJvm
-import com.geeksville.mesh.buildlogic.libs
+/*
+ * 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 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.meshtastic.buildlogic.configureDetekt
+import org.meshtastic.buildlogic.configureKotlinJvm
+import org.meshtastic.buildlogic.libs
class DetektConventionPlugin : Plugin {
override fun apply(target: Project) {
diff --git a/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt b/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt
index 280503ddb..15c707409 100644
--- a/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/HiltConventionPlugin.kt
@@ -15,11 +15,11 @@
* along with this program. If not, see .
*/
-import com.geeksville.mesh.buildlogic.libs
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.libs
class HiltConventionPlugin : Plugin {
override fun apply(target: Project) {
diff --git a/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt
index c0520eae4..30343ce66 100644
--- a/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt
@@ -15,14 +15,14 @@
* along with this program. If not, see .
*/
-import com.android.build.api.dsl.androidLibrary
+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 java.io.FileInputStream
-import java.util.Properties
+import org.meshtastic.buildlogic.configProperties
class KmpLibraryConventionPlugin : Plugin {
override fun apply(target: Project) {
@@ -31,20 +31,11 @@ class KmpLibraryConventionPlugin : Plugin {
apply(plugin = "com.android.kotlin.multiplatform.library")
apply(plugin = "meshtastic.detekt")
apply(plugin = "meshtastic.spotless")
- apply(plugin = "com.autonomousapps.dependency-analysis")
-
- val configPropertiesFile = rootProject.file("config.properties")
- val configProperties = Properties()
-
- if (configPropertiesFile.exists()) {
- FileInputStream(configPropertiesFile).use { configProperties.load(it) }
- }
extensions.configure {
- @Suppress("UnstableApiUsage")
- androidLibrary {
- compileSdk = configProperties.getProperty("COMPILE_SDK").toInt()
- minSdk = configProperties.getProperty("MIN_SDK").toInt()
+ (this as ExtensionAware).extensions.configure("android") {
+ compileSdk = this@with.configProperties.getProperty("COMPILE_SDK").toInt()
+ minSdk = this@with.configProperties.getProperty("MIN_SDK").toInt()
}
}
}
diff --git a/build-logic/convention/src/main/kotlin/KotlinXSerializationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KotlinXSerializationConventionPlugin.kt
index 890b48f1f..07b90ad5a 100644
--- a/build-logic/convention/src/main/kotlin/KotlinXSerializationConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/KotlinXSerializationConventionPlugin.kt
@@ -15,11 +15,11 @@
* along with this program. If not, see .
*/
-import com.geeksville.mesh.buildlogic.libs
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.libs
class KotlinXSerializationConventionPlugin : Plugin {
override fun apply(target: Project) {
diff --git a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/ProjectExtensions.kt b/build-logic/convention/src/main/kotlin/RootConventionPlugin.kt
similarity index 71%
rename from build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/ProjectExtensions.kt
rename to build-logic/convention/src/main/kotlin/RootConventionPlugin.kt
index 2c2b55eb2..6cb891173 100644
--- a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/ProjectExtensions.kt
+++ b/build-logic/convention/src/main/kotlin/RootConventionPlugin.kt
@@ -15,12 +15,13 @@
* along with this program. If not, see .
*/
-package com.geeksville.mesh.buildlogic
-
+import org.gradle.api.Plugin
import org.gradle.api.Project
-import org.gradle.api.artifacts.VersionCatalog
-import org.gradle.api.artifacts.VersionCatalogsExtension
-import org.gradle.kotlin.dsl.getByType
+import org.meshtastic.buildlogic.configureGraphTasks
-val Project.libs
- get(): VersionCatalog = extensions.getByType().named("libs")
\ No newline at end of file
+class RootConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ require(target.path == ":")
+ target.subprojects { configureGraphTasks() }
+ }
+}
diff --git a/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt b/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt
index c92fd92fb..5ef4318ef 100644
--- a/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt
@@ -1,11 +1,28 @@
+/*
+ * 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.diffplug.gradle.spotless.SpotlessExtension
-import com.geeksville.mesh.buildlogic.configureKotlinJvm
-import com.geeksville.mesh.buildlogic.configureSpotless
-import com.geeksville.mesh.buildlogic.libs
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.meshtastic.buildlogic.configureSpotless
+import org.meshtastic.buildlogic.libs
class SpotlessConventionPlugin : Plugin {
override fun apply(target: Project) {
diff --git a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/AndroidCompose.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt
similarity index 98%
rename from build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/AndroidCompose.kt
rename to build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt
index a59f97576..e8a4d1835 100644
--- a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/AndroidCompose.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-package com.geeksville.mesh.buildlogic
+package org.meshtastic.buildlogic
import com.android.build.api.dsl.CommonExtension
import org.gradle.api.Project
diff --git a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/AndroidInstrumentedTests.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidInstrumentedTests.kt
similarity index 95%
rename from build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/AndroidInstrumentedTests.kt
rename to build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidInstrumentedTests.kt
index dcff2f42d..60544dca9 100644
--- a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/AndroidInstrumentedTests.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidInstrumentedTests.kt
@@ -15,11 +15,10 @@
* along with this program. If not, see .
*/
-package com.geeksville.mesh.buildlogic
+package org.meshtastic.buildlogic
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import org.gradle.api.Project
-import kotlin.io.resolve
/**
* Disable unnecessary Android instrumented tests for the [project] if there is no `androidTest` folder.
diff --git a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/Detekt.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Detekt.kt
similarity index 98%
rename from build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/Detekt.kt
rename to build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Detekt.kt
index 1c39b0554..b6fdd5c9c 100644
--- a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/Detekt.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Detekt.kt
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-package com.geeksville.mesh.buildlogic
+package org.meshtastic.buildlogic
import io.gitlab.arturbosch.detekt.Detekt
import io.gitlab.arturbosch.detekt.extensions.DetektExtension
diff --git a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/GitVersionValueSource.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/GitVersionValueSource.kt
similarity index 95%
rename from build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/GitVersionValueSource.kt
rename to build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/GitVersionValueSource.kt
index 392554390..979994dc3 100644
--- a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/GitVersionValueSource.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/GitVersionValueSource.kt
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-package com.geeksville.mesh.buildlogic
+package org.meshtastic.buildlogic
/*
* Copyright (c) 2025 Meshtastic LLC
@@ -37,6 +37,7 @@ package com.geeksville.mesh.buildlogic
import org.gradle.api.provider.ValueSource
import org.gradle.api.provider.ValueSourceParameters
import org.gradle.process.ExecOperations
+import java.io.ByteArrayOutputStream
import javax.inject.Inject
abstract class GitVersionValueSource : ValueSource {
@@ -45,7 +46,7 @@ abstract class GitVersionValueSource : ValueSource.
+ */
+
+package org.meshtastic.buildlogic
+
+import com.android.utils.associateWithNotNull
+import org.gradle.api.DefaultTask
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.ProjectDependency
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.provider.MapProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.CacheableTask
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.PathSensitive
+import org.gradle.api.tasks.PathSensitivity.NONE
+import org.gradle.api.tasks.TaskAction
+import org.gradle.kotlin.dsl.assign
+import org.gradle.kotlin.dsl.register
+import org.gradle.kotlin.dsl.withType
+import org.meshtastic.buildlogic.PluginType.Unknown
+import kotlin.text.RegexOption.DOT_MATCHES_ALL
+
+/**
+ * Generates module dependency graphs with `graphDump` task, and update the corresponding `README.md` file with `graphUpdate`.
+ *
+ * This is not an optimal implementation and could be improved if needed:
+ * - [Graph.invoke] is **recursively** searching through dependent projects (although in practice it will never reach a stack overflow).
+ * - [Graph.invoke] is entirely re-executed for all projects, without re-using intermediate values.
+ * - [Graph.invoke] is always executed during Gradle's Configuration phase (but takes in general less than 1 ms for a project).
+ *
+ * The resulting graphs can be configured with `graph.ignoredProjects` and `graph.supportedConfigurations` properties.
+ */
+private class Graph(
+ private val root: Project,
+ private val dependencies: MutableMap>> = mutableMapOf(),
+ private val plugins: MutableMap = mutableMapOf(),
+ private val seen: MutableSet = mutableSetOf(),
+) {
+
+ private val ignoredProjects = root.providers.gradleProperty("graph.ignoredProjects")
+ .map { it.split(",").toSet() }
+ .orElse(emptySet())
+ private val supportedConfigurations =
+ root.providers.gradleProperty("graph.supportedConfigurations")
+ .map { it.split(",").toSet() }
+ .orElse(setOf("api", "implementation", "baselineProfile", "testedApks"))
+
+ operator fun invoke(project: Project = root): Graph {
+ if (project.path in seen) return this
+ seen += project.path
+ plugins.putIfAbsent(
+ project,
+ PluginType.entries.firstOrNull { project.pluginManager.hasPlugin(it.id) } ?: Unknown,
+ )
+ dependencies.compute(project) { _, u -> u.orEmpty() }
+ project.configurations
+ .matching { it.name in supportedConfigurations.get() }
+ .associateWithNotNull { it.dependencies.withType().ifEmpty { null } }
+ .flatMap { (c, value) -> value.map { dep -> c to project.project(dep.path) } }
+ .filter { (_, p) -> p.path !in ignoredProjects.get() }
+ .forEach { (configuration: Configuration, projectDependency: Project) ->
+ dependencies.compute(project) { _, u -> u.orEmpty() + (configuration to projectDependency) }
+ invoke(projectDependency)
+ }
+ return this
+ }
+
+ fun dependencies(): Map>> = dependencies
+ .mapKeys { it.key.path }
+ .mapValues { it.value.mapTo(mutableSetOf()) { (c, p) -> c.name to p.path } }
+
+ fun plugins() = plugins.mapKeys { it.key.path }
+}
+
+/**
+ * Declaration order is important, as only the first match will be retained.
+ */
+internal enum class PluginType(val id: String, val ref: String, val style: String) {
+ AndroidApplication(
+ id = "meshtastic.android.application",
+ ref = "android-application",
+ style = "fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ AndroidApplicationCompose(
+ id = "meshtastic.android.application.compose",
+ ref = "android-application-compose",
+ style = "fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ AndroidFeature(
+ id = "meshtastic.android.feature",
+ ref = "android-feature",
+ style = "fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ AndroidLibrary(
+ id = "meshtastic.android.library",
+ ref = "android-library",
+ style = "fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ AndroidLibraryCompose(
+ // Assuming this might be a distinct plugin
+ id = "meshtastic.android.library.compose",
+ ref = "android-library-compose",
+ style = "fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ AndroidTest(
+ id = "meshtastic.android.test", // Placeholder
+ ref = "android-test",
+ style = "fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ Jvm(
+ id = "meshtastic.jvm.library", // Placeholder
+ ref = "jvm-library",
+ style = "fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ KmpLibrary(
+ id = "meshtastic.kmp.library",
+ ref = "kmp-library",
+ style = "fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000",
+ ),
+ Unknown(
+ id = "?",
+ ref = "unknown",
+ style = "fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000",
+ ),
+}
+
+internal fun Project.configureGraphTasks() {
+ if (!buildFile.exists()) return // Ignore root modules without build file
+ val dumpTask = tasks.register("graphDump") {
+ val graph = Graph(this@configureGraphTasks).invoke()
+ projectPath = this@configureGraphTasks.path
+ dependencies = graph.dependencies()
+ plugins = graph.plugins()
+ output = this@configureGraphTasks.layout.buildDirectory.file("mermaid/graph.txt")
+ legend = this@configureGraphTasks.layout.buildDirectory.file("mermaid/legend.txt")
+ }
+ tasks.register("graphUpdate") {
+ projectPath = this@configureGraphTasks.path
+ input = dumpTask.flatMap { it.output }
+ legend = dumpTask.flatMap { it.legend }
+ output = this@configureGraphTasks.layout.projectDirectory.file("README.md")
+ }
+}
+
+@CacheableTask
+private abstract class GraphDumpTask : DefaultTask() {
+
+ @get:Input
+ abstract val projectPath: Property
+
+ @get:Input
+ abstract val dependencies: MapProperty>>
+
+ @get:Input
+ abstract val plugins: MapProperty
+
+ @get:OutputFile
+ abstract val output: RegularFileProperty
+
+ @get:OutputFile
+ abstract val legend: RegularFileProperty
+
+ override fun getDescription() = "Dumps project dependencies to a mermaid file."
+
+ @TaskAction
+ operator fun invoke() {
+ output.get().asFile.writeText(mermaid())
+ legend.get().asFile.writeText(legend())
+ logger.lifecycle(output.get().asFile.toPath().toUri().toString())
+ }
+
+ private fun mermaid() = buildString {
+ val dependencies: Set = dependencies.get()
+ .flatMapTo(mutableSetOf()) { (project, entries) -> entries.map { it.toDependency(project) } }
+ // FrontMatter configuration (not supported yet on GitHub.com)
+ appendLine(
+ // language=YAML
+ """
+ ---
+ config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+ ---
+ """.trimIndent(),
+ )
+ // Graph declaration
+ appendLine("graph TB")
+ // Nodes and subgraphs
+ val (rootProjects, nestedProjects) = dependencies
+ .map { listOf(it.project, it.dependency) }.flatten().toSet()
+ .plus(projectPath.get()) // Special case when this specific module has no other dependency
+ .groupBy { it.substringBeforeLast(":") }
+ .entries.partition { it.key.isEmpty() }
+
+ val orderedGroups = nestedProjects.groupBy {
+ if (it.key.count { char -> char == ':' } > 1) it.key.substringBeforeLast(":") else ""
+ }
+
+ orderedGroups.forEach { (outerGroup, innerGroups) ->
+ if (outerGroup.isNotEmpty()) {
+ appendLine(" subgraph $outerGroup")
+ appendLine(" direction TB")
+ }
+ innerGroups.sortedWith(
+ compareBy(
+ { (group, _) ->
+ dependencies.filter { dep ->
+ val toGroup = dep.dependency.substringBeforeLast(":")
+ toGroup == group && dep.project.substringBeforeLast(":") != group
+ }.count()
+ },
+ { -it.value.size },
+ ),
+ ).forEach { (group, projects) ->
+ val indent = if (outerGroup.isNotEmpty()) 4 else 2
+ appendLine(" ".repeat(indent) + "subgraph $group")
+ appendLine(" ".repeat(indent) + " direction TB")
+ projects.sorted().forEach {
+ appendLine(it.alias(indent = indent + 2, plugins.get().getValue(it)))
+ }
+ appendLine(" ".repeat(indent) + "end")
+ }
+ if (outerGroup.isNotEmpty()) {
+ appendLine(" end")
+ }
+ }
+
+ rootProjects.flatMap { it.value }.sortedDescending().forEach {
+ appendLine(it.alias(indent = 2, plugins.get().getValue(it)))
+ }
+ // Links
+ if (dependencies.isNotEmpty()) appendLine()
+ dependencies
+ .sortedWith(compareBy({ it.project }, { it.dependency }, { it.configuration }))
+ .forEach { appendLine(it.link(indent = 2)) }
+ // Classes
+ appendLine()
+ PluginType.entries.forEach { appendLine(it.classDef()) }
+ }
+
+ private fun legend() = buildString {
+ appendLine("graph TB")
+ listOf(
+ "application" to PluginType.AndroidApplication,
+ "feature" to PluginType.AndroidFeature,
+ "library" to PluginType.AndroidLibrary,
+ "jvm" to PluginType.Jvm,
+ "kmp-library" to PluginType.KmpLibrary,
+ ).forEach { (name, type) ->
+ appendLine(name.alias(indent = 2, type))
+ }
+ appendLine()
+ listOf(
+ Dependency("application", "implementation", "feature"),
+ Dependency("library", "api", "jvm"),
+ ).forEach {
+ appendLine(it.link(indent = 2))
+ }
+ appendLine()
+ PluginType.entries.forEach { appendLine(it.classDef()) }
+ }
+
+ private class Dependency(val project: String, val configuration: String, val dependency: String)
+
+ private fun Pair.toDependency(project: String) =
+ Dependency(project, configuration = first, dependency = second)
+
+ private fun String.alias(indent: Int, pluginType: PluginType): String = buildString {
+ append(" ".repeat(indent))
+ append(this@alias)
+ append("[").append(substringAfterLast(":")).append("]:::")
+ append(pluginType.ref)
+ }
+
+ private fun Dependency.link(indent: Int) = buildString {
+ append(" ".repeat(indent))
+ append(project).append(" ")
+ append(
+ when (configuration) {
+ "api" -> "-->"
+ "implementation" -> "-.->"
+ else -> "-.->|$configuration|"
+ },
+ )
+ append(" ").append(dependency)
+ }
+
+ private fun PluginType.classDef() = "classDef $ref $style;"
+}
+
+@CacheableTask
+private abstract class GraphUpdateTask : DefaultTask() {
+
+ @get:Input
+ abstract val projectPath: Property
+
+ @get:InputFile
+ @get:PathSensitive(NONE)
+ abstract val input: RegularFileProperty
+
+ @get:InputFile
+ @get:PathSensitive(NONE)
+ abstract val legend: RegularFileProperty
+
+ @get:OutputFile
+ abstract val output: RegularFileProperty
+
+ override fun getDescription() = "Updates Markdown file with the corresponding dependency graph."
+
+ @TaskAction
+ operator fun invoke() = with(output.get().asFile) {
+ if (!exists()) {
+ createNewFile()
+ writeText(
+ """
+ # `${projectPath.get()}`
+
+ ## Module dependency graph
+
+
+
+ """.trimIndent(),
+ )
+ }
+ val mermaid = input.get().asFile.readText().trimTrailingNewLines()
+ val legend = legend.get().asFile.readText().trimTrailingNewLines()
+ val regex = """()(.*?)()""".toRegex(DOT_MATCHES_ALL)
+ val text = readText().replace(regex) { match ->
+ val (start, _, end) = match.destructured
+ """
+ |$start
+ |```mermaid
+ |$mermaid
+ |```
+ |
+ |📋 Graph legend
+ |
+ |```mermaid
+ |$legend
+ |```
+ |
+ |
+ |$end
+ """.trimMargin()
+ }
+ writeText(text)
+ }
+
+ private fun String.trimTrailingNewLines() = lines()
+ .dropLastWhile(String::isBlank)
+ .joinToString(System.lineSeparator())
+}
diff --git a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/KotlinAndroid.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt
similarity index 98%
rename from build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/KotlinAndroid.kt
rename to build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt
index a226fcaf4..1100ef547 100644
--- a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/KotlinAndroid.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-package com.geeksville.mesh.buildlogic
+package org.meshtastic.buildlogic
import com.android.build.api.dsl.CommonExtension
import org.gradle.api.JavaVersion
diff --git a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/MeshtasticFlavor.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/MeshtasticFlavor.kt
similarity index 98%
rename from build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/MeshtasticFlavor.kt
rename to build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/MeshtasticFlavor.kt
index 53094a1f6..f4267a836 100644
--- a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/MeshtasticFlavor.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/MeshtasticFlavor.kt
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-package com.geeksville.mesh.buildlogic
+package org.meshtastic.buildlogic
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.ApplicationProductFlavor
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
new file mode 100644
index 000000000..bed3a40f2
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/ProjectExtensions.kt
@@ -0,0 +1,38 @@
+/*
+ * 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 .
+ */
+
+package org.meshtastic.buildlogic
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalog
+import org.gradle.api.artifacts.VersionCatalogsExtension
+import org.gradle.kotlin.dsl.getByType
+import java.io.FileInputStream
+import java.util.Properties
+
+val Project.libs
+ get(): VersionCatalog = extensions.getByType().named("libs")
+
+val Project.configProperties: Properties
+ get() {
+ val properties = Properties()
+ val propertiesFile = rootProject.file("config.properties")
+ if (propertiesFile.exists()) {
+ FileInputStream(propertiesFile).use { properties.load(it) }
+ }
+ return properties
+ }
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/Spotless.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Spotless.kt
similarity index 97%
rename from build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/Spotless.kt
rename to build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Spotless.kt
index 65d10ea9f..59d432444 100644
--- a/build-logic/convention/src/main/kotlin/com/geeksville/mesh/buildlogic/Spotless.kt
+++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/Spotless.kt
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-package com.geeksville.mesh.buildlogic
+package org.meshtastic.buildlogic
import com.diffplug.gradle.spotless.SpotlessExtension
import org.gradle.api.Project
diff --git a/build.gradle.kts b/build.gradle.kts
index 05cd28452..93ec64ba0 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -37,10 +37,10 @@ plugins {
alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.protobuf) apply false
alias(libs.plugins.secrets) apply false
- alias(libs.plugins.dependency.analysis)
alias(libs.plugins.detekt) apply false
alias(libs.plugins.kover)
alias(libs.plugins.spotless) apply false
+ alias(libs.plugins.meshtastic.root)
}
@@ -95,26 +95,3 @@ dependencies {
kover(projects.feature.node)
kover(projects.feature.settings)
}
-
-dependencyAnalysis {
- structure {
- ignoreKtx(true)
-
- // Hilt Android is required by the Hilt plugin, but isn't directly used in many cases. Group
- // these dependencies together so warnings aren't triggered. If neither of these are being
- // used, the module likely shouldn't be applying the Hilt plugin.
- bundle("hilt-core") {
- includeDependency("com.google.dagger:hilt-core")
- includeDependency(libs.hilt.android)
- }
- }
-
- issues {
- all {
- onUnusedDependencies {
- severity("fail")
- exclude("androidx.compose.ui:ui-test-manifest")
- }
- }
- }
-}
\ No newline at end of file
diff --git a/core/analytics/README.md b/core/analytics/README.md
new file mode 100644
index 000000000..cdeb0473c
--- /dev/null
+++ b/core/analytics/README.md
@@ -0,0 +1,58 @@
+# `:core:analytics`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:prefs[prefs]:::android-library
+ end
+
+ :core:analytics -.-> :core:prefs
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/common/README.md b/core/common/README.md
new file mode 100644
index 000000000..21e22dda5
--- /dev/null
+++ b/core/common/README.md
@@ -0,0 +1,55 @@
+# `:core:common`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::kmp-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/data/README.md b/core/data/README.md
new file mode 100644
index 000000000..34b610805
--- /dev/null
+++ b/core/data/README.md
@@ -0,0 +1,83 @@
+# `:core:data`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::kmp-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:di[di]:::android-library
+ :core:model[model]:::android-library
+ :core:network[network]:::android-library
+ :core:prefs[prefs]:::android-library
+ :core:proto[proto]:::android-library
+ :core:strings[strings]:::kmp-library
+ end
+
+ :core:analytics -.-> :core:prefs
+ :core:data -.-> :core:analytics
+ :core:data -.-> :core:database
+ :core:data -.-> :core:datastore
+ :core:data -.-> :core:di
+ :core:data -.-> :core:model
+ :core:data -.-> :core:network
+ :core:data -.-> :core:prefs
+ :core:data -.-> :core:proto
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:datastore -.-> :core:proto
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:network -.-> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/database/README.md b/core/database/README.md
new file mode 100644
index 000000000..a4c95300b
--- /dev/null
+++ b/core/database/README.md
@@ -0,0 +1,66 @@
+# `:core:database`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::kmp-library
+ :core:database[database]:::android-library
+ :core:model[model]:::android-library
+ :core:proto[proto]:::android-library
+ :core:strings[strings]:::kmp-library
+ end
+
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/datastore/README.md b/core/datastore/README.md
new file mode 100644
index 000000000..675a015e8
--- /dev/null
+++ b/core/datastore/README.md
@@ -0,0 +1,58 @@
+# `:core:datastore`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:datastore[datastore]:::android-library
+ :core:proto[proto]:::android-library
+ end
+
+ :core:datastore -.-> :core:proto
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/di/README.md b/core/di/README.md
new file mode 100644
index 000000000..2a5702504
--- /dev/null
+++ b/core/di/README.md
@@ -0,0 +1,55 @@
+# `:core:di`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:di[di]:::android-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/model/README.md b/core/model/README.md
new file mode 100644
index 000000000..9edc886dd
--- /dev/null
+++ b/core/model/README.md
@@ -0,0 +1,62 @@
+# `:core:model`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::kmp-library
+ :core:model[model]:::android-library
+ :core:proto[proto]:::android-library
+ :core:strings[strings]:::kmp-library
+ end
+
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/navigation/README.md b/core/navigation/README.md
new file mode 100644
index 000000000..25bd7e59f
--- /dev/null
+++ b/core/navigation/README.md
@@ -0,0 +1,55 @@
+# `:core:navigation`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:navigation[navigation]:::android-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/network/README.md b/core/network/README.md
new file mode 100644
index 000000000..9c059acfa
--- /dev/null
+++ b/core/network/README.md
@@ -0,0 +1,64 @@
+# `:core:network`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::kmp-library
+ :core:model[model]:::android-library
+ :core:network[network]:::android-library
+ :core:proto[proto]:::android-library
+ :core:strings[strings]:::kmp-library
+ end
+
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:network -.-> :core:model
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/prefs/README.md b/core/prefs/README.md
new file mode 100644
index 000000000..0e60ace28
--- /dev/null
+++ b/core/prefs/README.md
@@ -0,0 +1,55 @@
+# `:core:prefs`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:prefs[prefs]:::android-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/proto/README.md b/core/proto/README.md
new file mode 100644
index 000000000..4ef4fc5e1
--- /dev/null
+++ b/core/proto/README.md
@@ -0,0 +1,55 @@
+# `:core:proto`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:proto[proto]:::android-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/service/README.md b/core/service/README.md
new file mode 100644
index 000000000..fef8eee89
--- /dev/null
+++ b/core/service/README.md
@@ -0,0 +1,70 @@
+# `:core:service`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:common[common]:::kmp-library
+ :core:database[database]:::android-library
+ :core:model[model]:::android-library
+ :core:proto[proto]:::android-library
+ :core:service[service]:::android-library
+ :core:strings[strings]:::kmp-library
+ end
+
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:service -.-> :core:database
+ :core:service -.-> :core:model
+ :core:service -.-> :core:proto
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/strings/README.md b/core/strings/README.md
new file mode 100644
index 000000000..3c5f5bf77
--- /dev/null
+++ b/core/strings/README.md
@@ -0,0 +1,55 @@
+# `:core:strings`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:strings[strings]:::kmp-library
+ end
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/core/ui/README.md b/core/ui/README.md
new file mode 100644
index 000000000..3d60c5b1c
--- /dev/null
+++ b/core/ui/README.md
@@ -0,0 +1,95 @@
+# `:core:ui`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::kmp-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:di[di]:::android-library
+ :core:model[model]:::android-library
+ :core:network[network]:::android-library
+ :core:prefs[prefs]:::android-library
+ :core:proto[proto]:::android-library
+ :core:service[service]:::android-library
+ :core:strings[strings]:::kmp-library
+ :core:ui[ui]:::android-library
+ end
+
+ :core:analytics -.-> :core:prefs
+ :core:data -.-> :core:analytics
+ :core:data -.-> :core:database
+ :core:data -.-> :core:datastore
+ :core:data -.-> :core:di
+ :core:data -.-> :core:model
+ :core:data -.-> :core:network
+ :core:data -.-> :core:prefs
+ :core:data -.-> :core:proto
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:datastore -.-> :core:proto
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:network -.-> :core:model
+ :core:service -.-> :core:database
+ :core:service -.-> :core:model
+ :core:service -.-> :core:proto
+ :core:ui -.-> :core:data
+ :core:ui -.-> :core:database
+ :core:ui -.-> :core:model
+ :core:ui -.-> :core:prefs
+ :core:ui -.-> :core:proto
+ :core:ui -.-> :core:service
+ :core:ui -.-> :core:strings
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/firmware/README.md b/feature/firmware/README.md
new file mode 100644
index 000000000..11b444873
--- /dev/null
+++ b/feature/firmware/README.md
@@ -0,0 +1,111 @@
+# `:feature:firmware`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :feature
+ direction TB
+ :feature:firmware[firmware]:::android-library
+ end
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::kmp-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:di[di]:::android-library
+ :core:model[model]:::android-library
+ :core:navigation[navigation]:::android-library
+ :core:network[network]:::android-library
+ :core:prefs[prefs]:::android-library
+ :core:proto[proto]:::android-library
+ :core:service[service]:::android-library
+ :core:strings[strings]:::kmp-library
+ :core:ui[ui]:::android-library
+ end
+
+ :core:analytics -.-> :core:prefs
+ :core:data -.-> :core:analytics
+ :core:data -.-> :core:database
+ :core:data -.-> :core:datastore
+ :core:data -.-> :core:di
+ :core:data -.-> :core:model
+ :core:data -.-> :core:network
+ :core:data -.-> :core:prefs
+ :core:data -.-> :core:proto
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:datastore -.-> :core:proto
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:network -.-> :core:model
+ :core:service -.-> :core:database
+ :core:service -.-> :core:model
+ :core:service -.-> :core:proto
+ :core:ui -.-> :core:data
+ :core:ui -.-> :core:database
+ :core:ui -.-> :core:model
+ :core:ui -.-> :core:prefs
+ :core:ui -.-> :core:proto
+ :core:ui -.-> :core:service
+ :core:ui -.-> :core:strings
+ :feature:firmware -.-> :core:common
+ :feature:firmware -.-> :core:data
+ :feature:firmware -.-> :core:database
+ :feature:firmware -.-> :core:datastore
+ :feature:firmware -.-> :core:model
+ :feature:firmware -.-> :core:navigation
+ :feature:firmware -.-> :core:prefs
+ :feature:firmware -.-> :core:proto
+ :feature:firmware -.-> :core:service
+ :feature:firmware -.-> :core:strings
+ :feature:firmware -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/intro/README.md b/feature/intro/README.md
new file mode 100644
index 000000000..fd542728e
--- /dev/null
+++ b/feature/intro/README.md
@@ -0,0 +1,61 @@
+# `:feature:intro`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :feature
+ direction TB
+ :feature:intro[intro]:::android-library
+ end
+ subgraph :core
+ direction TB
+ :core:strings[strings]:::kmp-library
+ end
+
+ :feature:intro -.-> :core:strings
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/map/README.md b/feature/map/README.md
new file mode 100644
index 000000000..c1e863890
--- /dev/null
+++ b/feature/map/README.md
@@ -0,0 +1,111 @@
+# `:feature:map`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :feature
+ direction TB
+ :feature:map[map]:::android-library
+ end
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::kmp-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:di[di]:::android-library
+ :core:model[model]:::android-library
+ :core:navigation[navigation]:::android-library
+ :core:network[network]:::android-library
+ :core:prefs[prefs]:::android-library
+ :core:proto[proto]:::android-library
+ :core:service[service]:::android-library
+ :core:strings[strings]:::kmp-library
+ :core:ui[ui]:::android-library
+ end
+
+ :core:analytics -.-> :core:prefs
+ :core:data -.-> :core:analytics
+ :core:data -.-> :core:database
+ :core:data -.-> :core:datastore
+ :core:data -.-> :core:di
+ :core:data -.-> :core:model
+ :core:data -.-> :core:network
+ :core:data -.-> :core:prefs
+ :core:data -.-> :core:proto
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:datastore -.-> :core:proto
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:network -.-> :core:model
+ :core:service -.-> :core:database
+ :core:service -.-> :core:model
+ :core:service -.-> :core:proto
+ :core:ui -.-> :core:data
+ :core:ui -.-> :core:database
+ :core:ui -.-> :core:model
+ :core:ui -.-> :core:prefs
+ :core:ui -.-> :core:proto
+ :core:ui -.-> :core:service
+ :core:ui -.-> :core:strings
+ :feature:map -.-> :core:common
+ :feature:map -.-> :core:data
+ :feature:map -.-> :core:database
+ :feature:map -.-> :core:datastore
+ :feature:map -.-> :core:model
+ :feature:map -.-> :core:navigation
+ :feature:map -.-> :core:prefs
+ :feature:map -.-> :core:proto
+ :feature:map -.-> :core:service
+ :feature:map -.-> :core:strings
+ :feature:map -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/messaging/README.md b/feature/messaging/README.md
new file mode 100644
index 000000000..2a4c48a78
--- /dev/null
+++ b/feature/messaging/README.md
@@ -0,0 +1,107 @@
+# `:feature:messaging`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :feature
+ direction TB
+ :feature:messaging[messaging]:::android-library
+ end
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::kmp-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:di[di]:::android-library
+ :core:model[model]:::android-library
+ :core:network[network]:::android-library
+ :core:prefs[prefs]:::android-library
+ :core:proto[proto]:::android-library
+ :core:service[service]:::android-library
+ :core:strings[strings]:::kmp-library
+ :core:ui[ui]:::android-library
+ end
+
+ :core:analytics -.-> :core:prefs
+ :core:data -.-> :core:analytics
+ :core:data -.-> :core:database
+ :core:data -.-> :core:datastore
+ :core:data -.-> :core:di
+ :core:data -.-> :core:model
+ :core:data -.-> :core:network
+ :core:data -.-> :core:prefs
+ :core:data -.-> :core:proto
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:datastore -.-> :core:proto
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:network -.-> :core:model
+ :core:service -.-> :core:database
+ :core:service -.-> :core:model
+ :core:service -.-> :core:proto
+ :core:ui -.-> :core:data
+ :core:ui -.-> :core:database
+ :core:ui -.-> :core:model
+ :core:ui -.-> :core:prefs
+ :core:ui -.-> :core:proto
+ :core:ui -.-> :core:service
+ :core:ui -.-> :core:strings
+ :feature:messaging -.-> :core:data
+ :feature:messaging -.-> :core:database
+ :feature:messaging -.-> :core:model
+ :feature:messaging -.-> :core:prefs
+ :feature:messaging -.-> :core:proto
+ :feature:messaging -.-> :core:service
+ :feature:messaging -.-> :core:strings
+ :feature:messaging -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/node/README.md b/feature/node/README.md
new file mode 100644
index 000000000..cd444704c
--- /dev/null
+++ b/feature/node/README.md
@@ -0,0 +1,123 @@
+# `:feature:node`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :feature
+ direction TB
+ :feature:map[map]:::android-library
+ :feature:node[node]:::android-library
+ end
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::kmp-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:di[di]:::android-library
+ :core:model[model]:::android-library
+ :core:navigation[navigation]:::android-library
+ :core:network[network]:::android-library
+ :core:prefs[prefs]:::android-library
+ :core:proto[proto]:::android-library
+ :core:service[service]:::android-library
+ :core:strings[strings]:::kmp-library
+ :core:ui[ui]:::android-library
+ end
+
+ :core:analytics -.-> :core:prefs
+ :core:data -.-> :core:analytics
+ :core:data -.-> :core:database
+ :core:data -.-> :core:datastore
+ :core:data -.-> :core:di
+ :core:data -.-> :core:model
+ :core:data -.-> :core:network
+ :core:data -.-> :core:prefs
+ :core:data -.-> :core:proto
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:datastore -.-> :core:proto
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:network -.-> :core:model
+ :core:service -.-> :core:database
+ :core:service -.-> :core:model
+ :core:service -.-> :core:proto
+ :core:ui -.-> :core:data
+ :core:ui -.-> :core:database
+ :core:ui -.-> :core:model
+ :core:ui -.-> :core:prefs
+ :core:ui -.-> :core:proto
+ :core:ui -.-> :core:service
+ :core:ui -.-> :core:strings
+ :feature:map -.-> :core:common
+ :feature:map -.-> :core:data
+ :feature:map -.-> :core:database
+ :feature:map -.-> :core:datastore
+ :feature:map -.-> :core:model
+ :feature:map -.-> :core:navigation
+ :feature:map -.-> :core:prefs
+ :feature:map -.-> :core:proto
+ :feature:map -.-> :core:service
+ :feature:map -.-> :core:strings
+ :feature:map -.-> :core:ui
+ :feature:node -.-> :core:data
+ :feature:node -.-> :core:database
+ :feature:node -.-> :core:datastore
+ :feature:node -.-> :core:di
+ :feature:node -.-> :core:model
+ :feature:node -.-> :core:navigation
+ :feature:node -.-> :core:proto
+ :feature:node -.-> :core:service
+ :feature:node -.-> :core:strings
+ :feature:node -.-> :core:ui
+ :feature:node -.-> :feature:map
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/feature/settings/README.md b/feature/settings/README.md
new file mode 100644
index 000000000..7640d4e36
--- /dev/null
+++ b/feature/settings/README.md
@@ -0,0 +1,111 @@
+# `:feature:settings`
+
+## Module dependency graph
+
+
+```mermaid
+---
+config:
+ layout: elk
+ elk:
+ nodePlacementStrategy: SIMPLE
+---
+graph TB
+ subgraph :feature
+ direction TB
+ :feature:settings[settings]:::android-library
+ end
+ subgraph :core
+ direction TB
+ :core:analytics[analytics]:::android-library
+ :core:common[common]:::kmp-library
+ :core:data[data]:::android-library
+ :core:database[database]:::android-library
+ :core:datastore[datastore]:::android-library
+ :core:di[di]:::android-library
+ :core:model[model]:::android-library
+ :core:navigation[navigation]:::android-library
+ :core:network[network]:::android-library
+ :core:prefs[prefs]:::android-library
+ :core:proto[proto]:::android-library
+ :core:service[service]:::android-library
+ :core:strings[strings]:::kmp-library
+ :core:ui[ui]:::android-library
+ end
+
+ :core:analytics -.-> :core:prefs
+ :core:data -.-> :core:analytics
+ :core:data -.-> :core:database
+ :core:data -.-> :core:datastore
+ :core:data -.-> :core:di
+ :core:data -.-> :core:model
+ :core:data -.-> :core:network
+ :core:data -.-> :core:prefs
+ :core:data -.-> :core:proto
+ :core:database -.-> :core:model
+ :core:database -.-> :core:proto
+ :core:database -.-> :core:strings
+ :core:datastore -.-> :core:proto
+ :core:model -.-> :core:common
+ :core:model -.-> :core:proto
+ :core:model -.-> :core:strings
+ :core:network -.-> :core:model
+ :core:service -.-> :core:database
+ :core:service -.-> :core:model
+ :core:service -.-> :core:proto
+ :core:ui -.-> :core:data
+ :core:ui -.-> :core:database
+ :core:ui -.-> :core:model
+ :core:ui -.-> :core:prefs
+ :core:ui -.-> :core:proto
+ :core:ui -.-> :core:service
+ :core:ui -.-> :core:strings
+ :feature:settings -.-> :core:common
+ :feature:settings -.-> :core:data
+ :feature:settings -.-> :core:database
+ :feature:settings -.-> :core:datastore
+ :feature:settings -.-> :core:model
+ :feature:settings -.-> :core:navigation
+ :feature:settings -.-> :core:prefs
+ :feature:settings -.-> :core:proto
+ :feature:settings -.-> :core:service
+ :feature:settings -.-> :core:strings
+ :feature:settings -.-> :core:ui
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+📋 Graph legend
+
+```mermaid
+graph TB
+ application[application]:::android-application
+ feature[feature]:::android-feature
+ library[library]:::android-library
+ jvm[jvm]:::jvm-library
+ kmp-library[kmp-library]:::kmp-library
+
+ application -.-> feature
+ library --> jvm
+
+classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
+classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
+classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
+classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
+classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
+```
+
+
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 41e99c0a0..49d5a52a1 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -210,7 +210,7 @@ firebase-perf = { id = "com.google.firebase.firebase-perf", version = "2.0.2" }
# Other
aboutlibraries = { id = "com.mikepenz.aboutlibraries.plugin.android", version.ref = "aboutlibraries" }
datadog = { id = "com.datadoghq.dd-sdk-android-gradle-plugin", version = "1.21.0" }
-dependency-analysis = { id = "com.autonomousapps.dependency-analysis", version = "3.5.1" }
+# Removed dependency-analysis = { id = "com.autonomousapps.dependency-analysis", version = "3.5.1" }
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
dokka = { id = "org.jetbrains.dokka", version = "2.1.0" }
protobuf = { id = "com.google.protobuf", version = "0.9.6" }
@@ -231,4 +231,5 @@ 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-root = { id = "meshtastic.root" }
meshtastic-spotless = { id = "meshtastic.spotless" }
diff --git a/mesh_service_example/build.gradle.kts b/mesh_service_example/build.gradle.kts
index 79a696378..5bf8f8bcd 100644
--- a/mesh_service_example/build.gradle.kts
+++ b/mesh_service_example/build.gradle.kts
@@ -14,25 +14,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-import com.geeksville.mesh.buildlogic.FlavorDimension
-import com.geeksville.mesh.buildlogic.MeshtasticFlavor
-/*
- * 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.ApplicationExtension
+import org.meshtastic.buildlogic.FlavorDimension
+import org.meshtastic.buildlogic.MeshtasticFlavor
plugins {
alias(libs.plugins.meshtastic.android.application)
@@ -42,7 +27,7 @@ plugins {
alias(libs.plugins.kover)
}
-android {
+configure {
namespace = "com.meshtastic.android.meshserviceexample"
defaultConfig {
// Force this app to use the Google variant of any modules it's using that apply AndroidLibraryConventionPlugin