diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 39ea2178..7380d000 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -339,10 +339,10 @@ children = ( DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */, DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */, + DD2160AE28C5552500C17253 /* MQTTConfig.swift */, DD41582928585C32009B0E59 /* RangeTestConfig.swift */, DD6193782863875F00E59241 /* SerialConfig.swift */, DD415827285859C4009B0E59 /* TelemetryConfig.swift */, - DD2160AE28C5552500C17253 /* MQTTConfig.swift */, ); path = Module; sourceTree = ""; diff --git a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift index 1516a5a9..57e2da92 100644 --- a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift +++ b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift @@ -33,89 +33,81 @@ struct BluetoothConfig: View { var body: some View { - VStack { - - Form { - - Section(header: Text("options")) { - - Toggle(isOn: $enabled) { - - Label("enabled", systemImage: "antenna.radiowaves.left.and.right") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - - - Picker("Pairing Mode", selection: $mode ) { - ForEach(BluetoothModes.allCases) { bm in - Text(bm.description) - } - } - .pickerStyle(DefaultPickerStyle()) - - if mode == 1 { - - HStack { - Label("Fixed PIN", systemImage: "wallet.pass") - TextField("Fixed PIN", text: $fixedPin) - .foregroundColor(.gray) - .onChange(of: fixedPin, perform: { value in - //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) + Form { + Section(header: Text("options")) { - Button { - isPresentingSaveConfirm = true - } label: { - Label("save", systemImage: "square.and.arrow.down") - } - .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 - goBack() + Toggle(isOn: $enabled) { + Label("enabled", systemImage: "antenna.radiowaves.left.and.right") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + Picker("bluetooth.pairingmode", selection: $mode ) { + ForEach(BluetoothModes.allCases) { bm in + Text(bm.description) + } + } + .pickerStyle(DefaultPickerStyle()) + + if mode == 1 { + HStack { + Label("bluetooth.mode.fixedpin", systemImage: "wallet.pass") + TextField("bluetooth.mode.fixedpin", text: $fixedPin) + .foregroundColor(.gray) + .onChange(of: fixedPin, perform: { value in + //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) } } - } message: { - Text("After bluetooth config saves the node will reboot.") } } + .disabled(bleManager.connectedPeripheral == nil) + + Button { + isPresentingSaveConfirm = true + } label: { + Label("save", systemImage: "square.and.arrow.down") + } + .disabled(bleManager.connectedPeripheral == nil || !hasChanges || shortPin) + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding() + .confirmationDialog( + "are.you.sure", + 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 + goBack() + } + } + } message: { + Text("config.save.confirm") + } .navigationTitle("bluetooth.config") .navigationBarItems(trailing: ZStack { diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index 1abc2cdf..7a06d1c2 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -152,7 +152,7 @@ struct DeviceConfig: View { .padding() .confirmationDialog( - "Are you sure you want to save?", + "are.you.sure", isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { @@ -175,18 +175,14 @@ struct DeviceConfig: View { } } message: { - - Text("After device config saves the node will reboot.") + Text("config.save.confirm") } } Spacer() } - .navigationTitle("device.config") .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") }) .onAppear { diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index 13b12138..dfda6988 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -27,110 +27,108 @@ struct DisplayConfig: View { var body: some View { - VStack { - - Form { - Section(header: Text("Device Screen")) { - - Picker("Screen on for", selection: $screenOnSeconds ) { - ForEach(ScreenOnIntervals.allCases) { soi in - Text(soi.description) - } + Form { + Section(header: Text("Device Screen")) { + + Picker("Screen on for", selection: $screenOnSeconds ) { + ForEach(ScreenOnIntervals.allCases) { soi in + Text(soi.description) } - .pickerStyle(DefaultPickerStyle()) - - Text("How long the screen remains on after the user button is pressed or messages are received.") - .font(.caption) - - Picker("Carousel Interval", selection: $screenCarouselInterval ) { - ForEach(ScreenCarouselIntervals.allCases) { sci in - Text(sci.description) - } - } - .pickerStyle(DefaultPickerStyle()) - Text("Automatically toggles to the next page on the screen like a carousel, based the specified interval.") - .font(.caption) - - Toggle(isOn: $compassNorthTop) { - - Label("Always point north", systemImage: "location.north.circle") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - Text("The compass heading on the screen outside of the circle will always point north.") - .font(.caption) - - Toggle(isOn: $flipScreen) { - - Label("Flip Screen", systemImage: "pip.swap") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - Text("Flip screen vertically") - .font(.caption) - Picker("OLED Type", selection: $oledType ) { - ForEach(OledTypes.allCases) { ot in - Text(ot.description) - } - } - .pickerStyle(DefaultPickerStyle()) - Text("Override automatic OLED screen detection.") - .font(.caption) - } - Section(header: Text("Format")) { - Picker("GPS Format", selection: $gpsFormat ) { - ForEach(GpsFormats.allCases) { lu in - Text(lu.description) - } + .pickerStyle(DefaultPickerStyle()) + + Text("How long the screen remains on after the user button is pressed or messages are received.") + .font(.caption) + + Picker("Carousel Interval", selection: $screenCarouselInterval ) { + ForEach(ScreenCarouselIntervals.allCases) { sci in + Text(sci.description) } - .pickerStyle(DefaultPickerStyle()) - - Text("The format used to display GPS coordinates on the device screen.") - .font(.caption) - .listRowSeparator(.visible) } + .pickerStyle(DefaultPickerStyle()) + Text("Automatically toggles to the next page on the screen like a carousel, based the specified interval.") + .font(.caption) + + Toggle(isOn: $compassNorthTop) { + + Label("Always point north", systemImage: "location.north.circle") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + Text("The compass heading on the screen outside of the circle will always point north.") + .font(.caption) + + Toggle(isOn: $flipScreen) { + + Label("Flip Screen", systemImage: "pip.swap") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + Text("Flip screen vertically") + .font(.caption) + Picker("OLED Type", selection: $oledType ) { + ForEach(OledTypes.allCases) { ot in + Text(ot.description) + } + } + .pickerStyle(DefaultPickerStyle()) + Text("Override automatic OLED screen detection.") + .font(.caption) + } - .disabled(bleManager.connectedPeripheral == nil) - - Button { - - isPresentingSaveConfirm = true + Section(header: Text("Format")) { + Picker("GPS Format", selection: $gpsFormat ) { + ForEach(GpsFormats.allCases) { lu in + Text(lu.description) + } + } + .pickerStyle(DefaultPickerStyle()) - } label: { - - Label("save", systemImage: "square.and.arrow.down") + Text("The format used to display GPS coordinates on the device screen.") + .font(.caption) + .listRowSeparator(.visible) } - .disabled(bleManager.connectedPeripheral == nil || !hasChanges) - .buttonStyle(.bordered) - .buttonBorderShape(.capsule) - .controlSize(.large) - .padding() - .confirmationDialog( - - "are.you.sure", - isPresented: $isPresentingSaveConfirm - ) { - Button("Save Display Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") { - - var dc = Config.DisplayConfig() - dc.gpsFormat = GpsFormats(rawValue: gpsFormat)!.protoEnumValue() - dc.screenOnSecs = UInt32(screenOnSeconds) - dc.autoScreenCarouselSecs = UInt32(screenCarouselInterval) - dc.compassNorthTop = compassNorthTop - dc.flipScreen = flipScreen - dc.oled = OledTypes(rawValue: oledType)!.protoEnumValue() - - let adminMessageId = bleManager.saveDisplayConfig(config: dc, fromUser: node!.user!, toUser: node!.user!) - - if adminMessageId > 0 { + } + .disabled(bleManager.connectedPeripheral == nil) + + Button { - // 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() - } + 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 Display Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") { + + var dc = Config.DisplayConfig() + dc.gpsFormat = GpsFormats(rawValue: gpsFormat)!.protoEnumValue() + dc.screenOnSecs = UInt32(screenOnSeconds) + dc.autoScreenCarouselSecs = UInt32(screenCarouselInterval) + dc.compassNorthTop = compassNorthTop + dc.flipScreen = flipScreen + dc.oled = OledTypes(rawValue: oledType)!.protoEnumValue() + + let adminMessageId = bleManager.saveDisplayConfig(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 + goBack() } } } + message: { + Text("config.save.confirm") + } .navigationTitle("display.config") .navigationBarItems(trailing: ZStack { diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index 6f5164a3..ed618aff 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -71,7 +71,7 @@ struct LoRaConfig: View { .controlSize(.large) .padding() .confirmationDialog( - "Are you sure you want to save?", + "are.you.sure", isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { @@ -91,7 +91,7 @@ struct LoRaConfig: View { } } } message: { - Text("After LoRa config saves the node will reboot.") + Text("config.save.confirm") } } .navigationTitle("lora.config") diff --git a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift index 65922a38..db08f329 100644 --- a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift @@ -269,6 +269,9 @@ struct CannedMessagesConfig: View { } } } + message: { + Text("config.save.confirm") + } .navigationTitle("canned.messages.config") .navigationBarItems(trailing: ZStack { diff --git a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift index c3a9b9fe..e1bb039e 100644 --- a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift @@ -213,6 +213,9 @@ struct ExternalNotificationConfig: View { } } } + message: { + Text("config.save.confirm") + } .navigationTitle("external.notification.config") .navigationBarItems(trailing: ZStack { diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index 89f472dc..aa91813d 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -22,158 +22,155 @@ struct MQTTConfig: View { @State var jsonEnabled = false var body: some View { - - VStack { - - Form { - Section(header: Text("options")) { + + Form { + Section(header: Text("options")) { + + Toggle(isOn: $enabled) { + + Label("enabled", systemImage: "dot.radiowaves.right") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + Toggle(isOn: $encryptionEnabled) { + + Label("Encryption Enabled", systemImage: "lock.icloud") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + Toggle(isOn: $jsonEnabled) { + + Label("JSON Enabled", systemImage: "ellipsis.curlybraces") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + } + Section(header: Text("Custom Server")) { + + HStack { + Label("Address", systemImage: "server.rack") + TextField("Server Address", text: $address) + .foregroundColor(.gray) + .autocapitalization(.none) + .disableAutocorrection(true) + .onChange(of: address, perform: { value in + + let totalBytes = address.utf8.count + + // Only mess with the value if it is too big + if totalBytes > 30 { + + let firstNBytes = Data(username.utf8.prefix(30)) - Toggle(isOn: $enabled) { - - Label("enabled", systemImage: "dot.radiowaves.right") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - - Toggle(isOn: $encryptionEnabled) { - - Label("Encryption Enabled", systemImage: "lock.icloud") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - - Toggle(isOn: $jsonEnabled) { - - Label("JSON Enabled", systemImage: "ellipsis.curlybraces") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - + if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { + + // Set the shortName back to the last place where it was the right size + address = maxBytesString + } + } + hasChanges = true + }) + .foregroundColor(.gray) + .keyboardType(.default) } - Section(header: Text("Custom Server")) { - - HStack { - Label("Address", systemImage: "server.rack") - TextField("Server Address", text: $address) - .foregroundColor(.gray) - .autocapitalization(.none) - .disableAutocorrection(true) - .onChange(of: address, perform: { value in - - let totalBytes = address.utf8.count - - // Only mess with the value if it is too big - if totalBytes > 30 { - - let firstNBytes = Data(username.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 - address = maxBytesString - } - } - hasChanges = true - }) - .foregroundColor(.gray) - .keyboardType(.default) - } - .autocorrectionDisabled() - - HStack { - Label("mqtt.username", systemImage: "person.text.rectangle") - TextField("mqtt.username", text: $username) - .foregroundColor(.gray) - .autocapitalization(.none) - .disableAutocorrection(true) - .onChange(of: username, perform: { value in - - let totalBytes = username.utf8.count - - // Only mess with the value if it is too big - if totalBytes > 62 { - - let firstNBytes = Data(username.utf8.prefix(62)) - - if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { - - // Set the shortName back to the last place where it was the right size - username = maxBytesString - } - } - hasChanges = true - }) - .foregroundColor(.gray) - } - .keyboardType(.default) - .scrollDismissesKeyboard(.interactively) - 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 > 62 { - - let firstNBytes = Data(password.utf8.prefix(62)) - - if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { - - // Set the shortName back to the last place where it was the right size - password = maxBytesString - } - } - hasChanges = true - }) - .foregroundColor(.gray) - } - .keyboardType(.default) - .scrollDismissesKeyboard(.interactively) - } - Text("WiFi or Ethernet must also be enabled for MQTT to work. You can set uplink and downlink for each channel.") - .font(.callout) - } - .scrollDismissesKeyboard(.interactively) - .disabled(!(node != nil)) - - Button { - - isPresentingSaveConfirm = true + .autocorrectionDisabled() - } label: { - - Label("save", systemImage: "square.and.arrow.down") + HStack { + Label("mqtt.username", systemImage: "person.text.rectangle") + TextField("mqtt.username", text: $username) + .foregroundColor(.gray) + .autocapitalization(.none) + .disableAutocorrection(true) + .onChange(of: username, perform: { value in + + let totalBytes = username.utf8.count + + // Only mess with the value if it is too big + if totalBytes > 62 { + + let firstNBytes = Data(username.utf8.prefix(62)) + + if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { + + // Set the shortName back to the last place where it was the right size + username = maxBytesString + } + } + hasChanges = true + }) + .foregroundColor(.gray) + } + .keyboardType(.default) + .scrollDismissesKeyboard(.interactively) + 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 > 62 { + + let firstNBytes = Data(password.utf8.prefix(62)) + + if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { + + // Set the shortName back to the last place where it was the right size + password = maxBytesString + } + } + hasChanges = true + }) + .foregroundColor(.gray) + } + .keyboardType(.default) + .scrollDismissesKeyboard(.interactively) } - .disabled(bleManager.connectedPeripheral == nil || !hasChanges) - .buttonStyle(.bordered) - .buttonBorderShape(.capsule) - .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 - mqtt.username = self.username - 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 - hasChanges = false - goBack() - } + Text("WiFi or Ethernet must also be enabled for MQTT to work. You can set uplink and downlink for each channel.") + .font(.callout) + } + .scrollDismissesKeyboard(.interactively) + .disabled(!(node != nil)) + + 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, + 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 + mqtt.username = self.username + 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 + hasChanges = false + goBack() } } } + message: { + Text("config.save.confirm") + } .navigationTitle("mqtt.config") .navigationBarItems(trailing: ZStack { diff --git a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift index 38ecae08..8e6a6438 100644 --- a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift @@ -114,6 +114,9 @@ struct RangeTestConfig: View { } } } + message: { + Text("config.save.confirm") + } .navigationTitle("range.test.config") .navigationBarItems(trailing: ZStack { diff --git a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift index 349373bd..d86fca71 100644 --- a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift @@ -147,7 +147,9 @@ struct SerialConfig: View { } } } - + message: { + Text("config.save.confirm") + } .navigationTitle("serial.config") .navigationBarItems(trailing: diff --git a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift index 0eeb1902..148b9981 100644 --- a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift @@ -153,7 +153,9 @@ struct TelemetryConfig: View { } } } - + message: { + Text("config.save.confirm") + } .navigationTitle("telemetry.config") .navigationBarItems(trailing: ZStack { diff --git a/Meshtastic/Views/Settings/Config/NetworkConfig.swift b/Meshtastic/Views/Settings/Config/NetworkConfig.swift index c71bfaa0..58c022f0 100644 --- a/Meshtastic/Views/Settings/Config/NetworkConfig.swift +++ b/Meshtastic/Views/Settings/Config/NetworkConfig.swift @@ -104,7 +104,7 @@ struct NetworkConfig: View { .controlSize(.large) .padding() .confirmationDialog( - "Are you sure you want to save?", + "are.you.sure", isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { @@ -125,7 +125,7 @@ struct NetworkConfig: View { } } } message: { - Text("After network config saves the node will reboot.") + Text("config.save.confirm") } } .navigationTitle("network.config") diff --git a/Meshtastic/Views/Settings/Config/PositionConfig.swift b/Meshtastic/Views/Settings/Config/PositionConfig.swift index e800a64f..6006109f 100644 --- a/Meshtastic/Views/Settings/Config/PositionConfig.swift +++ b/Meshtastic/Views/Settings/Config/PositionConfig.swift @@ -239,6 +239,9 @@ struct PositionConfig: View { } } } + message: { + Text("config.save.confirm") + } } .navigationTitle("position.config") .navigationBarItems(trailing: diff --git a/Meshtastic/Views/Settings/UserConfig.swift b/Meshtastic/Views/Settings/UserConfig.swift index 6380430b..f372499e 100644 --- a/Meshtastic/Views/Settings/UserConfig.swift +++ b/Meshtastic/Views/Settings/UserConfig.swift @@ -80,7 +80,7 @@ struct UserConfig: View { .controlSize(.large) .padding() .confirmationDialog( - "Are you sure you want to save?", + "are.you.sure", isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { @@ -95,7 +95,7 @@ struct UserConfig: View { } } } message: { - Text("After user config saves the node will reboot.") + Text("config.save.confirm") } } Spacer() diff --git a/de.lproj/Localizable.strings b/de.lproj/Localizable.strings index fa78bc25..06a62a0e 100644 --- a/de.lproj/Localizable.strings +++ b/de.lproj/Localizable.strings @@ -25,6 +25,7 @@ "bluetooth.mode.randompin"="Zufällige PIN"; "bluetooth.mode.fixedpin"="Feste PIN"; "bluetooth.mode.nopin"="Keine PIN (geht einfach)"; +"bluetooth.pairingmode"="Pairing Mode"; "bytes"="Bytes"; "cancel"="Abbrechen"; "canned.messages"="Canned Messages"; @@ -39,6 +40,7 @@ "channels"="Kanäle"; "clear.app.data"="App Daten löschen"; "close"="Close"; +"config.save.confirm"="After config values save the node will reboot."; "connected.radio"="Verbundenes Gerät"; "communicating"="Verbinde mit Gerät..."; "connected"="Derzeit verbunden"; diff --git a/en.lproj/Localizable.strings b/en.lproj/Localizable.strings index 1f312eee..db240f32 100644 --- a/en.lproj/Localizable.strings +++ b/en.lproj/Localizable.strings @@ -22,6 +22,7 @@ "bluetooth.mode.randompin"="Random PIN"; "bluetooth.mode.fixedpin"="Fixed PIN"; "bluetooth.mode.nopin"="No PIN (Just Works)"; +"bluetooth.pairingmode"="Pairing Mode"; "bytes"="Bytes"; "cancel"="Cancel"; "canned.messages"="Canned Messages"; @@ -36,6 +37,7 @@ "channels"="Channels"; "clear.app.data"="Clear App Data"; "close"="Close"; +"config.save.confirm"="After config values save the node will reboot."; "connected.radio"="Connected Radio"; "communicating"="Communicating with device. ."; "connected"="Currently Connected";