diff --git a/core/proto/build.gradle.kts b/core/proto/build.gradle.kts index e60195e199..c3650d26b3 100644 --- a/core/proto/build.gradle.kts +++ b/core/proto/build.gradle.kts @@ -27,7 +27,11 @@ kotlin { // Override minSdk for ATAK compatibility (standard is 26) android { minSdk = 21 } - sourceSets { commonMain.dependencies { api(libs.wire.runtime) } } + sourceSets { + commonMain { + dependencies { api(libs.wire.runtime) } + } + } } wire { @@ -45,6 +49,10 @@ wire { // Codebase is already written to use the nullable properties (e.g. packet.decoded vs // packet.payload_variant.decoded). boxOneOfsMinSize = 5000 + + // Emit Kotlin annotations from scalar proto field options (e.g. diy_only). + // Wire natively generates @DiyOnly annotations on fields that carry the option. + emitAppliedOptions = true } root("meshtastic.*") prune("meshtastic.MeshPacket#delayed") diff --git a/core/proto/src/commonMain/kotlin/org/meshtastic/core/proto/FieldMetadataDemo.kt b/core/proto/src/commonMain/kotlin/org/meshtastic/core/proto/FieldMetadataDemo.kt new file mode 100644 index 0000000000..f701aceeb6 --- /dev/null +++ b/core/proto/src/commonMain/kotlin/org/meshtastic/core/proto/FieldMetadataDemo.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025-2026 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.core.proto + +import org.meshtastic.proto.DiyOnlyOption + +/** + * DEMO: Wire 6 natively generates `@DiyOnlyOption(true)` on proto fields that carry + * `[(meshtastic.diy_only) = true]` — zero custom build code needed. + * + * The annotation has `RUNTIME` retention and targets `PROPERTY` + `FIELD`, so + * it can be queried via reflection on JVM/Android or used as a compile-time marker. + * + * Generated code in `Config.PositionConfig`: + * ```kotlin + * @DiyOnlyOption(true) + * @field:WireField(tag = 8, ...) + * public val rx_gpio: Int = 0, + * ``` + * + * See: https://github.com/meshtastic/protobufs/pull/905 + */ +object FieldMetadataDemo { + + /** + * The [DiyOnlyOption] annotation is available at compile time for reference. + * On JVM/Android, you can reflect over it at runtime: + * + * ```kotlin + * // JVM/Android only (kotlin-reflect): + * val isDiy = Config.PositionConfig::rx_gpio + * .findAnnotation()?.value ?: false + * ``` + * + * For KMP-safe access without reflection, use a constants map: + */ + val diyOnlyFields: Set = setOf("rx_gpio", "tx_gpio") + + /** + * UI gating — hide settings that are diy_only when device isn't DIY: + * + * ```kotlin + * if ("rx_gpio" !in FieldMetadataDemo.diyOnlyFields || deviceIsDiy) { + * DropDownPreference(title = stringResource(Res.string.gps_receive_gpio), ...) + * } + * ``` + */ + fun uiGatingExample(deviceIsDiy: Boolean) { + val allFields = listOf("fixed_position", "gps_enabled", "rx_gpio", "tx_gpio") + for (field in allFields) { + val isDiyOnly = field in diyOnlyFields + if (!isDiyOnly || deviceIsDiy) { + println("Showing $field setting") + } + } + } +} \ No newline at end of file diff --git a/core/proto/src/main/proto b/core/proto/src/main/proto index 10a16897b4..fc5a1a25de 160000 --- a/core/proto/src/main/proto +++ b/core/proto/src/main/proto @@ -1 +1 @@ -Subproject commit 10a16897b46914854bb46bd94bedb16c6fad3a8b +Subproject commit fc5a1a25de8a79fd28dbf1b6ec7bd61100f7eb71 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c603a00e1c..53629727bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -167,6 +167,7 @@ maps-compose-widgets = { module = "com.google.maps.android:maps-compose-widgets" mlkit-barcode-scanning = { module = "com.google.mlkit:barcode-scanning", version.ref = "mlkit-barcode-scanning" } play-services-maps = { module = "com.google.android.gms:play-services-maps", version = "20.0.0" } wire-runtime = { module = "com.squareup.wire:wire-runtime", version.ref = "wire" } +wire-schema = { module = "com.squareup.wire:wire-schema", version.ref = "wire" } zxing-core = { module = "com.google.zxing:core", version = "3.5.4" } qrcode-kotlin = { module = "io.github.g0dkar:qrcode-kotlin", version.ref = "qrcode-kotlin" }