Skip to content

Commit d11af85

Browse files
committed
refactor(proto): use Wire native emitAppliedOptions, delete custom SchemaHandler
The upstream proto (meshtastic/protobufs#905) has been simplified to use a scalar bool extension instead of a message wrapper: [(meshtastic.diy_only) = true] Wire 6's emitAppliedOptions now natively generates @DiyOnlyOption(true) annotations on fields, eliminating the need for our custom FieldMetadataSchemaHandler. Changes: - Delete FieldMetadataSchemaHandler.kt (~200 LOC) - Remove wire-schema dependency from build-logic - Remove custom {} handler block from core:proto build - Add emitAppliedOptions = true to Wire kotlin {} config - Update FieldMetadataDemo to demonstrate the native annotation - Bump protobufs submodule to metadata-experiment branch
1 parent f610789 commit d11af85

5 files changed

Lines changed: 77 additions & 209 deletions

File tree

build-logic/convention/build.gradle.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ dependencies {
5656
compileOnly(libs.androidx.room.gradlePlugin)
5757
compileOnly(libs.spotless.gradlePlugin)
5858
compileOnly(libs.test.retry.gradlePlugin)
59-
implementation(libs.wire.schema)
6059

6160
detektPlugins(libs.detekt.formatting)
6261
}

build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/proto/FieldMetadataSchemaHandler.kt

Lines changed: 0 additions & 197 deletions
This file was deleted.

core/proto/build.gradle.kts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ kotlin {
3030
sourceSets {
3131
commonMain {
3232
dependencies { api(libs.wire.runtime) }
33-
kotlin.srcDir(layout.buildDirectory.dir("generated/source/wire-metadata"))
3433
}
3534
}
3635
}
@@ -50,15 +49,10 @@ wire {
5049
// Codebase is already written to use the nullable properties (e.g. packet.decoded vs
5150
// packet.payload_variant.decoded).
5251
boxOneOfsMinSize = 5000
53-
}
54-
// Emit a static ConfigFieldMetadataRegistry from (meshtastic.config_field) annotations.
55-
// Fully automatic — annotating new proto fields requires no changes here or in the handler.
56-
// Only modify the handler if ConfigFieldMetadata gains new sub-fields.
57-
custom {
58-
schemaHandlerFactoryClass =
59-
"org.meshtastic.buildlogic.proto.FieldMetadataSchemaHandlerFactory"
60-
out = layout.buildDirectory.dir("generated/source/wire-metadata").get().asFile.path
61-
exclusive = false
52+
53+
// Emit Kotlin annotations from scalar proto field options (e.g. diy_only).
54+
// Wire natively generates @DiyOnly annotations on fields that carry the option.
55+
emitAppliedOptions = true
6256
}
6357
root("meshtastic.*")
6458
prune("meshtastic.MeshPacket#delayed")
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2025-2026 Meshtastic LLC
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package org.meshtastic.core.proto
19+
20+
import org.meshtastic.proto.DiyOnlyOption
21+
22+
/**
23+
* DEMO: Wire 6 natively generates `@DiyOnlyOption(true)` on proto fields that carry
24+
* `[(meshtastic.diy_only) = true]` — zero custom build code needed.
25+
*
26+
* The annotation has `RUNTIME` retention and targets `PROPERTY` + `FIELD`, so
27+
* it can be queried via reflection on JVM/Android or used as a compile-time marker.
28+
*
29+
* Generated code in `Config.PositionConfig`:
30+
* ```kotlin
31+
* @DiyOnlyOption(true)
32+
* @field:WireField(tag = 8, ...)
33+
* public val rx_gpio: Int = 0,
34+
* ```
35+
*
36+
* See: https://github.com/meshtastic/protobufs/pull/905
37+
*/
38+
object FieldMetadataDemo {
39+
40+
/**
41+
* The [DiyOnlyOption] annotation is available at compile time for reference.
42+
* On JVM/Android, you can reflect over it at runtime:
43+
*
44+
* ```kotlin
45+
* // JVM/Android only (kotlin-reflect):
46+
* val isDiy = Config.PositionConfig::rx_gpio
47+
* .findAnnotation<DiyOnlyOption>()?.value ?: false
48+
* ```
49+
*
50+
* For KMP-safe access without reflection, use a constants map:
51+
*/
52+
val diyOnlyFields: Set<String> = setOf("rx_gpio", "tx_gpio")
53+
54+
/**
55+
* UI gating — hide settings that are diy_only when device isn't DIY:
56+
*
57+
* ```kotlin
58+
* if ("rx_gpio" !in FieldMetadataDemo.diyOnlyFields || deviceIsDiy) {
59+
* DropDownPreference(title = stringResource(Res.string.gps_receive_gpio), ...)
60+
* }
61+
* ```
62+
*/
63+
fun uiGatingExample(deviceIsDiy: Boolean) {
64+
val allFields = listOf("fixed_position", "gps_enabled", "rx_gpio", "tx_gpio")
65+
for (field in allFields) {
66+
val isDiyOnly = field in diyOnlyFields
67+
if (!isDiyOnly || deviceIsDiy) {
68+
println("Showing $field setting")
69+
}
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)