Filter module settings based on excluded_modules field

This commit is contained in:
Jake-B 2025-03-28 15:53:48 -04:00
parent b212bc8761
commit 18db01eb7f
4 changed files with 123 additions and 62 deletions

View file

@ -6366,6 +6366,9 @@
}
}
}
},
"Currently showing modules that may not be supported by this node." : {
},
"Currently the recommended way to update ESP32 devices is using the web flasher on a desktop computer from a chrome based browser. It does not work on mobile devices or over BLE." : {
"localizations" : {
@ -30354,6 +30357,9 @@
}
}
}
},
"This node does not support any configurable modules." : {
},
"This will disable fixed position and remove the currently set position." : {
"localizations" : {

View file

@ -226,6 +226,7 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, sessionPass
newMetadata.hasEthernet = metadata.hasEthernet_p
newMetadata.role = Int32(metadata.role.rawValue)
newMetadata.positionFlags = Int32(metadata.positionFlags)
newMetadata.excludedModules = Int32(metadata.excludedModules)
// Swift does strings weird, this does work to get the version without the github hash
let lastDotIndex = metadata.firmwareVersion.lastIndex(of: ".")
var version = metadata.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: metadata.firmwareVersion))]

View file

@ -76,6 +76,7 @@
<entity name="DeviceMetadataEntity" representedClassName="DeviceMetadataEntity" syncable="YES" codeGenerationType="class">
<attribute name="canShutdown" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="deviceStateVersion" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="excludedModules" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="firmwareVersion" optional="YES" attributeType="String"/>
<attribute name="hasBluetooth" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="hasEthernet" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>

View file

@ -8,6 +8,7 @@
import SwiftUI
import OSLog
import TipKit
import MeshtasticProtobufs
struct Settings: View {
@Environment(\.managedObjectContext) var context
@ -25,10 +26,21 @@ struct Settings: View {
@State private var selectedNode: Int = 0
@State private var preferredNodeNum: Int = 0
@State private var moduleOverride: Bool = false
@ObservedObject
var router: Router
// MARK: Helper
private func isModuleSupported(_ module: ExcludedModules) -> Bool {
return moduleOverride || Int(nodes.first(where: { $0.num == preferredNodeNum })?.metadata?.excludedModules ?? Int32.zero) & module.rawValue == 0
}
private func isAnySupported(_ modules: [ExcludedModules]) -> Bool {
return modules.map(isModuleSupported).contains(true)
}
// MARK: Views
var radioConfigurationSection: some View {
@ -153,57 +165,70 @@ struct Settings: View {
}
var moduleConfigurationSection: some View {
Section("module.configuration") {
NavigationLink(value: SettingsNavigationState.ambientLighting) {
Label {
Text("Ambient Lighting")
} icon: {
Image(systemName: "light.max")
Section {
if isModuleSupported(.ambientlightingConfig) {
NavigationLink(value: SettingsNavigationState.ambientLighting) {
Label {
Text("Ambient Lighting")
} icon: {
Image(systemName: "light.max")
}
}
}
NavigationLink(value: SettingsNavigationState.cannedMessages) {
Label {
Text("Canned Messages")
} icon: {
Image(systemName: "list.bullet.rectangle.fill")
if isModuleSupported(.cannedmsgConfig) {
NavigationLink(value: SettingsNavigationState.cannedMessages) {
Label {
Text("Canned Messages")
} icon: {
Image(systemName: "list.bullet.rectangle.fill")
}
}
}
NavigationLink(value: SettingsNavigationState.detectionSensor) {
Label {
Text("detection.sensor")
} icon: {
Image(systemName: "sensor")
}
}
NavigationLink(value: SettingsNavigationState.externalNotification) {
Label {
Text("external.notification")
} icon: {
Image(systemName: "megaphone")
}
}
NavigationLink(value: SettingsNavigationState.mqtt) {
Label {
Text("mqtt")
} icon: {
Image(systemName: "dot.radiowaves.up.forward")
}
}
NavigationLink(value: SettingsNavigationState.rangeTest) {
Label {
Text("range.test")
} icon: {
Image(systemName: "point.3.connected.trianglepath.dotted")
if isModuleSupported(.detectionsensorConfig) {
NavigationLink(value: SettingsNavigationState.detectionSensor) {
Label {
Text("detection.sensor")
} icon: {
Image(systemName: "sensor")
}
}
}
if let node = nodes.first(where: { $0.num == preferredNodeNum }),
node.metadata?.hasWifi ?? false {
node.metadata?.hasWifi ?? false, isModuleSupported(.extnotifConfig) {
NavigationLink(value: SettingsNavigationState.externalNotification) {
Label {
Text("external.notification")
} icon: {
Image(systemName: "megaphone")
}
}
}
if isModuleSupported(.mqttConfig) {
NavigationLink(value: SettingsNavigationState.mqtt) {
Label {
Text("mqtt")
} icon: {
Image(systemName: "dot.radiowaves.up.forward")
}
}
}
if isModuleSupported(.rangetestConfig) {
NavigationLink(value: SettingsNavigationState.rangeTest) {
Label {
Text("range.test")
} icon: {
Image(systemName: "point.3.connected.trianglepath.dotted")
}
}
}
if let node = nodes.first(where: { $0.num == preferredNodeNum }),
node.metadata?.hasWifi ?? false, isModuleSupported(.paxcounterConfig) {
NavigationLink(value: SettingsNavigationState.paxCounter) {
Label {
Text("config.module.paxcounter.settings")
@ -213,37 +238,62 @@ struct Settings: View {
}
}
NavigationLink(value: SettingsNavigationState.ringtone) {
Label {
Text("ringtone")
} icon: {
Image(systemName: "music.note.list")
if isModuleSupported(.audioConfig) {
NavigationLink(value: SettingsNavigationState.ringtone) {
Label {
Text("ringtone")
} icon: {
Image(systemName: "music.note.list")
}
}
}
NavigationLink(value: SettingsNavigationState.serial) {
Label {
Text("serial")
} icon: {
Image(systemName: "terminal")
if let node = nodes.first(where: { $0.num == preferredNodeNum }),
node.metadata?.hasWifi ?? false, isModuleSupported(.serialConfig) {
NavigationLink(value: SettingsNavigationState.serial) {
Label {
Text("serial")
} icon: {
Image(systemName: "terminal")
}
}
}
NavigationLink(value: SettingsNavigationState.storeAndForward) {
Label {
Text("Store & Forward")
} icon: {
Image(systemName: "envelope.arrow.triangle.branch")
if isModuleSupported(.storeforwardConfig) {
NavigationLink(value: SettingsNavigationState.storeAndForward) {
Label {
Text("Store & Forward")
} icon: {
Image(systemName: "envelope.arrow.triangle.branch")
}
}
}
NavigationLink(value: SettingsNavigationState.telemetry) {
Label {
Text("telemetry")
} icon: {
Image(systemName: "chart.xyaxis.line")
if isModuleSupported(.telemetryConfig) {
NavigationLink(value: SettingsNavigationState.telemetry) {
Label {
Text("telemetry")
} icon: {
Image(systemName: "chart.xyaxis.line")
}
}
}
// Update this list with the modules that are shown above. If all are not supported
// Then show a message.
if !isAnySupported([.ambientlightingConfig, .cannedmsgConfig,
.detectionsensorConfig, .extnotifConfig,
.mqttConfig, .rangetestConfig, .paxcounterConfig,
.audioConfig, .serialConfig, .storeforwardConfig,
.telemetryConfig]) {
Text("This node does not support any configurable modules.")
}
} header: {
Text("module.configuration")
} footer: {
if moduleOverride {
Text("Currently showing modules that may not be supported by this node.")
}
}
}
@ -497,7 +547,10 @@ struct Settings: View {
}
.navigationTitle("settings")
.navigationBarItems(
leading: MeshtasticLogo()
leading: MeshtasticLogo().onLongPressGesture(minimumDuration: 1.0) {
self.moduleOverride.toggle()
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
}
)
}
}