mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Seperate apps settings and data clearing, update logic for online nodes text
This commit is contained in:
parent
25f8e424ed
commit
d3a7de2f76
9 changed files with 159 additions and 60 deletions
|
|
@ -140,6 +140,16 @@
|
|||
},
|
||||
"%@%%" : {
|
||||
|
||||
},
|
||||
"%@%% %@%%" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "%1$@%% %2$@%%"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"%@°F" : {
|
||||
|
||||
|
|
@ -6712,6 +6722,9 @@
|
|||
},
|
||||
"Drag & Drop is the recommended way to update firmware for NRF devices. If your iPhone or iPad is USB-C it will work with your regular USB-C charging cable, for lightning devices you need the Apple Lightning to USB camera adaptor." : {
|
||||
|
||||
},
|
||||
"Dupe / Bad Packets: %d" : {
|
||||
|
||||
},
|
||||
"echo" : {
|
||||
"localizations" : {
|
||||
|
|
@ -16072,6 +16085,12 @@
|
|||
},
|
||||
"Override automatic OLED screen detection." : {
|
||||
|
||||
},
|
||||
"Packets Received: %d" : {
|
||||
|
||||
},
|
||||
"Packets Sent: %d" : {
|
||||
|
||||
},
|
||||
"password" : {
|
||||
"localizations" : {
|
||||
|
|
@ -17387,6 +17406,9 @@
|
|||
},
|
||||
"Requires that there be an accelerometer on your device." : {
|
||||
|
||||
},
|
||||
"Reset App Settings" : {
|
||||
|
||||
},
|
||||
"Reset NodeDB" : {
|
||||
|
||||
|
|
@ -22679,7 +22701,7 @@
|
|||
"Your Firmware is up to date" : {
|
||||
|
||||
},
|
||||
"Your MQTT Server must support TLS." : {
|
||||
"Your MQTT Server must support TLS. Not available via the public mqtt server." : {
|
||||
|
||||
},
|
||||
"Your position has been sent with a request for a response with their position. You will receive a notification when a position is returned." : {
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ extension NodeInfoEntity {
|
|||
return self.telemetries?.filtered(using: NSPredicate(format: "metricsType == 1")).lastObject as? TelemetryEntity
|
||||
}
|
||||
|
||||
var latestLocalStats: TelemetryEntity? {
|
||||
return self.telemetries?.filtered(using: NSPredicate(format: "metricsType == 6")).lastObject as? TelemetryEntity
|
||||
}
|
||||
// var latestLocalStats: TelemetryEntity? {
|
||||
// return self.telemetries?.filtered(using: NSPredicate(format: "metricsType == 6")).lastObject as? TelemetryEntity
|
||||
// }
|
||||
|
||||
var hasPositions: Bool {
|
||||
return positions?.count ?? 0 > 0
|
||||
|
|
|
|||
|
|
@ -52,38 +52,80 @@ struct Connect: View {
|
|||
if #available(iOS 17.0, macOS 14.0, *) {
|
||||
TipView(BluetoothConnectionTip(), arrowEdge: .bottom)
|
||||
}
|
||||
HStack {
|
||||
VStack(alignment: .center) {
|
||||
CircleText(text: node?.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node?.num ?? 0))), circleSize: 90)
|
||||
}
|
||||
.padding(.trailing)
|
||||
VStack(alignment: .leading) {
|
||||
if node != nil {
|
||||
Text(connectedPeripheral.longName).font(.title2)
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
VStack(alignment: .center) {
|
||||
CircleText(text: node?.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node?.num ?? 0))), circleSize: 90)
|
||||
.padding(.trailing, 5)
|
||||
if node?.latestDeviceMetrics != nil {
|
||||
BatteryCompact(batteryLevel: node?.latestDeviceMetrics?.batteryLevel ?? 0, font: .caption, iconFont: .callout, color: .accentColor)
|
||||
.padding(.trailing, 5)
|
||||
}
|
||||
}
|
||||
Text("ble.name").font(.callout)+Text(": \(bleManager.connectedPeripheral?.peripheral.name ?? "unknown".localized)")
|
||||
.font(.callout).foregroundColor(Color.gray)
|
||||
if node != nil {
|
||||
Text("firmware.version").font(.callout)+Text(": \(node?.metadata?.firmwareVersion ?? "unknown".localized)")
|
||||
.padding(.trailing)
|
||||
VStack(alignment: .leading) {
|
||||
if node != nil {
|
||||
Text(connectedPeripheral.longName).font(.title2)
|
||||
}
|
||||
Text("ble.name").font(.callout)+Text(": \(bleManager.connectedPeripheral?.peripheral.name ?? "unknown".localized)")
|
||||
.font(.callout).foregroundColor(Color.gray)
|
||||
}
|
||||
if bleManager.isSubscribed {
|
||||
Text("subscribed").font(.callout)
|
||||
.foregroundColor(.green)
|
||||
} else {
|
||||
|
||||
HStack {
|
||||
if #available(iOS 17.0, macOS 14.0, *) {
|
||||
Image(systemName: "square.stack.3d.down.forward")
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.symbolEffect(.variableColor.reversing.cumulative, options: .repeat(20).speed(3))
|
||||
if node != nil {
|
||||
Text("firmware.version").font(.callout)+Text(": \(node?.metadata?.firmwareVersion ?? "unknown".localized)")
|
||||
.font(.callout).foregroundColor(Color.gray)
|
||||
}
|
||||
if bleManager.isSubscribed {
|
||||
Text("subscribed").font(.callout)
|
||||
.foregroundColor(.green)
|
||||
} else {
|
||||
HStack {
|
||||
if #available(iOS 17.0, macOS 14.0, *) {
|
||||
Image(systemName: "square.stack.3d.down.forward")
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.symbolEffect(.variableColor.reversing.cumulative, options: .repeat(20).speed(3))
|
||||
.foregroundColor(.orange)
|
||||
}
|
||||
Text("communicating").font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
}
|
||||
Text("communicating").font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
}
|
||||
}
|
||||
}
|
||||
VStack {
|
||||
let localStats = node?.telemetries?.filtered(using: NSPredicate(format: "metricsType == 6")).lastObject as? TelemetryEntity
|
||||
if localStats != nil {
|
||||
Divider()
|
||||
if localStats?.numTotalNodes ?? 0 >= 100 {
|
||||
Text("\(String(format: "Connected: %d nodes online", localStats?.numOnlineNodes ?? 0))")
|
||||
.font(.callout)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize()
|
||||
} else {
|
||||
Text("\(String(format: "Connected: %d of %d nodes online", localStats?.numOnlineNodes ?? 0, localStats?.numTotalNodes ?? 0))")
|
||||
.font(.callout)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize()
|
||||
}
|
||||
Text("\(String(format: "Ch. Util: %.2f", localStats?.channelUtilization ?? 0))% \(String(format: "Airtime: %.2f", localStats?.airUtilTx ?? 0))%")
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
Text("Packets Sent: \(localStats?.numPacketsTx ?? 0)")
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
Text("Packets Received: \(localStats?.numPacketsRx ?? 0)")
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
Text("Dupe / Bad Packets: \(localStats?.numPacketsRxBad ?? 0)")
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize()
|
||||
}
|
||||
}
|
||||
}
|
||||
.font(.caption)
|
||||
.foregroundColor(Color.gray)
|
||||
|
|
|
|||
|
|
@ -98,9 +98,6 @@ struct ChannelMessageList: View {
|
|||
Text("\(ackErrorVal?.display ?? "Empty Ack Error")").fixedSize(horizontal: false, vertical: true)
|
||||
.foregroundStyle(ackErrorVal?.color ?? Color.red)
|
||||
.font(.caption2)
|
||||
} else {
|
||||
let messageDate = message.timestamp
|
||||
Text(" \(messageDate.formattedDate(format: MessageText.dateFormatString))").font(.caption2).foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,9 +76,11 @@ struct AppSettings: View {
|
|||
}
|
||||
clearCoreDataDatabase(context: context, includeRoutes: true)
|
||||
context.refreshAllObjects()
|
||||
UserDefaults.standard.reset()
|
||||
}
|
||||
}
|
||||
Button("Reset App Settings", systemImage: "clipboard") {
|
||||
UserDefaults.standard.reset()
|
||||
}
|
||||
}
|
||||
if totalDownloadedTileSize != "0MB" {
|
||||
Section(header: Text("Map Tile Data")) {
|
||||
|
|
|
|||
|
|
@ -98,7 +98,12 @@ struct Channels: View {
|
|||
preciseLocation = false
|
||||
positionsEnabled = false
|
||||
} else {
|
||||
if positionPrecision == 32 {
|
||||
if channelKey == "AQ==" {
|
||||
preciseLocation = false
|
||||
if positionPrecision < 10 || positionPrecision > 16 {
|
||||
positionPrecision = 13
|
||||
}
|
||||
} else if positionPrecision == 32 {
|
||||
preciseLocation = true
|
||||
positionsEnabled = true
|
||||
} else {
|
||||
|
|
@ -250,7 +255,7 @@ struct Channels: View {
|
|||
channelKey = key
|
||||
positionsEnabled = false
|
||||
preciseLocation = false
|
||||
positionPrecision = 0
|
||||
positionPrecision = 13
|
||||
uplink = false
|
||||
downlink = false
|
||||
hasChanges = true
|
||||
|
|
|
|||
|
|
@ -157,11 +157,20 @@ struct ChannelForm: View {
|
|||
if !preciseLocation {
|
||||
VStack(alignment: .leading) {
|
||||
Label("Approximate Location", systemImage: "location.slash.circle.fill")
|
||||
Slider(value: $positionPrecision, in: 10...19, step: 1) {
|
||||
} minimumValueLabel: {
|
||||
Image(systemName: "minus")
|
||||
} maximumValueLabel: {
|
||||
Image(systemName: "plus")
|
||||
if channelKeySize == -1 {
|
||||
Slider(value: $positionPrecision, in: 10...16, step: 1) {
|
||||
} minimumValueLabel: {
|
||||
Image(systemName: "minus")
|
||||
} maximumValueLabel: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
} else {
|
||||
Slider(value: $positionPrecision, in: 10...19, step: 1) {
|
||||
} minimumValueLabel: {
|
||||
Image(systemName: "minus")
|
||||
} maximumValueLabel: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
}
|
||||
Text(PositionPrecision(rawValue: Int(positionPrecision))?.description ?? "")
|
||||
.foregroundColor(.gray)
|
||||
|
|
@ -199,6 +208,11 @@ struct ChannelForm: View {
|
|||
.onChange(of: channelKey) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKeySize) { _ in
|
||||
if channelKeySize == -1 {
|
||||
preciseLocation = false
|
||||
}
|
||||
}
|
||||
.onChange(of: channelRole) { _ in
|
||||
hasChanges = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ struct MQTTConfig: View {
|
|||
@State var password = ""
|
||||
@State var encryptionEnabled = true
|
||||
@State var jsonEnabled = false
|
||||
@State var tlsEnabled = true
|
||||
@State var tlsEnabled = false
|
||||
@State var root = "msh"
|
||||
@State var selectedTopic = ""
|
||||
@State var mqttConnected: Bool = false
|
||||
|
|
@ -234,7 +234,7 @@ struct MQTTConfig: View {
|
|||
.listRowSeparator(/*@START_MENU_TOKEN@*/.visible/*@END_MENU_TOKEN@*/)
|
||||
Toggle(isOn: $tlsEnabled) {
|
||||
Label("TLS Enabled", systemImage: "checkmark.shield.fill")
|
||||
Text("Your MQTT Server must support TLS.")
|
||||
Text("Your MQTT Server must support TLS. Not available via the public mqtt server.")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
}
|
||||
|
|
@ -288,9 +288,6 @@ struct MQTTConfig: View {
|
|||
jsonEnabled = false
|
||||
}
|
||||
if newProxyToClientEnabled != node?.mqttConfig?.proxyToClientEnabled { hasChanges = true }
|
||||
if newProxyToClientEnabled {
|
||||
jsonEnabled = false
|
||||
}
|
||||
}
|
||||
.onChange(of: address) { newAddress in
|
||||
if node != nil && node?.mqttConfig != nil {
|
||||
|
|
@ -324,8 +321,12 @@ struct MQTTConfig: View {
|
|||
}
|
||||
if newJsonEnabled != node?.mqttConfig?.jsonEnabled { hasChanges = true }
|
||||
}
|
||||
.onChange(of: tlsEnabled) {
|
||||
if $0 != node?.mqttConfig?.tlsEnabled { hasChanges = true }
|
||||
.onChange(of: tlsEnabled) { newTlsEnabled in
|
||||
if address.lowercased() == "mqtt.meshtastic.org" {
|
||||
tlsEnabled = false
|
||||
} else {
|
||||
if newTlsEnabled != node?.mqttConfig?.tlsEnabled { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: mqttConnected) { newMqttConnected in
|
||||
if newMqttConnected == false {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ struct WidgetsLiveActivity: Widget {
|
|||
nodesOnline: context.state.nodesOnline,
|
||||
totalNodes: context.state.totalNodes,
|
||||
timerRange: context.state.timerRange)
|
||||
.widgetURL(URL(string: "meshtastic:///node/\(context.attributes.name)"))
|
||||
.widgetURL(URL(string: "meshtastic:///bluetooth"))
|
||||
|
||||
} dynamicIsland: { context in
|
||||
DynamicIsland {
|
||||
|
|
@ -38,10 +38,17 @@ struct WidgetsLiveActivity: Widget {
|
|||
.fixedSize()
|
||||
Spacer()
|
||||
}
|
||||
Text("\(context.state.nodesOnline) nodes online")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize()
|
||||
if context.state.nodesOnline >= 100 {
|
||||
Text("100+ online")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize()
|
||||
} else {
|
||||
Text("\(context.state.nodesOnline) of \(context.state.totalNodes) online")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize()
|
||||
}
|
||||
Text("\(String(format: "Ch. Util: %.2f", context.state.channelUtilization))%")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
|
|
@ -74,7 +81,7 @@ struct WidgetsLiveActivity: Widget {
|
|||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize()
|
||||
Text("Dupe / Bad: \(context.state.badReceivedPackets)")
|
||||
Text("Dupe / Bad \(context.state.badReceivedPackets)")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.fixedSize()
|
||||
|
|
@ -108,7 +115,7 @@ struct WidgetsLiveActivity: Widget {
|
|||
.contentMargins(.trailing, 32, for: .expanded)
|
||||
.contentMargins([.leading, .top, .bottom], 6, for: .compactLeading)
|
||||
.contentMargins(.all, 6, for: .minimal)
|
||||
.widgetURL(URL(string: "meshtastic:///node/\(context.attributes.name)"))
|
||||
.widgetURL(URL(string: "meshtastic:///bluetooth"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -214,12 +221,21 @@ struct NodeInfoView: View {
|
|||
.foregroundStyle(.secondary)
|
||||
.opacity(isLuminanceReduced ? 0.8 : 1.0)
|
||||
.fixedSize()
|
||||
Text("\(String(format: "Connected: %d nodes online", nodesOnline, totalNodes))")
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
.opacity(isLuminanceReduced ? 0.8 : 1.0)
|
||||
.fixedSize()
|
||||
if totalNodes >= 100 {
|
||||
Text("\(String(format: "Connected: %d nodes online", nodesOnline))")
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
.opacity(isLuminanceReduced ? 0.8 : 1.0)
|
||||
.fixedSize()
|
||||
} else {
|
||||
Text("\(String(format: "Connected: %d of %d nodes online", nodesOnline, totalNodes))")
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.secondary)
|
||||
.opacity(isLuminanceReduced ? 0.8 : 1.0)
|
||||
.fixedSize()
|
||||
}
|
||||
let now = Date()
|
||||
Text("Last Heard: \(now.formatted())")
|
||||
.font(.caption)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue