From af4ef58e1431060c831724067740a93790ad1aa3 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 6 Aug 2022 08:07:16 -0700 Subject: [PATCH 1/3] Support new wifi config, update firmware version modal, prevent connection of unsupported devices for real this time. --- Meshtastic.xcodeproj/project.pbxproj | 4 +- Meshtastic/Helpers/BLEManager.swift | 15 +- Meshtastic/Helpers/MeshPackets.swift | 12 +- Meshtastic/Meshtastic.entitlements | 2 +- .../Meshtastic.xcdatamodeld/.xccurrentversion | 2 +- .../contents | 221 ++++++++++++++++++ Meshtastic/Protobufs/config.pb.swift | 133 ++++++++--- Meshtastic/Views/Bluetooth/Connect.swift | 18 +- .../Views/Settings/Config/WiFiConfig.swift | 107 +++++---- 9 files changed, 403 insertions(+), 111 deletions(-) create mode 100644 Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 6.xcdatamodel/contents diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index d1afffe5..40df6cb7 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -150,6 +150,7 @@ DD8ED9C328978D9D00B3B0AB /* MeshtasticDataModel v 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 5.xcdatamodel"; sourceTree = ""; }; DD8ED9C42898D51F00B3B0AB /* WiFiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WiFiConfig.swift; sourceTree = ""; }; DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutingError.swift; sourceTree = ""; }; + DD8ED9C9289EA77E00B3B0AB /* MeshtasticDataModel v 6.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 6.xcdatamodel"; sourceTree = ""; }; DD90860A26F645B700DC5189 /* Meshtastic.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Meshtastic.entitlements; sourceTree = ""; }; DD90860B26F684AF00DC5189 /* BatteryIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryIcon.swift; sourceTree = ""; }; DD90860D26F69BAE00DC5189 /* NodeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMap.swift; sourceTree = ""; }; @@ -1097,13 +1098,14 @@ DD9D8F2D2764403B00080993 /* Meshtastic.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + DD8ED9C9289EA77E00B3B0AB /* MeshtasticDataModel v 6.xcdatamodel */, DD8ED9C328978D9D00B3B0AB /* MeshtasticDataModel v 5.xcdatamodel */, DD619373285CC7D600E59241 /* MeshtasticDataModel v 4.xcdatamodel */, DDB2CC6F27F3F0AC009C5FCC /* MeshtasticDataModel v 3.xcdatamodel */, DD45C77427BD4EF80011784F /* MeshtasticDataModel v2.xcdatamodel */, DD9D8F2E2764403B00080993 /* CoreDataSample.xcdatamodel */, ); - currentVersion = DD8ED9C328978D9D00B3B0AB /* MeshtasticDataModel v 5.xcdatamodel */; + currentVersion = DD8ED9C9289EA77E00B3B0AB /* MeshtasticDataModel v 6.xcdatamodel */; name = Meshtastic.xcdatamodeld; path = Meshtastic/Meshtastic.xcdatamodeld; sourceTree = ""; diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 636b0f35..35b8dd92 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -29,7 +29,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph @Published var connectedPeripheral: Peripheral! @Published var lastConnectionError: String - @Published var lastConnnectionVersion: String + @Published var connectedVersion: String @Published var isSwitchedOn: Bool = false @Published var isScanning: Bool = false @@ -77,7 +77,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph //self.meshLoggingEnabled = UserDefaults.standard.object(forKey: "meshActivityLog") as? Bool ?? false self.lastConnectionError = "" - self.lastConnnectionVersion = "0.0.0" + self.connectedVersion = "0.0.0" super.init() // let bleQueue: DispatchQueue = DispatchQueue(label: "CentralManager") centralManager = CBCentralManager(delegate: self, queue: nil) @@ -159,13 +159,15 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if meshLoggingEnabled { MeshLogger.log("✅ BLE Connecting: \(peripheral.name ?? "Unknown")") } stopScanning() + if self.connectedPeripheral != nil { if meshLoggingEnabled { MeshLogger.log("ℹ️ BLE Disconnecting from: \(self.connectedPeripheral.name) to connect to \(peripheral.name ?? "Unknown")") } self.disconnectPeripheral() } - + + self.connectedVersion = "0.0.0" self.centralManager?.connect(peripheral) // Use a timer to keep track of connecting peripherals, context to pass the radio name with the timer and the RunLoop to prevent @@ -460,15 +462,20 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph // MyInfo if decodedInfo.myInfo.isInitialized && decodedInfo.myInfo.myNodeNum > 0 { + + let lastDotIndex = decodedInfo.myInfo.firmwareVersion.lastIndex(of: ".") + var version = decodedInfo.myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: decodedInfo.myInfo.firmwareVersion))] nowKnown = true + connectedVersion = String(version) + let myInfo = myInfoPacket(myInfo: decodedInfo.myInfo, meshLogging: meshLoggingEnabled, context: context!) if myInfo != nil { self.connectedPeripheral.bitrate = myInfo!.bitrate self.connectedPeripheral.num = myInfo!.myNodeNum - lastConnnectionVersion = myInfo?.firmwareVersion ?? myInfo!.firmwareVersion ?? "Unknown" + self.connectedPeripheral.firmwareVersion = myInfo!.firmwareVersion ?? "Unknown" self.connectedPeripheral.name = myInfo!.bleName ?? "Unknown" self.connectedPeripheral.longName = myInfo!.bleName ?? "Unknown" diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 8157d990..38a3b7a6 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -377,15 +377,13 @@ func localConfig (config: Config, meshlogging: Bool, context:NSManagedObjectCont newWiFiConfig.ssid = "" newWiFiConfig.password = "" - newWiFiConfig.apMode = false - newWiFiConfig.apHidden = false + newWiFiConfig.mode = 0 } else { newWiFiConfig.ssid = config.wifi.ssid newWiFiConfig.password = config.wifi.psk - newWiFiConfig.apMode = config.wifi.apMode - newWiFiConfig.apHidden = config.wifi.apHidden + newWiFiConfig.mode = Int32(config.wifi.mode.rawValue) } newWiFiConfig.num = fetchedNode[0].num fetchedNode[0].wiFiConfig = newWiFiConfig @@ -396,15 +394,13 @@ func localConfig (config: Config, meshlogging: Bool, context:NSManagedObjectCont fetchedNode[0].wiFiConfig?.ssid = "" fetchedNode[0].wiFiConfig?.password = "" - fetchedNode[0].wiFiConfig?.apMode = false - fetchedNode[0].wiFiConfig?.apHidden = false + fetchedNode[0].wiFiConfig?.mode = 0 } else { fetchedNode[0].wiFiConfig?.ssid = config.wifi.ssid fetchedNode[0].wiFiConfig?.password = config.wifi.psk - fetchedNode[0].wiFiConfig?.apMode = config.wifi.apMode - fetchedNode[0].wiFiConfig?.apHidden = config.wifi.apHidden + fetchedNode[0].wiFiConfig?.mode = Int32(config.wifi.mode.rawValue) } } diff --git a/Meshtastic/Meshtastic.entitlements b/Meshtastic/Meshtastic.entitlements index 68669b4c..5c8b6ee4 100644 --- a/Meshtastic/Meshtastic.entitlements +++ b/Meshtastic/Meshtastic.entitlements @@ -4,7 +4,7 @@ com.apple.developer.associated-domains - applinks:meshtastic.org/E/* + applinks:meshtastic.org/e/* com.apple.security.app-sandbox diff --git a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion index 5664b468..319888a5 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion +++ b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - MeshtasticDataModel v 5.xcdatamodel + MeshtasticDataModel v 6.xcdatamodel diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 6.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 6.xcdatamodel/contents new file mode 100644 index 00000000..eca24535 --- /dev/null +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 6.xcdatamodel/contents @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meshtastic/Protobufs/config.pb.swift b/Meshtastic/Protobufs/config.pb.swift index ad46c586..7d003b01 100644 --- a/Meshtastic/Protobufs/config.pb.swift +++ b/Meshtastic/Protobufs/config.pb.swift @@ -509,6 +509,15 @@ struct Config { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. + /// + /// Enable WiFi (disables Bluetooth) + var enabled: Bool = false + + /// + /// If set, this node will try to join the specified wifi network and + /// acquire an address via DHCP + var mode: Config.WiFiConfig.WiFiMode = .client + /// /// If set, this node will try to join the specified wifi network and /// acquire an address via DHCP @@ -518,21 +527,48 @@ struct Config { /// If set, will be use to authenticate to the named wifi var psk: String = String() - /// - /// If set, the node will operate as an AP (and DHCP server), otherwise it - /// will be a station - var apMode: Bool = false - - /// - /// If set, the node AP will broadcast as a hidden SSID - var apHidden: Bool = false - - /// - /// If set, wifi is enabled. Previously done through setting ssid and psk - var enabled: Bool = false - var unknownFields = SwiftProtobuf.UnknownStorage() + enum WiFiMode: SwiftProtobuf.Enum { + typealias RawValue = Int + + /// + /// This mode is used to connect to an external WiFi network + case client // = 0 + + /// + /// In this mode the node will operate as an AP (and DHCP server) + case accessPoint // = 1 + + /// + /// If set, the node AP will broadcast as a hidden SSID + case accessPointHidden // = 2 + case UNRECOGNIZED(Int) + + init() { + self = .client + } + + init?(rawValue: Int) { + switch rawValue { + case 0: self = .client + case 1: self = .accessPoint + case 2: self = .accessPointHidden + default: self = .UNRECOGNIZED(rawValue) + } + } + + var rawValue: Int { + switch self { + case .client: return 0 + case .accessPoint: return 1 + case .accessPointHidden: return 2 + case .UNRECOGNIZED(let i): return i + } + } + + } + init() {} } @@ -557,6 +593,11 @@ struct Config { /// Potentially useful for devices without user buttons. var autoScreenCarouselSecs: UInt32 = 0 + /// + /// If this is set, the displayed compass will always point north. if unset, the old behaviour + /// (top of display is heading direction) is used. + var compassNorthTop: Bool = false + var unknownFields = SwiftProtobuf.UnknownStorage() /// @@ -920,6 +961,15 @@ extension Config.PowerConfig.ChargeCurrent: CaseIterable { ] } +extension Config.WiFiConfig.WiFiMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + static var allCases: [Config.WiFiConfig.WiFiMode] = [ + .client, + .accessPoint, + .accessPointHidden, + ] +} + extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. static var allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ @@ -976,6 +1026,7 @@ extension Config.PositionConfig.PositionFlags: @unchecked Sendable {} extension Config.PowerConfig: @unchecked Sendable {} extension Config.PowerConfig.ChargeCurrent: @unchecked Sendable {} extension Config.WiFiConfig: @unchecked Sendable {} +extension Config.WiFiConfig.WiFiMode: @unchecked Sendable {} extension Config.DisplayConfig: @unchecked Sendable {} extension Config.DisplayConfig.GpsCoordinateFormat: @unchecked Sendable {} extension Config.LoRaConfig: @unchecked Sendable {} @@ -1381,11 +1432,10 @@ extension Config.PowerConfig.ChargeCurrent: SwiftProtobuf._ProtoNameProviding { extension Config.WiFiConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = Config.protoMessageName + ".WiFiConfig" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "ssid"), - 2: .same(proto: "psk"), - 3: .standard(proto: "ap_mode"), - 4: .standard(proto: "ap_hidden"), - 5: .same(proto: "enabled"), + 1: .same(proto: "enabled"), + 2: .same(proto: "mode"), + 3: .same(proto: "ssid"), + 4: .same(proto: "psk"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -1394,52 +1444,56 @@ extension Config.WiFiConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.ssid) }() - case 2: try { try decoder.decodeSingularStringField(value: &self.psk) }() - case 3: try { try decoder.decodeSingularBoolField(value: &self.apMode) }() - case 4: try { try decoder.decodeSingularBoolField(value: &self.apHidden) }() - case 5: try { try decoder.decodeSingularBoolField(value: &self.enabled) }() + case 1: try { try decoder.decodeSingularBoolField(value: &self.enabled) }() + case 2: try { try decoder.decodeSingularEnumField(value: &self.mode) }() + case 3: try { try decoder.decodeSingularStringField(value: &self.ssid) }() + case 4: try { try decoder.decodeSingularStringField(value: &self.psk) }() default: break } } } func traverse(visitor: inout V) throws { + if self.enabled != false { + try visitor.visitSingularBoolField(value: self.enabled, fieldNumber: 1) + } + if self.mode != .client { + try visitor.visitSingularEnumField(value: self.mode, fieldNumber: 2) + } if !self.ssid.isEmpty { - try visitor.visitSingularStringField(value: self.ssid, fieldNumber: 1) + try visitor.visitSingularStringField(value: self.ssid, fieldNumber: 3) } if !self.psk.isEmpty { - try visitor.visitSingularStringField(value: self.psk, fieldNumber: 2) - } - if self.apMode != false { - try visitor.visitSingularBoolField(value: self.apMode, fieldNumber: 3) - } - if self.apHidden != false { - try visitor.visitSingularBoolField(value: self.apHidden, fieldNumber: 4) - } - if self.enabled != false { - try visitor.visitSingularBoolField(value: self.enabled, fieldNumber: 5) + try visitor.visitSingularStringField(value: self.psk, fieldNumber: 4) } try unknownFields.traverse(visitor: &visitor) } static func ==(lhs: Config.WiFiConfig, rhs: Config.WiFiConfig) -> Bool { + if lhs.enabled != rhs.enabled {return false} + if lhs.mode != rhs.mode {return false} if lhs.ssid != rhs.ssid {return false} if lhs.psk != rhs.psk {return false} - if lhs.apMode != rhs.apMode {return false} - if lhs.apHidden != rhs.apHidden {return false} - if lhs.enabled != rhs.enabled {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } +extension Config.WiFiConfig.WiFiMode: SwiftProtobuf._ProtoNameProviding { + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 0: .same(proto: "Client"), + 1: .same(proto: "AccessPoint"), + 2: .same(proto: "AccessPointHidden"), + ] +} + extension Config.DisplayConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = Config.protoMessageName + ".DisplayConfig" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "screen_on_secs"), 2: .standard(proto: "gps_format"), 3: .standard(proto: "auto_screen_carousel_secs"), + 4: .standard(proto: "compass_north_top"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -1451,6 +1505,7 @@ extension Config.DisplayConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp case 1: try { try decoder.decodeSingularUInt32Field(value: &self.screenOnSecs) }() case 2: try { try decoder.decodeSingularEnumField(value: &self.gpsFormat) }() case 3: try { try decoder.decodeSingularUInt32Field(value: &self.autoScreenCarouselSecs) }() + case 4: try { try decoder.decodeSingularBoolField(value: &self.compassNorthTop) }() default: break } } @@ -1466,6 +1521,9 @@ extension Config.DisplayConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp if self.autoScreenCarouselSecs != 0 { try visitor.visitSingularUInt32Field(value: self.autoScreenCarouselSecs, fieldNumber: 3) } + if self.compassNorthTop != false { + try visitor.visitSingularBoolField(value: self.compassNorthTop, fieldNumber: 4) + } try unknownFields.traverse(visitor: &visitor) } @@ -1473,6 +1531,7 @@ extension Config.DisplayConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp if lhs.screenOnSecs != rhs.screenOnSecs {return false} if lhs.gpsFormat != rhs.gpsFormat {return false} if lhs.autoScreenCarouselSecs != rhs.autoScreenCarouselSecs {return false} + if lhs.compassNorthTop != rhs.compassNorthTop {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 1e69925e..41161dc1 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -16,15 +16,12 @@ struct Connect: View { @EnvironmentObject var bleManager: BLEManager @EnvironmentObject var userSettings: UserSettings - @State private var showingVersionSheet = false - @State var initialLoad: Bool = true @State var isPreferredRadio: Bool = false @State var firmwareVersion = "0.0.0" - @State var minimumVersion = "1.3.30" + @State var minimumVersion = "1.3.36" @State var invalidVersion = false - var body: some View { @@ -267,23 +264,18 @@ struct Connect: View { InvalidVersion(errorText: "1.3 ALPHA PREVIEW this version of the app supports only version \(minimumVersion) and above. Your device has been disconnected.") } - - - .onChange(of: firmwareVersion) { iv in + + .onChange(of: (self.bleManager.connectedVersion)) { ic in - bleManager.disconnectPeripheral() - } - .onChange(of: self.bleManager.isConnected) { ic in - - firmwareVersion = bleManager.lastConnnectionVersion + firmwareVersion = self.bleManager.connectedVersion let supportedVersion = firmwareVersion == "0.0.0" || minimumVersion.compare(firmwareVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(firmwareVersion, options: .numeric) == .orderedSame invalidVersion = !supportedVersion if invalidVersion { + bleManager.disconnectPeripheral() } - } .onAppear(perform: { diff --git a/Meshtastic/Views/Settings/Config/WiFiConfig.swift b/Meshtastic/Views/Settings/Config/WiFiConfig.swift index 0e44b935..1da29f14 100644 --- a/Meshtastic/Views/Settings/Config/WiFiConfig.swift +++ b/Meshtastic/Views/Settings/Config/WiFiConfig.swift @@ -7,6 +7,40 @@ import SwiftUI +enum WiFiModes: Int, CaseIterable, Identifiable { + + case client = 0 + case accessPoint = 1 + case accessPointHidden = 2 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + case .client: + return "Client" + case .accessPoint: + return "Software Access Point" + case .accessPointHidden: + return "Software Access Point (Hidden)" + + } + } + } + func protoEnumValue() -> Config.WiFiConfig.WiFiMode { + + switch self { + + case .client: + return Config.WiFiConfig.WiFiMode.client + case .accessPoint: + return Config.WiFiConfig.WiFiMode.accessPoint + case .accessPointHidden: + return Config.WiFiConfig.WiFiMode.accessPointHidden + } + } +} + struct WiFiConfig: View { @Environment(\.managedObjectContext) var context @@ -19,12 +53,9 @@ struct WiFiConfig: View { @State var hasChanges: Bool = false @State var enabled = false - @State var ssid = "" @State var password = "" - - @State var apMode = false - @State var apHidden = false + @State var mode = 0 var body: some View { @@ -39,22 +70,35 @@ struct WiFiConfig: View { Toggle(isOn: $enabled) { - Label("Enable", systemImage: "wifi") + Label("Enabled", systemImage: "wifi") } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + Picker("Mode", selection: $mode ) { + ForEach(WiFiModes.allCases) { lu in + Text(lu.description) + } + } + .pickerStyle(DefaultPickerStyle()) + + } + Section(header: Text("SSID & Password")) { + HStack { Label("SSID", systemImage: "network") TextField("SSID", text: $ssid) .foregroundColor(.gray) + .autocapitalization(.none) + .disableAutocorrection(true) .onChange(of: ssid, perform: { value in let totalBytes = ssid.utf8.count // Only mess with the value if it is too big - if totalBytes > 30 { + if totalBytes > 32 { - let firstNBytes = Data(ssid.utf8.prefix(30)) + let firstNBytes = Data(ssid.utf8.prefix(32)) if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { @@ -66,20 +110,22 @@ struct WiFiConfig: View { .foregroundColor(.gray) } .keyboardType(.default) - .disableAutocorrection(true) + HStack { Label("Password", systemImage: "wallet.pass") TextField("Password", text: $password) .foregroundColor(.gray) + .autocapitalization(.none) + .disableAutocorrection(true) .onChange(of: password, perform: { value in let totalBytes = password.utf8.count // Only mess with the value if it is too big - if totalBytes > 60 { + if totalBytes > 63 { - let firstNBytes = Data(ssid.utf8.prefix(60)) + let firstNBytes = Data(ssid.utf8.prefix(63)) if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { @@ -91,28 +137,6 @@ struct WiFiConfig: View { .foregroundColor(.gray) } .keyboardType(.default) - .disableAutocorrection(true) - - } - Section(header: Text("Sofware Access Point")) { - - Text("WiFi uses client mode by default, if Software Access Point(AP) is on the SSID and password will be used to access the AP at meshtastic.local.") - .font(.caption) - - Toggle(isOn: $apMode) { - - Label("Soft AP Mode", systemImage: "externaldrive.fill.badge.wifi") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - - if apMode { - - Toggle(isOn: $apHidden) { - - Label("Hidden SSID", systemImage: "eye.slash") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - } } } .disabled(!(node != nil && node!.myInfo?.hasWifi ?? false)) @@ -141,8 +165,7 @@ struct WiFiConfig: View { wifi.enabled = self.enabled wifi.ssid = self.ssid wifi.psk = self.password - wifi.apMode = self.apMode - wifi.apHidden = self.apHidden + wifi.mode = WiFiModes(rawValue: self.mode)?.protoEnumValue() ?? WiFiModes.client.protoEnumValue() let adminMessageId = bleManager.saveWiFiConfig(config: wifi, fromUser: node!.user!, toUser: node!.user!, wantResponse: true) @@ -174,9 +197,8 @@ struct WiFiConfig: View { self.enabled = (node!.wiFiConfig?.enabled ?? false) self.ssid = node!.wiFiConfig?.ssid ?? "" self.password = node!.wiFiConfig?.password ?? "" - self.apMode = (node!.wiFiConfig?.apMode ?? false) - self.apHidden = (node!.wiFiConfig?.apHidden ?? false) - + self.mode = Int(node!.wiFiConfig?.mode ?? 0) + self.hasChanges = false self.initialLoad = false } @@ -202,18 +224,11 @@ struct WiFiConfig: View { if newPassword != node!.wiFiConfig!.password { hasChanges = true } } } - .onChange(of: apMode) { newApMode in + .onChange(of: mode) { newMode in if node != nil && node!.wiFiConfig != nil { - if newApMode != node!.wiFiConfig!.apMode { hasChanges = true } - } - } - .onChange(of: apHidden) { newApHidden in - - if node != nil && node!.wiFiConfig != nil { - - if newApHidden != node!.wiFiConfig!.apHidden { hasChanges = true } + if newMode != node!.wiFiConfig!.mode { hasChanges = true } } } .navigationViewStyle(StackNavigationViewStyle()) From 19b646dd73fa7df120f8a89cff16dcd968f38150 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 6 Aug 2022 12:57:05 -0700 Subject: [PATCH 2/3] Bump version required --- Meshtastic.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 40df6cb7..0b7571d5 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -893,7 +893,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.30; + MARKETING_VERSION = 1.3.32; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -925,7 +925,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.30; + MARKETING_VERSION = 1.3.32; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; From e44c3739deeb972f98049eec333d4503e9a4bbf5 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 6 Aug 2022 12:57:36 -0700 Subject: [PATCH 3/3] Fix required version on bluetooth connect view --- Meshtastic/Views/Bluetooth/Connect.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 41161dc1..5db1234b 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -20,7 +20,7 @@ struct Connect: View { @State var isPreferredRadio: Bool = false @State var firmwareVersion = "0.0.0" - @State var minimumVersion = "1.3.36" + @State var minimumVersion = "1.3.32" @State var invalidVersion = false var body: some View {