From 9804c38fb8a15c4b321954a44fb95e0627a72771 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:56:43 -0600 Subject: [PATCH] feat(settings): add about screen with open source licenses (#4012) Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com> --- app/build.gradle.kts | 11 +++ .../mesh/navigation/SettingsNavigation.kt | 3 + .../org/meshtastic/core/navigation/Routes.kt | 2 + .../composeResources/values/strings.xml | 2 +- feature/map/build.gradle.kts | 5 +- feature/settings/build.gradle.kts | 1 + .../feature/settings/AboutScreen.kt | 69 +++++++++++++++++++ .../feature/settings/SettingsScreen.kt | 11 +++ gradle/libs.versions.toml | 3 + 9 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 feature/settings/src/main/kotlin/org/meshtastic/feature/settings/AboutScreen.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 017017233..0dae07d1c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -16,6 +16,8 @@ */ import com.geeksville.mesh.buildlogic.GitVersionValueSource +import com.mikepenz.aboutlibraries.plugin.DuplicateMode +import com.mikepenz.aboutlibraries.plugin.DuplicateRule import java.io.FileInputStream import java.util.Properties @@ -31,6 +33,7 @@ plugins { alias(libs.plugins.secrets) alias(libs.plugins.dokka) alias(libs.plugins.kover) + alias(libs.plugins.aboutlibraries) } val keystorePropertiesFile = rootProject.file("keystore.properties") @@ -278,3 +281,11 @@ dokka { maxHeapSize = "6g" } } + +aboutLibraries { + export { excludeFields = listOf("generated") } + library { + duplicationMode = DuplicateMode.MERGE + duplicationRule = DuplicateRule.SIMPLE + } +} diff --git a/app/src/main/java/com/geeksville/mesh/navigation/SettingsNavigation.kt b/app/src/main/java/com/geeksville/mesh/navigation/SettingsNavigation.kt index 3c201ff2e..e2371d05b 100644 --- a/app/src/main/java/com/geeksville/mesh/navigation/SettingsNavigation.kt +++ b/app/src/main/java/com/geeksville/mesh/navigation/SettingsNavigation.kt @@ -32,6 +32,7 @@ import org.meshtastic.core.navigation.Graph import org.meshtastic.core.navigation.NodesRoutes import org.meshtastic.core.navigation.Route import org.meshtastic.core.navigation.SettingsRoutes +import org.meshtastic.feature.settings.AboutScreen import org.meshtastic.feature.settings.SettingsScreen import org.meshtastic.feature.settings.debugging.DebugScreen import org.meshtastic.feature.settings.navigation.ConfigRoute @@ -172,6 +173,8 @@ fun NavGraphBuilder.settingsGraph(navController: NavHostController) { ) { DebugScreen(onNavigateUp = navController::navigateUp) } + + composable { AboutScreen(onNavigateUp = navController::navigateUp) } } } diff --git a/core/navigation/src/main/kotlin/org/meshtastic/core/navigation/Routes.kt b/core/navigation/src/main/kotlin/org/meshtastic/core/navigation/Routes.kt index cb592d958..7032d4354 100644 --- a/core/navigation/src/main/kotlin/org/meshtastic/core/navigation/Routes.kt +++ b/core/navigation/src/main/kotlin/org/meshtastic/core/navigation/Routes.kt @@ -148,6 +148,8 @@ object SettingsRoutes { @Serializable data object DebugPanel : Route + @Serializable data object About : Route + // endregion } diff --git a/core/strings/src/commonMain/composeResources/values/strings.xml b/core/strings/src/commonMain/composeResources/values/strings.xml index 1ad9d59ad..c5d07fdbd 100644 --- a/core/strings/src/commonMain/composeResources/values/strings.xml +++ b/core/strings/src/commonMain/composeResources/values/strings.xml @@ -216,7 +216,7 @@ You must update this application on the app store (or Github). It is too old to talk to this radio firmware. Please read our docs on this topic. None (disable) Service notifications - About + Acknowledgements This Channel URL is invalid and can not be used This contact is invalid and can not be added Debug Panel diff --git a/feature/map/build.gradle.kts b/feature/map/build.gradle.kts index 3372a7c94..1affe72b8 100644 --- a/feature/map/build.gradle.kts +++ b/feature/map/build.gradle.kts @@ -49,10 +49,11 @@ dependencies { implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.navigation.common) implementation(libs.material) - implementation(libs.osmbonuspack) - implementation(libs.osmdroid.android) implementation(libs.timber) + fdroidImplementation(libs.osmbonuspack) + fdroidImplementation(libs.osmdroid.android) + googleImplementation(libs.location.services) googleImplementation(libs.maps.compose) googleImplementation(libs.maps.compose.utils) diff --git a/feature/settings/build.gradle.kts b/feature/settings/build.gradle.kts index feb38c645..fd8fffe5f 100644 --- a/feature/settings/build.gradle.kts +++ b/feature/settings/build.gradle.kts @@ -37,6 +37,7 @@ dependencies { implementation(projects.core.strings) implementation(projects.core.ui) + implementation(libs.aboutlibraries.compose.m3) implementation(libs.accompanist.permissions) implementation(libs.androidx.appcompat) implementation(libs.androidx.compose.material.iconsExtended) diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/AboutScreen.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/AboutScreen.kt new file mode 100644 index 000000000..326486c34 --- /dev/null +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/AboutScreen.kt @@ -0,0 +1,69 @@ +/* + * 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.feature.settings + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import com.mikepenz.aboutlibraries.Libs +import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer +import com.mikepenz.aboutlibraries.util.withContext +import org.jetbrains.compose.resources.stringResource +import org.meshtastic.core.strings.Res +import org.meshtastic.core.strings.acknowledgements +import org.meshtastic.core.ui.component.MainAppBar + +@Composable +fun AboutScreen(onNavigateUp: () -> Unit) { + Scaffold( + topBar = { + MainAppBar( + title = stringResource(Res.string.acknowledgements), + canNavigateUp = true, + onNavigateUp = onNavigateUp, + ourNode = null, + showNodeChip = false, + actions = {}, + onClickChip = {}, + ) + }, + ) { paddingValues -> + val context = LocalContext.current + val libraries = Libs.Builder().withContext(context).build() + LibrariesContainer( + showAuthor = true, + showVersion = true, + showDescription = true, + showLicenseBadges = true, + showFundingBadges = true, + modifier = Modifier.fillMaxSize().padding(paddingValues), + libraries = libraries, + ) + } +} + +@Preview +@Composable +fun AboutScreenPreview() { + MaterialTheme { AboutScreen(onNavigateUp = {}) } +} diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/SettingsScreen.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/SettingsScreen.kt index 487acea42..e5c3124cd 100644 --- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/SettingsScreen.kt +++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/SettingsScreen.kt @@ -40,6 +40,7 @@ import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight import androidx.compose.material.icons.filled.BugReport import androidx.compose.material.icons.rounded.AppSettingsAlt import androidx.compose.material.icons.rounded.FormatPaint +import androidx.compose.material.icons.rounded.Info import androidx.compose.material.icons.rounded.Language import androidx.compose.material.icons.rounded.LocationOn import androidx.compose.material.icons.rounded.Memory @@ -76,7 +77,9 @@ import org.jetbrains.compose.resources.stringResource import org.meshtastic.core.common.gpsDisabled import org.meshtastic.core.database.DatabaseConstants import org.meshtastic.core.navigation.Route +import org.meshtastic.core.navigation.SettingsRoutes import org.meshtastic.core.strings.Res +import org.meshtastic.core.strings.acknowledgements import org.meshtastic.core.strings.analytics_okay import org.meshtastic.core.strings.app_settings import org.meshtastic.core.strings.app_version @@ -422,6 +425,14 @@ fun SettingsScreen( settingsLauncher.launch(intent) } + ListItem( + text = stringResource(Res.string.acknowledgements), + leadingIcon = Icons.Rounded.Info, + trailingIcon = null, + ) { + onNavigate(SettingsRoutes.About) + } + AppVersionButton( excludedModulesUnlocked = excludedModulesUnlocked, appVersionName = settingsViewModel.appVersionName, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 132a729e0..98e25c717 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,6 +29,7 @@ ktor = "3.3.3" ktorfit = "2.7.1" # Other +aboutlibraries = "13.1.0" coil = "3.3.0" dd-sdk-android = "3.4.0" detekt = "1.23.8" @@ -128,6 +129,7 @@ androidx-test-runner = { module = "androidx.test:runner", version = "1.7.0" } junit = { module = "junit:junit", version = "4.13.2" } # Other +aboutlibraries-compose-m3 = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutlibraries" } coil = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } coil-network-core = { module = "io.coil-kt.coil3:coil-network-core", version.ref = "coil" } coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } @@ -205,6 +207,7 @@ firebase-crashlytics = { id = "com.google.firebase.crashlytics", version = "3.0. 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" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }