diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index c17157b8..ea0af322 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -979,7 +979,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0.6; + MARKETING_VERSION = 2.0.7; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1012,7 +1012,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.0.6; + MARKETING_VERSION = 2.0.7; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 4bba33be..c3c1da54 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -198,6 +198,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { self.connectedPeripheral = nil self.isConnecting = false + self.isConnected = false self.isSubscribed = false if let e = error { // https://developer.apple.com/documentation/corebluetooth/cberror/code @@ -501,11 +502,12 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { MeshLogger.log("ℹ️ MESH PACKET received for Simulator App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .audioApp: MeshLogger.log("ℹ️ MESH PACKET received for Audio App UNHANDLED \(try! decodedInfo.packet.jsonString())") + case .tracerouteApp: + MeshLogger.log("ℹ️ MESH PACKET received for Trace Route App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .UNRECOGNIZED(_): MeshLogger.log("ℹ️ MESH PACKET received for Other App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .max: print("MAX PORT NUM OF 511") - } // MARK: Check for an All / Broadcast User and delete it as a transition to multi channel diff --git a/Meshtastic/Protobufs/config.pb.swift b/Meshtastic/Protobufs/config.pb.swift index ebd95f47..3c300b12 100644 --- a/Meshtastic/Protobufs/config.pb.swift +++ b/Meshtastic/Protobufs/config.pb.swift @@ -815,6 +815,12 @@ struct Config { /// NUM_CHANNELS (Where num channels depends on the regulatory region). var channelNum: UInt32 = 0 + /// + /// If true, duty cycle limits will be exceeded and thus you're possibly not following + /// the local regulations if you're not a HAM. + /// Has no effect if the duty cycle of the used region is 100%. + var overrideDutyCycle: Bool = false + /// /// For testing it is useful sometimes to force a node to never listen to /// particular other nodes (simulating radio out of range). All nodenums listed @@ -1830,6 +1836,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem 9: .standard(proto: "tx_enabled"), 10: .standard(proto: "tx_power"), 11: .standard(proto: "channel_num"), + 12: .standard(proto: "override_duty_cycle"), 103: .standard(proto: "ignore_incoming"), ] @@ -1850,6 +1857,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem case 9: try { try decoder.decodeSingularBoolField(value: &self.txEnabled) }() case 10: try { try decoder.decodeSingularInt32Field(value: &self.txPower) }() case 11: try { try decoder.decodeSingularUInt32Field(value: &self.channelNum) }() + case 12: try { try decoder.decodeSingularBoolField(value: &self.overrideDutyCycle) }() case 103: try { try decoder.decodeRepeatedUInt32Field(value: &self.ignoreIncoming) }() default: break } @@ -1890,6 +1898,9 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if self.channelNum != 0 { try visitor.visitSingularUInt32Field(value: self.channelNum, fieldNumber: 11) } + if self.overrideDutyCycle != false { + try visitor.visitSingularBoolField(value: self.overrideDutyCycle, fieldNumber: 12) + } if !self.ignoreIncoming.isEmpty { try visitor.visitPackedUInt32Field(value: self.ignoreIncoming, fieldNumber: 103) } @@ -1908,6 +1919,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if lhs.txEnabled != rhs.txEnabled {return false} if lhs.txPower != rhs.txPower {return false} if lhs.channelNum != rhs.channelNum {return false} + if lhs.overrideDutyCycle != rhs.overrideDutyCycle {return false} if lhs.ignoreIncoming != rhs.ignoreIncoming {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true diff --git a/Meshtastic/Protobufs/mesh.pb.swift b/Meshtastic/Protobufs/mesh.pb.swift index 860dcc91..a2dd9a94 100644 --- a/Meshtastic/Protobufs/mesh.pb.swift +++ b/Meshtastic/Protobufs/mesh.pb.swift @@ -968,6 +968,10 @@ struct Routing { /// (possibly due to bad channel permissions) case noResponse // = 8 + /// + /// Cannot send currently because duty cycle regulations will be violated. + case dutyCycleLimit // = 9 + /// /// The application layer service on the remote node received your request, but considered your request somehow invalid case badRequest // = 32 @@ -993,6 +997,7 @@ struct Routing { case 6: self = .noChannel case 7: self = .tooLarge case 8: self = .noResponse + case 9: self = .dutyCycleLimit case 32: self = .badRequest case 33: self = .notAuthorized default: self = .UNRECOGNIZED(rawValue) @@ -1010,6 +1015,7 @@ struct Routing { case .noChannel: return 6 case .tooLarge: return 7 case .noResponse: return 8 + case .dutyCycleLimit: return 9 case .badRequest: return 32 case .notAuthorized: return 33 case .UNRECOGNIZED(let i): return i @@ -1035,6 +1041,7 @@ extension Routing.Error: CaseIterable { .noChannel, .tooLarge, .noResponse, + .dutyCycleLimit, .badRequest, .notAuthorized, ] @@ -2627,6 +2634,7 @@ extension Routing.Error: SwiftProtobuf._ProtoNameProviding { 6: .same(proto: "NO_CHANNEL"), 7: .same(proto: "TOO_LARGE"), 8: .same(proto: "NO_RESPONSE"), + 9: .same(proto: "DUTY_CYCLE_LIMIT"), 32: .same(proto: "BAD_REQUEST"), 33: .same(proto: "NOT_AUTHORIZED"), ] diff --git a/Meshtastic/Protobufs/module_config.pb.swift b/Meshtastic/Protobufs/module_config.pb.swift index 9de93522..3f0709a2 100644 --- a/Meshtastic/Protobufs/module_config.pb.swift +++ b/Meshtastic/Protobufs/module_config.pb.swift @@ -241,14 +241,6 @@ struct ModuleConfig { /// Whether Audio is enabled var codec2Enabled: Bool = false - /// - /// ADC where Microphone is connected - var micChan: UInt32 = 0 - - /// - /// DAC where Speaker is connected - var ampPin: UInt32 = 0 - /// /// PTT Pin var pttPin: UInt32 = 0 @@ -257,6 +249,22 @@ struct ModuleConfig { /// The audio sample rate to use for codec2 var bitrate: ModuleConfig.AudioConfig.Audio_Baud = .codec2Default + /// + /// I2S Word Select + var i2SWs: UInt32 = 0 + + /// + /// I2S Data IN + var i2SSd: UInt32 = 0 + + /// + /// I2S Data OUT + var i2SDin: UInt32 = 0 + + /// + /// I2S Clock + var i2SSck: UInt32 = 0 + var unknownFields = SwiftProtobuf.UnknownStorage() /// @@ -1057,10 +1065,12 @@ extension ModuleConfig.AudioConfig: SwiftProtobuf.Message, SwiftProtobuf._Messag static let protoMessageName: String = ModuleConfig.protoMessageName + ".AudioConfig" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "codec2_enabled"), - 2: .standard(proto: "mic_chan"), - 3: .standard(proto: "amp_pin"), - 4: .standard(proto: "ptt_pin"), - 5: .same(proto: "bitrate"), + 2: .standard(proto: "ptt_pin"), + 3: .same(proto: "bitrate"), + 4: .standard(proto: "i2s_ws"), + 5: .standard(proto: "i2s_sd"), + 6: .standard(proto: "i2s_din"), + 7: .standard(proto: "i2s_sck"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -1070,10 +1080,12 @@ extension ModuleConfig.AudioConfig: SwiftProtobuf.Message, SwiftProtobuf._Messag // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularBoolField(value: &self.codec2Enabled) }() - case 2: try { try decoder.decodeSingularUInt32Field(value: &self.micChan) }() - case 3: try { try decoder.decodeSingularUInt32Field(value: &self.ampPin) }() - case 4: try { try decoder.decodeSingularUInt32Field(value: &self.pttPin) }() - case 5: try { try decoder.decodeSingularEnumField(value: &self.bitrate) }() + case 2: try { try decoder.decodeSingularUInt32Field(value: &self.pttPin) }() + case 3: try { try decoder.decodeSingularEnumField(value: &self.bitrate) }() + case 4: try { try decoder.decodeSingularUInt32Field(value: &self.i2SWs) }() + case 5: try { try decoder.decodeSingularUInt32Field(value: &self.i2SSd) }() + case 6: try { try decoder.decodeSingularUInt32Field(value: &self.i2SDin) }() + case 7: try { try decoder.decodeSingularUInt32Field(value: &self.i2SSck) }() default: break } } @@ -1083,27 +1095,35 @@ extension ModuleConfig.AudioConfig: SwiftProtobuf.Message, SwiftProtobuf._Messag if self.codec2Enabled != false { try visitor.visitSingularBoolField(value: self.codec2Enabled, fieldNumber: 1) } - if self.micChan != 0 { - try visitor.visitSingularUInt32Field(value: self.micChan, fieldNumber: 2) - } - if self.ampPin != 0 { - try visitor.visitSingularUInt32Field(value: self.ampPin, fieldNumber: 3) - } if self.pttPin != 0 { - try visitor.visitSingularUInt32Field(value: self.pttPin, fieldNumber: 4) + try visitor.visitSingularUInt32Field(value: self.pttPin, fieldNumber: 2) } if self.bitrate != .codec2Default { - try visitor.visitSingularEnumField(value: self.bitrate, fieldNumber: 5) + try visitor.visitSingularEnumField(value: self.bitrate, fieldNumber: 3) + } + if self.i2SWs != 0 { + try visitor.visitSingularUInt32Field(value: self.i2SWs, fieldNumber: 4) + } + if self.i2SSd != 0 { + try visitor.visitSingularUInt32Field(value: self.i2SSd, fieldNumber: 5) + } + if self.i2SDin != 0 { + try visitor.visitSingularUInt32Field(value: self.i2SDin, fieldNumber: 6) + } + if self.i2SSck != 0 { + try visitor.visitSingularUInt32Field(value: self.i2SSck, fieldNumber: 7) } try unknownFields.traverse(visitor: &visitor) } static func ==(lhs: ModuleConfig.AudioConfig, rhs: ModuleConfig.AudioConfig) -> Bool { if lhs.codec2Enabled != rhs.codec2Enabled {return false} - if lhs.micChan != rhs.micChan {return false} - if lhs.ampPin != rhs.ampPin {return false} if lhs.pttPin != rhs.pttPin {return false} if lhs.bitrate != rhs.bitrate {return false} + if lhs.i2SWs != rhs.i2SWs {return false} + if lhs.i2SSd != rhs.i2SSd {return false} + if lhs.i2SDin != rhs.i2SDin {return false} + if lhs.i2SSck != rhs.i2SSck {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Meshtastic/Protobufs/portnums.pb.swift b/Meshtastic/Protobufs/portnums.pb.swift index 7f58fd3e..91949cd8 100644 --- a/Meshtastic/Protobufs/portnums.pb.swift +++ b/Meshtastic/Protobufs/portnums.pb.swift @@ -130,6 +130,11 @@ enum PortNum: SwiftProtobuf.Enum { /// Project files at https://github.com/GUVWAF/Meshtasticator case simulatorApp // = 69 + /// + /// Provides a traceroute functionality to show the route a packet towards + /// a certain destination would take on the mesh. + case tracerouteApp // = 70 + /// /// Private applications should use portnums >= 256. /// To simplify initial development and testing you can use "PRIVATE_APP" @@ -169,6 +174,7 @@ enum PortNum: SwiftProtobuf.Enum { case 67: self = .telemetryApp case 68: self = .zpsApp case 69: self = .simulatorApp + case 70: self = .tracerouteApp case 256: self = .privateApp case 257: self = .atakForwarder case 511: self = .max @@ -196,6 +202,7 @@ enum PortNum: SwiftProtobuf.Enum { case .telemetryApp: return 67 case .zpsApp: return 68 case .simulatorApp: return 69 + case .tracerouteApp: return 70 case .privateApp: return 256 case .atakForwarder: return 257 case .max: return 511 @@ -228,6 +235,7 @@ extension PortNum: CaseIterable { .telemetryApp, .zpsApp, .simulatorApp, + .tracerouteApp, .privateApp, .atakForwarder, .max, @@ -262,6 +270,7 @@ extension PortNum: SwiftProtobuf._ProtoNameProviding { 67: .same(proto: "TELEMETRY_APP"), 68: .same(proto: "ZPS_APP"), 69: .same(proto: "SIMULATOR_APP"), + 70: .same(proto: "TRACEROUTE_APP"), 256: .same(proto: "PRIVATE_APP"), 257: .same(proto: "ATAK_FORWARDER"), 511: .same(proto: "MAX"), diff --git a/Meshtastic/Views/Messages/Contacts.swift b/Meshtastic/Views/Messages/Contacts.swift index d22b019e..54b00d9e 100644 --- a/Meshtastic/Views/Messages/Contacts.swift +++ b/Meshtastic/Views/Messages/Contacts.swift @@ -46,7 +46,15 @@ struct Contacts: View { .padding(.trailing, 5) VStack { HStack { - Text(String(channel.name ?? "Channel \(channel.index)").camelCaseToWords()).font(.headline) + if channel.name?.isEmpty ?? false { + if channel.role == 1 { + Text(String("PrimaryChannel").camelCaseToWords()).font(.headline) + } else { + Text(String("Channel \(channel.index)").camelCaseToWords()).font(.headline) + } + } else { + Text(String(channel.name ?? "Channel \(channel.index)").camelCaseToWords()).font(.headline) + } Spacer() if channel.allPrivateMessages.count > 0 { VStack (alignment: .trailing) { diff --git a/Meshtastic/Views/Settings/About.swift b/Meshtastic/Views/Settings/About.swift index d880b3fe..8cc59d3c 100644 --- a/Meshtastic/Views/Settings/About.swift +++ b/Meshtastic/Views/Settings/About.swift @@ -34,7 +34,7 @@ struct AboutMeshtastic: View { Link("GitHub Repository", destination: URL(string: "https://github.com/meshtastic/Meshtastic-Apple")!) .font(.title2) } - if locale.region?.identifier == "US" { + if locale.region?.identifier ?? "no locale" == "US" { Section(header: Text("Get Devices")) { Link("Buy Complete Radios", destination: URL(string: "https://www.etsy.com/shop/GarthVH")!) .font(.title2) diff --git a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift index 7eabda05..412282aa 100644 --- a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift +++ b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift @@ -11,6 +11,7 @@ struct BluetoothConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -19,6 +20,8 @@ struct BluetoothConfig: View { @State var enabled = true @State var mode = 0 @State var fixedPin = "123456" + @State var shortPin = false + var pinLength: Int = 6 let numberFormatter: NumberFormatter = { @@ -57,77 +60,66 @@ struct BluetoothConfig: View { TextField("Fixed PIN", text: $fixedPin) .foregroundColor(.gray) .onChange(of: fixedPin, perform: { value in - - let digitCount = fixedPin.utf8.count - // Only mess with the value if it is too big - if digitCount > 6 || digitCount < 6 { - - fixedPin = "123456" - } - - if digitCount < 6 { - - fixedPin = "123456" + //Require that pin is no more than 6 numbers and no less than 6 numbers + if fixedPin.utf8.count == pinLength { + shortPin = false + } else if fixedPin.utf8.count > pinLength { + shortPin = false + fixedPin = String(fixedPin.prefix(pinLength)) + } else if fixedPin.utf8.count < pinLength { + shortPin = true } }) .foregroundColor(.gray) } .keyboardType(.decimalPad) + if shortPin { + + Text("BLE Pin must be 6 digits long.") + .font(.callout) + .foregroundColor(.red) + } } } } .disabled(bleManager.connectedPeripheral == nil) Button { - isPresentingSaveConfirm = true - } label: { - Label("Save", systemImage: "square.and.arrow.down") } - .disabled(bleManager.connectedPeripheral == nil || !hasChanges) + .disabled(bleManager.connectedPeripheral == nil || !hasChanges || shortPin) .buttonStyle(.bordered) .buttonBorderShape(.capsule) .controlSize(.large) .padding() .confirmationDialog( - "Are you sure you want to save?", isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { Button("Save Config for \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")") { - var bc = Config.BluetoothConfig() bc.enabled = enabled bc.mode = BluetoothModes(rawValue: mode)?.protoEnumValue() ?? Config.BluetoothConfig.PairingMode.randomPin bc.fixedPin = UInt32(fixedPin) ?? 123456 - let adminMessageId = bleManager.saveBluetoothConfig(config: bc, fromUser: node!.user!, toUser: node!.user!) - if adminMessageId > 0 { - // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false - - } else { - + goBack() } } - } message: { - Text("After bluetooth config saves the node will reboot.") } } .navigationTitle("Bluetooth (BLE) Config") .navigationBarItems(trailing: - ZStack { - - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") }) .onAppear { self.bleManager.context = context diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index 58be6096..6800a117 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -10,6 +10,7 @@ struct DeviceConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -165,15 +166,11 @@ struct DeviceConfig: View { dc.buzzerGpio = UInt32(buzzerGPIO) let adminMessageId = bleManager.saveDeviceConfig(config: dc, fromUser: node!.user!, toUser: node!.user!) - if adminMessageId > 0 { - // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false - - } else { - + goBack() } } } diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index 99e8df47..61b420c2 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -11,6 +11,7 @@ struct DisplayConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -115,9 +116,7 @@ struct DisplayConfig: View { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false - - } else { - + goBack() } } } diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index 6288fb67..e5584f3d 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -11,6 +11,7 @@ struct LoRaConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -83,16 +84,12 @@ struct LoRaConfig: View { lc.txEnabled = true let adminMessageId = bleManager.saveLoRaConfig(config: lc, fromUser: node!.user!, toUser: node!.user!) if adminMessageId > 0 { - // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false - - } else { - + goBack() } } - } message: { Text("After LoRa config saves the node will reboot.") } diff --git a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift index 13f8a109..6d83625a 100644 --- a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift @@ -10,6 +10,7 @@ struct CannedMessagesConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -251,6 +252,7 @@ struct CannedMessagesConfig: View { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false + goBack() } } if hasMessagesChanges { diff --git a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift index b1665c6e..5bceaec3 100644 --- a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift @@ -50,6 +50,7 @@ struct ExternalNotificationConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -148,8 +149,7 @@ struct ExternalNotificationConfig: View { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false - } else { - + goBack() } } } diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index 208f8d68..a8b135d9 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -10,6 +10,7 @@ struct MQTTConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @State private var isPresentingSaveConfirm: Bool = false @State var hasChanges: Bool = false @@ -103,8 +104,6 @@ struct MQTTConfig: View { } .keyboardType(.default) .scrollDismissesKeyboard(.interactively) - - HStack { Label("Password", systemImage: "wallet.pass") TextField("Server Password", text: $password) @@ -153,13 +152,11 @@ struct MQTTConfig: View { .controlSize(.large) .padding() .confirmationDialog( - "Are you sure?", isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { Button("Save MQTT Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") { - var mqtt = ModuleConfig.MQTTConfig() mqtt.enabled = self.enabled mqtt.address = self.address @@ -167,17 +164,12 @@ struct MQTTConfig: View { mqtt.password = self.password mqtt.encryptionEnabled = self.encryptionEnabled mqtt.jsonEnabled = self.jsonEnabled - let adminMessageId = bleManager.saveMQTTConfig(config: mqtt, fromUser: node!.user!, toUser: node!.user!) - if adminMessageId > 0 { - // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save - self.hasChanges = false - - } else { - + hasChanges = false + goBack() } } } diff --git a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift index 58c51e6d..56ea350f 100644 --- a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift @@ -48,6 +48,7 @@ struct RangeTestConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -89,7 +90,7 @@ struct RangeTestConfig: View { } label: { Label("Save", systemImage: "square.and.arrow.down") } - .disabled(bleManager.connectedPeripheral == nil || !hasChanges || !(node!.myInfo?.hasWifi ?? false)) + .disabled(bleManager.connectedPeripheral == nil || !hasChanges || !(node?.myInfo?.hasWifi ?? false)) .buttonStyle(.bordered) .buttonBorderShape(.capsule) .controlSize(.large) @@ -109,8 +110,7 @@ struct RangeTestConfig: View { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false - } else { - + goBack() } } } diff --git a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift index df362039..16eea485 100644 --- a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift @@ -10,6 +10,7 @@ struct SerialConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -142,9 +143,7 @@ struct SerialConfig: View { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false - - } else { - + goBack() } } } diff --git a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift index c8af1300..c944d987 100644 --- a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift @@ -70,6 +70,7 @@ struct TelemetryConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -148,8 +149,7 @@ struct TelemetryConfig: View { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false - } else { - + goBack() } } } diff --git a/Meshtastic/Views/Settings/Config/NetworkConfig.swift b/Meshtastic/Views/Settings/Config/NetworkConfig.swift index 8a488a97..3d3bafb9 100644 --- a/Meshtastic/Views/Settings/Config/NetworkConfig.swift +++ b/Meshtastic/Views/Settings/Config/NetworkConfig.swift @@ -11,6 +11,7 @@ struct NetworkConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -119,10 +120,8 @@ struct NetworkConfig: View { if adminMessageId > 0 { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save - self.hasChanges = false - - } else { - + hasChanges = false + goBack() } } } message: { diff --git a/Meshtastic/Views/Settings/Config/PositionConfig.swift b/Meshtastic/Views/Settings/Config/PositionConfig.swift index 71db978d..361df32d 100644 --- a/Meshtastic/Views/Settings/Config/PositionConfig.swift +++ b/Meshtastic/Views/Settings/Config/PositionConfig.swift @@ -27,6 +27,7 @@ struct PositionConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -234,6 +235,7 @@ struct PositionConfig: View { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false + goBack() } } } diff --git a/Meshtastic/Views/Settings/ShareChannels.swift b/Meshtastic/Views/Settings/ShareChannels.swift index 4862835c..d2f1328c 100644 --- a/Meshtastic/Views/Settings/ShareChannels.swift +++ b/Meshtastic/Views/Settings/ShareChannels.swift @@ -33,6 +33,7 @@ struct ShareChannels: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var dismiss @State var channelSet: ChannelSet = ChannelSet() @State var includeChannel0 = true @State var includeChannel1 = true @@ -48,8 +49,6 @@ struct ShareChannels: View { var qrCodeImage = QrCodeImage() var body: some View { - - // VStack { GeometryReader { bounds in let smallest = min(bounds.size.width, bounds.size.height) ScrollView { @@ -218,8 +217,6 @@ struct ShareChannels: View { } } } - - //} } .sheet(isPresented: $isPresentingHelp) { VStack { @@ -244,6 +241,18 @@ struct ShareChannels: View { .padding() .presentationDetents([.large]) .presentationDragIndicator(.automatic) + + #if targetEnvironment(macCatalyst) + Button { + dismiss() + } label: { + Label("Close", systemImage: "xmark") + } + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding() + #endif } .navigationTitle("Generate QR Code") .navigationBarTitleDisplayMode(.inline) @@ -263,7 +272,6 @@ struct ShareChannels: View { .onChange(of: includeChannel6) { includeCh6 in GenerateChannelSet() } .onChange(of: includeChannel7) { includeCh7 in GenerateChannelSet() } } - // } } func GenerateChannelSet() { channelSet = ChannelSet() diff --git a/Meshtastic/Views/Settings/UserConfig.swift b/Meshtastic/Views/Settings/UserConfig.swift index 87eefd16..c8fe32b4 100644 --- a/Meshtastic/Views/Settings/UserConfig.swift +++ b/Meshtastic/Views/Settings/UserConfig.swift @@ -10,6 +10,7 @@ struct UserConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? @@ -90,6 +91,7 @@ struct UserConfig: View { let adminMessageId = bleManager.saveUser(config: u, fromUser: node!.user!, toUser: node!.user!) if adminMessageId > 0 { hasChanges = false + goBack() } } } message: {