mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge pull request #132 from meshtastic/add_wifi_config
Add wifi config
This commit is contained in:
commit
8a4c519ddb
9 changed files with 361 additions and 17 deletions
|
|
@ -51,6 +51,7 @@
|
|||
DD86D4112881D16900BAEB7A /* WriteCsvFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD86D4102881D16900BAEB7A /* WriteCsvFile.swift */; };
|
||||
DD882F5D2772E4640005BF05 /* Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD882F5C2772E4640005BF05 /* Contacts.swift */; };
|
||||
DD8EBF43285058FA00426DCA /* DisplayConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8EBF42285058FA00426DCA /* DisplayConfig.swift */; };
|
||||
DD8ED9C52898D51F00B3B0AB /* WiFiConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8ED9C42898D51F00B3B0AB /* WiFiConfig.swift */; };
|
||||
DD90860C26F684AF00DC5189 /* BatteryIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860B26F684AF00DC5189 /* BatteryIcon.swift */; };
|
||||
DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860D26F69BAE00DC5189 /* NodeMap.swift */; };
|
||||
DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */; };
|
||||
|
|
@ -146,6 +147,7 @@
|
|||
DD882F5C2772E4640005BF05 /* Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contacts.swift; sourceTree = "<group>"; };
|
||||
DD8EBF42285058FA00426DCA /* DisplayConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayConfig.swift; sourceTree = "<group>"; };
|
||||
DD8ED9C328978D9D00B3B0AB /* MeshtasticDataModel v 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 5.xcdatamodel"; sourceTree = "<group>"; };
|
||||
DD8ED9C42898D51F00B3B0AB /* WiFiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WiFiConfig.swift; sourceTree = "<group>"; };
|
||||
DD90860A26F645B700DC5189 /* Meshtastic.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Meshtastic.entitlements; sourceTree = "<group>"; };
|
||||
DD90860B26F684AF00DC5189 /* BatteryIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryIcon.swift; sourceTree = "<group>"; };
|
||||
DD90860D26F69BAE00DC5189 /* NodeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMap.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -275,6 +277,7 @@
|
|||
DD8EBF42285058FA00426DCA /* DisplayConfig.swift */,
|
||||
DD2553562855B02500E55709 /* LoRaConfig.swift */,
|
||||
DD2553582855B52700E55709 /* PositionConfig.swift */,
|
||||
DD8ED9C42898D51F00B3B0AB /* WiFiConfig.swift */,
|
||||
DD61937B2863877A00E59241 /* Module */,
|
||||
);
|
||||
path = Config;
|
||||
|
|
@ -680,6 +683,7 @@
|
|||
C9483F6D2773017500998F6B /* MapView.swift in Sources */,
|
||||
DDAF8C5826ED07FD0058C060 /* mesh.pb.swift in Sources */,
|
||||
DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */,
|
||||
DD8ED9C52898D51F00B3B0AB /* WiFiConfig.swift in Sources */,
|
||||
DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */,
|
||||
DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */,
|
||||
DD86D4112881D16900BAEB7A /* WriteCsvFile.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -1112,6 +1112,35 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
return 0
|
||||
}
|
||||
|
||||
public func saveWiFiConfig(config: Config.WiFiConfig, fromUser: UserEntity, toUser: UserEntity, wantResponse: Bool) -> Int64 {
|
||||
|
||||
var adminPacket = AdminMessage()
|
||||
adminPacket.setConfig.wifi = config
|
||||
|
||||
var meshPacket: MeshPacket = MeshPacket()
|
||||
meshPacket.to = UInt32(connectedPeripheral.num)
|
||||
meshPacket.from = 0 //UInt32(connectedPeripheral.num)
|
||||
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
|
||||
meshPacket.priority = MeshPacket.Priority.reliable
|
||||
meshPacket.wantAck = wantResponse
|
||||
meshPacket.hopLimit = 0
|
||||
|
||||
var dataMessage = DataMessage()
|
||||
dataMessage.payload = try! adminPacket.serializedData()
|
||||
dataMessage.portnum = PortNum.adminApp
|
||||
|
||||
meshPacket.decoded = dataMessage
|
||||
|
||||
let messageDescription = "Saved WiFi Config for \(toUser.longName ?? "Unknown")"
|
||||
|
||||
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
|
||||
|
||||
return Int64(meshPacket.id)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
public func saveCannedMessageModuleConfig(config: ModuleConfig.CannedMessageConfig, fromUser: UserEntity, toUser: UserEntity, wantResponse: Bool) -> Int64 {
|
||||
|
||||
var adminPacket = AdminMessage()
|
||||
|
|
@ -1174,14 +1203,13 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
var adminPacket = AdminMessage()
|
||||
adminPacket.getCannedMessageModulePart1Request = true
|
||||
|
||||
//adminPacket.getOwnerRequest = true
|
||||
|
||||
var meshPacket: MeshPacket = MeshPacket()
|
||||
meshPacket.to = UInt32(connectedPeripheral.num)
|
||||
meshPacket.from = 0 //UInt32(connectedPeripheral.num)
|
||||
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
|
||||
meshPacket.priority = MeshPacket.Priority.reliable
|
||||
meshPacket.wantAck = wantResponse
|
||||
meshPacket.decoded.wantResponse = wantResponse
|
||||
|
||||
var dataMessage = DataMessage()
|
||||
dataMessage.payload = try! adminPacket.serializedData()
|
||||
|
|
|
|||
|
|
@ -257,6 +257,11 @@ func localConfig (config: Config, meshlogging: Bool, context:NSManagedObjectCont
|
|||
if (try! config.position.jsonString()) == "{}" {
|
||||
|
||||
isDefault = true
|
||||
if meshlogging { MeshLogger.log("🗺️ Default Position config received \(String(nodeNum))") }
|
||||
|
||||
} else {
|
||||
|
||||
if meshlogging { MeshLogger.log("🗺️ Custom Position config received \(String(nodeNum))") }
|
||||
}
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
|
|
@ -334,6 +339,87 @@ func localConfig (config: Config, meshlogging: Bool, context:NSManagedObjectCont
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
if config.payloadVariant == Config.OneOf_PayloadVariant.wifi(config.wifi) {
|
||||
|
||||
var isDefault = false
|
||||
|
||||
if (try! config.wifi.jsonString()) == "{}" {
|
||||
|
||||
isDefault = true
|
||||
if meshlogging { MeshLogger.log("📶 Default WiFi config received \(String(nodeNum))") }
|
||||
|
||||
} else {
|
||||
|
||||
if meshlogging { MeshLogger.log("📶 Custom WiFi config received \(String(nodeNum))") }
|
||||
}
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
|
||||
do {
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
|
||||
// Found a node, save WiFi Config
|
||||
if !fetchedNode.isEmpty {
|
||||
|
||||
if fetchedNode[0].wiFiConfig == nil {
|
||||
|
||||
let newWiFiConfig = WiFiConfigEntity(context: context)
|
||||
|
||||
if isDefault {
|
||||
|
||||
newWiFiConfig.ssid = ""
|
||||
newWiFiConfig.password = ""
|
||||
newWiFiConfig.apMode = false
|
||||
newWiFiConfig.apHidden = false
|
||||
|
||||
} else {
|
||||
|
||||
newWiFiConfig.ssid = config.wifi.ssid
|
||||
newWiFiConfig.password = config.wifi.psk
|
||||
newWiFiConfig.apMode = config.wifi.apMode
|
||||
newWiFiConfig.apHidden = config.wifi.apHidden
|
||||
}
|
||||
newWiFiConfig.num = fetchedNode[0].num
|
||||
fetchedNode[0].wiFiConfig = newWiFiConfig
|
||||
|
||||
} else {
|
||||
|
||||
if isDefault {
|
||||
|
||||
fetchedNode[0].wiFiConfig?.ssid = ""
|
||||
fetchedNode[0].wiFiConfig?.password = ""
|
||||
fetchedNode[0].wiFiConfig?.apMode = false
|
||||
fetchedNode[0].wiFiConfig?.apHidden = false
|
||||
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
try context.save()
|
||||
if meshlogging { MeshLogger.log("💾 Updated WiFi Config for node number: \(String(nodeNum))") }
|
||||
|
||||
} catch {
|
||||
|
||||
context.rollback()
|
||||
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Updating Core Data WifionfigEntity: \(nsError)")
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func moduleConfig (config: ModuleConfig, meshlogging: Bool, context:NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
||||
|
|
@ -425,7 +511,7 @@ func moduleConfig (config: ModuleConfig, meshlogging: Bool, context:NSManagedObj
|
|||
|
||||
try context.save()
|
||||
if meshlogging { MeshLogger.log("💾 Updated Canned Message Module Config for node number: \(String(nodeNum))") }
|
||||
print(try config.cannedMessage.jsonString())
|
||||
|
||||
|
||||
} catch {
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@
|
|||
<relationship name="telemetries" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TelemetryEntity" inverseName="nodeTelemetry" inverseEntity="TelemetryEntity"/>
|
||||
<relationship name="telemetryConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TelemetryConfigEntity" inverseName="telemetryConfigNode" inverseEntity="TelemetryConfigEntity"/>
|
||||
<relationship name="user" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="userNode" inverseEntity="UserEntity"/>
|
||||
<relationship name="wiFiConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="WiFiConfigEntity" inverseName="wiFiConfigNode" inverseEntity="WiFiConfigEntity"/>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="num"/>
|
||||
|
|
@ -190,6 +191,14 @@
|
|||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="((toUser.num == $FETCH_SOURCE.num) OR (fromUser.num == $FETCH_SOURCE.num)) AND isEmoji == false AND admin = false"/>
|
||||
</fetchedProperty>
|
||||
</entity>
|
||||
<entity name="WiFiConfigEntity" representedClassName="WiFiConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="apHidden" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="apMode" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="password" optional="YES" attributeType="String" minValueString="1" maxValueString="60"/>
|
||||
<attribute name="ssid" optional="YES" attributeType="String" minValueString="1" maxValueString="30"/>
|
||||
<relationship name="wiFiConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="wiFiConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="CannedMessageConfigEntity" positionX="45" positionY="144" width="128" height="209"/>
|
||||
<element name="DeviceConfigEntity" positionX="45" positionY="144" width="128" height="104"/>
|
||||
|
|
@ -198,7 +207,7 @@
|
|||
<element name="LoRaConfigEntity" positionX="45" positionY="144" width="128" height="119"/>
|
||||
<element name="MessageEntity" positionX="-36" positionY="63" width="128" height="230"/>
|
||||
<element name="MyInfoEntity" positionX="-18" positionY="81" width="128" height="209"/>
|
||||
<element name="NodeInfoEntity" positionX="-63" positionY="-18" width="128" height="299"/>
|
||||
<element name="NodeInfoEntity" positionX="-63" positionY="-18" width="128" height="314"/>
|
||||
<element name="PositionConfigEntity" positionX="63" positionY="162" width="128" height="149"/>
|
||||
<element name="PositionEntity" positionX="-54" positionY="54" width="128" height="119"/>
|
||||
<element name="RangeTestConfigEntity" positionX="72" positionY="171" width="128" height="104"/>
|
||||
|
|
@ -206,5 +215,6 @@
|
|||
<element name="TelemetryConfigEntity" positionX="72" positionY="171" width="128" height="134"/>
|
||||
<element name="TelemetryEntity" positionX="160" positionY="192" width="128" height="209"/>
|
||||
<element name="UserEntity" positionX="0" positionY="144" width="128" height="230"/>
|
||||
<element name="WiFiConfigEntity" positionX="45" positionY="144" width="128" height="119"/>
|
||||
</elements>
|
||||
</model>
|
||||
|
|
@ -22,7 +22,7 @@ struct Connect: View {
|
|||
@State var isPreferredRadio: Bool = false
|
||||
|
||||
@State var firmwareVersion = "0.0.0"
|
||||
@State var minimumVersion = "1.3.27"
|
||||
@State var minimumVersion = "1.3.28"
|
||||
@State var invalidVersion = false
|
||||
|
||||
|
||||
|
|
|
|||
204
Meshtastic/Views/Settings/Config/WiFiConfig.swift
Normal file
204
Meshtastic/Views/Settings/Config/WiFiConfig.swift
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
//
|
||||
// WiFiConfig.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Copyright (c) Garth Vander Houwen 8/1/2022
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct WiFiConfig: View {
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var initialLoad: Bool = true
|
||||
@State var hasChanges: Bool = false
|
||||
|
||||
@State var ssid = ""
|
||||
@State var password = ""
|
||||
|
||||
@State var apMode = false
|
||||
@State var apHidden = false
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack {
|
||||
|
||||
Text("Enabling WiFi will disable bluetooth, only one connection method works at a time. Saving these settings will disconnect your device from the app.")
|
||||
.font(.title3)
|
||||
.padding()
|
||||
|
||||
Form {
|
||||
|
||||
Section(header: Text("SSID & Password")) {
|
||||
|
||||
HStack {
|
||||
Label("SSID", systemImage: "wifi")
|
||||
TextField("SSID", text: $ssid)
|
||||
.foregroundColor(.gray)
|
||||
.onChange(of: ssid, perform: { value in
|
||||
|
||||
let totalBytes = ssid.utf8.count
|
||||
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 30 {
|
||||
|
||||
let firstNBytes = Data(ssid.utf8.prefix(30))
|
||||
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
|
||||
// Set the shortName back to the last place where it was the right size
|
||||
ssid = maxBytesString
|
||||
}
|
||||
}
|
||||
})
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
.disableAutocorrection(true)
|
||||
|
||||
HStack {
|
||||
Label("Password", systemImage: "wallet.pass")
|
||||
TextField("Password", text: $password)
|
||||
.foregroundColor(.gray)
|
||||
.onChange(of: password, perform: { value in
|
||||
|
||||
let totalBytes = password.utf8.count
|
||||
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 60 {
|
||||
|
||||
let firstNBytes = Data(ssid.utf8.prefix(60))
|
||||
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
|
||||
// Set the shortName back to the last place where it was the right size
|
||||
ssid = maxBytesString
|
||||
}
|
||||
}
|
||||
})
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
.disableAutocorrection(true)
|
||||
|
||||
}
|
||||
Section(header: Text("AP Settings")) {
|
||||
|
||||
Toggle(isOn: $apMode) {
|
||||
|
||||
Label("Soft AP Mode", systemImage: "wifi")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Text("If set the software access point mode will be activated.")
|
||||
.font(.caption)
|
||||
|
||||
Toggle(isOn: $apHidden) {
|
||||
|
||||
Label("Hidden AP", systemImage: "eye.slash")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Text("If set the SSID for the AP will be hidden.")
|
||||
.font(.caption)
|
||||
|
||||
}
|
||||
}
|
||||
.disabled(!(node != nil && node!.myInfo?.hasWifi ?? false))
|
||||
|
||||
Button {
|
||||
|
||||
isPresentingSaveConfirm = true
|
||||
|
||||
} label: {
|
||||
|
||||
Label("Save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
.disabled(bleManager.connectedPeripheral == nil || !hasChanges)
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.confirmationDialog(
|
||||
|
||||
"Are you sure?",
|
||||
isPresented: $isPresentingSaveConfirm
|
||||
) {
|
||||
Button("Save WiFI Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") {
|
||||
|
||||
var wifi = Config.WiFiConfig()
|
||||
wifi.ssid = self.ssid
|
||||
wifi.psk = self.password
|
||||
wifi.apMode = self.apMode
|
||||
wifi.apHidden = self.apHidden
|
||||
|
||||
let adminMessageId = bleManager.saveWiFiConfig(config: wifi, fromUser: node!.user!, toUser: node!.user!, wantResponse: true)
|
||||
|
||||
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 {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("WiFi Config")
|
||||
.navigationBarItems(trailing:
|
||||
|
||||
ZStack {
|
||||
|
||||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
|
||||
})
|
||||
.onAppear {
|
||||
|
||||
if self.initialLoad{
|
||||
|
||||
self.bleManager.context = context
|
||||
|
||||
self.ssid = node!.wiFiConfig?.ssid ?? ""
|
||||
self.password = node!.wiFiConfig?.password ?? ""
|
||||
self.apMode = (node!.wiFiConfig?.apMode ?? false)
|
||||
self.apHidden = (node!.wiFiConfig?.apHidden ?? false)
|
||||
|
||||
self.hasChanges = false
|
||||
self.initialLoad = false
|
||||
}
|
||||
}
|
||||
.onChange(of: ssid) { newSsid in
|
||||
|
||||
if node != nil && node!.wiFiConfig != nil {
|
||||
|
||||
if newSsid != node!.wiFiConfig!.ssid { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: password) { newPassword in
|
||||
|
||||
if node != nil && node!.wiFiConfig != nil {
|
||||
|
||||
if newPassword != node!.wiFiConfig!.password { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: apMode) { newApMode 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 }
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
}
|
||||
}
|
||||
|
|
@ -100,6 +100,17 @@ struct Settings: View {
|
|||
}
|
||||
.disabled(bleManager.connectedPeripheral == nil)
|
||||
|
||||
NavigationLink {
|
||||
WiFiConfig(node: nodes.first(where: { $0.num == connectedNodeNum }))
|
||||
} label: {
|
||||
|
||||
Image(systemName: "wifi")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
|
||||
Text("WiFi (ESP32 Only)")
|
||||
}
|
||||
.disabled(bleManager.connectedPeripheral == nil)
|
||||
|
||||
Text("Default settings values are prefered as they consume no bandwidth when sent over the mesh.")
|
||||
.font(.caption2)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
|
@ -193,8 +204,7 @@ struct Settings: View {
|
|||
|
||||
// Not Implemented:
|
||||
// Store Forward Config - Not Working, TBEAM Only
|
||||
// WiFi Config - Would break connection to device
|
||||
// MQTT Config - Part of WiFi
|
||||
// MQTT Config - Can do from WebUI once WiFi is enabled
|
||||
}
|
||||
.onAppear {
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ struct ShareChannel: View {
|
|||
)
|
||||
Spacer()
|
||||
Text("Channel Name (Long/Slow)").font(.title)
|
||||
Text(String(node!.myInfo!.maxChannels))
|
||||
Spacer()
|
||||
}
|
||||
.frame(width: bounds.size.width, height: bounds.size.height)
|
||||
|
|
|
|||
|
|
@ -48,6 +48,17 @@ struct UserConfig: View {
|
|||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
.keyboardType(.default)
|
||||
.disableAutocorrection(true)
|
||||
Text("Long name can be up to 36 bytes long.")
|
||||
.font(.caption)
|
||||
|
||||
HStack {
|
||||
Label("Short Name", systemImage: "circlebadge.fill")
|
||||
TextField("Long Name", text: $shortName)
|
||||
.foregroundColor(.gray)
|
||||
.onChange(of: shortName, perform: { value in
|
||||
|
||||
let totalBytes = shortName.utf8.count
|
||||
|
|
@ -66,16 +77,6 @@ struct UserConfig: View {
|
|||
})
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
.disableAutocorrection(true)
|
||||
Text("Long name can be up to 36 bytes long.")
|
||||
.font(.caption)
|
||||
|
||||
HStack {
|
||||
Label("Short Name", systemImage: "circlebadge.fill")
|
||||
TextField("Long Name", text: $shortName)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.asciiCapable)
|
||||
.disableAutocorrection(true)
|
||||
Text("The short name is used in maps and messaging and will be appended to the last 4 of the device MAC address to set the device's BLE Name. It can be up to 4 bytes long.")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue