mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge pull request #806 from meshtastic/devicemetrics-log
Switch device metrics to tables
This commit is contained in:
commit
14a2eacf8b
10 changed files with 136 additions and 151 deletions
|
|
@ -191,9 +191,6 @@
|
|||
},
|
||||
"8" : {
|
||||
|
||||
},
|
||||
"10% Airtime" : {
|
||||
|
||||
},
|
||||
"25" : {
|
||||
|
||||
|
|
@ -679,7 +676,7 @@
|
|||
"Airtime" : {
|
||||
|
||||
},
|
||||
"AirTm" : {
|
||||
"Airtime %@%%" : {
|
||||
|
||||
},
|
||||
"Alert" : {
|
||||
|
|
@ -1427,9 +1424,6 @@
|
|||
},
|
||||
"Barometric Pressure" : {
|
||||
|
||||
},
|
||||
"Batt" : {
|
||||
|
||||
},
|
||||
"Battery Level %" : {
|
||||
|
||||
|
|
@ -2791,6 +2785,9 @@
|
|||
},
|
||||
"Channel Role" : {
|
||||
|
||||
},
|
||||
"Channel Utilization %@%% " : {
|
||||
|
||||
},
|
||||
"channel.role.disabled" : {
|
||||
"extractionState" : "migrated",
|
||||
|
|
@ -3090,9 +3087,6 @@
|
|||
},
|
||||
"CHG" : {
|
||||
|
||||
},
|
||||
"ChUtil" : {
|
||||
|
||||
},
|
||||
"Clear" : {
|
||||
|
||||
|
|
@ -22291,9 +22285,6 @@
|
|||
},
|
||||
"Via Mqtt" : {
|
||||
|
||||
},
|
||||
"Volt" : {
|
||||
|
||||
},
|
||||
"voltage" : {
|
||||
"localizations" : {
|
||||
|
|
@ -22352,6 +22343,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Volts %@ " : {
|
||||
|
||||
},
|
||||
"waiting" : {
|
||||
"localizations" : {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
DD3501892852FC3B000FC853 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3501882852FC3B000FC853 /* Settings.swift */; };
|
||||
DD354FD92BD96A0B0061A25F /* IAQScale.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD354FD82BD96A0B0061A25F /* IAQScale.swift */; };
|
||||
DD3619152B1EF9F900C41C8C /* LocationsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3619142B1EF9F900C41C8C /* LocationsHandler.swift */; };
|
||||
DD3CC24C2C498D6C001BD3A2 /* BatteryCompact.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC24B2C498D6C001BD3A2 /* BatteryCompact.swift */; };
|
||||
DD3CC6B528E33FD100FA9159 /* ShareChannels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6B428E33FD100FA9159 /* ShareChannels.swift */; };
|
||||
DD3CC6BC28E366DF00FA9159 /* Meshtastic.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */; };
|
||||
DD3CC6BE28E4CD9800FA9159 /* BatteryGauge.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */; };
|
||||
|
|
@ -248,12 +249,12 @@
|
|||
2519268F2C3CB44900249DF5 /* ClientHistoryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientHistoryButton.swift; sourceTree = "<group>"; };
|
||||
251926912C3CB52300249DF5 /* DeleteNodeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteNodeButton.swift; sourceTree = "<group>"; };
|
||||
25AECD4E2C2F723200862C8E /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
|
||||
25C49D8F2C471AEA0024FBD1 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
25F5D5BD2C3F6D87008036E3 /* NavigationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationState.swift; sourceTree = "<group>"; };
|
||||
25F5D5BF2C3F6DA6008036E3 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = "<group>"; };
|
||||
25F5D5C12C3F6E4B008036E3 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
|
||||
25F5D5C72C4375A8008036E3 /* MeshtasticTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeshtasticTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
25F5D5D02C4375DF008036E3 /* RouterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterTests.swift; sourceTree = "<group>"; };
|
||||
25C49D8F2C471AEA0024FBD1 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
6D825E612C34786C008DBEE4 /* CommonRegex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonRegex.swift; sourceTree = "<group>"; };
|
||||
6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticAppDelegate.swift; sourceTree = "<group>"; };
|
||||
6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectionSensorLog.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -307,6 +308,7 @@
|
|||
DD3619132B1EE20700C41C8C /* MeshtasticDataModelV21.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV21.xcdatamodel; sourceTree = "<group>"; };
|
||||
DD3619142B1EF9F900C41C8C /* LocationsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsHandler.swift; sourceTree = "<group>"; };
|
||||
DD398EBD2B93F640002B4C51 /* MeshtasticDataModelV 29.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 29.xcdatamodel"; sourceTree = "<group>"; };
|
||||
DD3CC24B2C498D6C001BD3A2 /* BatteryCompact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryCompact.swift; sourceTree = "<group>"; };
|
||||
DD3CC6B428E33FD100FA9159 /* ShareChannels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareChannels.swift; sourceTree = "<group>"; };
|
||||
DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModel.xcdatamodel; sourceTree = "<group>"; };
|
||||
DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryGauge.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -882,6 +884,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */,
|
||||
DD3CC24B2C498D6C001BD3A2 /* BatteryCompact.swift */,
|
||||
DDB75A222A13CDA9006ED576 /* BatteryLevelCompact.swift */,
|
||||
DD457187293C7E63000C49FB /* BLESignalStrengthIndicator.swift */,
|
||||
DD47E3D526F17ED900029299 /* CircleText.swift */,
|
||||
|
|
@ -1320,6 +1323,7 @@
|
|||
DDB75A112A059258006ED576 /* Url.swift in Sources */,
|
||||
DDAD49ED2AFB39DC00B4425D /* MeshMap.swift in Sources */,
|
||||
DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */,
|
||||
DD3CC24C2C498D6C001BD3A2 /* BatteryCompact.swift in Sources */,
|
||||
DD1B8F402B35E2F10022AABC /* GPSStatus.swift in Sources */,
|
||||
DD8ED9C52898D51F00B3B0AB /* NetworkConfig.swift in Sources */,
|
||||
DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -1061,7 +1061,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
Logger.data.error("💥 Send message failure \(self.connectedPeripheral.num.toHex(), privacy: .public) to \(toUserNum.toHex(), privacy: .public)")
|
||||
}
|
||||
}
|
||||
return success
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
}
|
||||
if fetchedNode[0].user == nil {
|
||||
let newUser = createUser(num: Int64(truncatingIfNeeded: packet.from), context: context)
|
||||
fetchedNode[0].user! = newUser
|
||||
fetchedNode[0].user? = newUser
|
||||
|
||||
}
|
||||
do {
|
||||
|
|
|
|||
68
Meshtastic/Views/Helpers/BatteryCompact.swift
Normal file
68
Meshtastic/Views/Helpers/BatteryCompact.swift
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// BatteryCompact.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Created by Garth Vander Houwen on 7/18/24.
|
||||
//
|
||||
import SwiftUI
|
||||
|
||||
struct BatteryCompact: View {
|
||||
@State var batteryLevel: Int32
|
||||
var font: Font
|
||||
var iconFont: Font
|
||||
var color: Color
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center, spacing: 0) {
|
||||
if batteryLevel == 100 {
|
||||
Image(systemName: "battery.100.bolt")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
} else if batteryLevel < 100 && batteryLevel > 74 {
|
||||
Image(systemName: "battery.75")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
} else if batteryLevel < 75 && batteryLevel > 49 {
|
||||
Image(systemName: "battery.50")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
} else if batteryLevel < 50 && batteryLevel > 14 {
|
||||
Image(systemName: "battery.25")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
} else if batteryLevel < 15 && batteryLevel > 0 {
|
||||
Image(systemName: "battery.0")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
} else if batteryLevel == 0 {
|
||||
Image(systemName: "battery.0")
|
||||
.font(iconFont)
|
||||
.foregroundColor(.red)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
} else if batteryLevel > 100 {
|
||||
Image(systemName: "powerplug")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
}
|
||||
if batteryLevel > 100 {
|
||||
Text("PWD")
|
||||
.foregroundStyle(.secondary)
|
||||
.font(font)
|
||||
} else if batteryLevel == 100 {
|
||||
Text("CHG")
|
||||
.foregroundStyle(.secondary)
|
||||
.font(font)
|
||||
} else {
|
||||
Text("\(batteryLevel)%")
|
||||
.foregroundStyle(.secondary)
|
||||
.font(font)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,61 +19,7 @@ struct BatteryLevelCompact: View {
|
|||
let mostRecent = deviceMetrics?.lastObject as? TelemetryEntity
|
||||
let batteryLevel = mostRecent?.batteryLevel ?? 0
|
||||
if deviceMetrics?.count ?? 0 > 0 {
|
||||
HStack(alignment: .center, spacing: 0) {
|
||||
if batteryLevel == 100 {
|
||||
Image(systemName: "battery.100.bolt")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
} else if batteryLevel < 100 && batteryLevel > 74 {
|
||||
|
||||
Image(systemName: "battery.75")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
} else if batteryLevel < 75 && batteryLevel > 49 {
|
||||
|
||||
Image(systemName: "battery.50")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
} else if batteryLevel < 50 && batteryLevel > 14 {
|
||||
|
||||
Image(systemName: "battery.25")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
} else if batteryLevel < 15 && batteryLevel > 0 {
|
||||
|
||||
Image(systemName: "battery.0")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
} else if batteryLevel == 0 {
|
||||
Image(systemName: "battery.0")
|
||||
.font(iconFont)
|
||||
.foregroundColor(.red)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
} else if batteryLevel > 100 {
|
||||
Image(systemName: "powerplug")
|
||||
.font(iconFont)
|
||||
.foregroundColor(color)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
if batteryLevel > 100 {
|
||||
Text("PWD")
|
||||
.foregroundStyle(.gray)
|
||||
.font(font)
|
||||
} else if batteryLevel == 100 {
|
||||
Text("CHG")
|
||||
.foregroundStyle(.gray)
|
||||
.font(font)
|
||||
} else {
|
||||
Text("\(batteryLevel)%")
|
||||
.foregroundStyle(.gray)
|
||||
.font(font)
|
||||
}
|
||||
}
|
||||
BatteryCompact(batteryLevel: batteryLevel, font: font, iconFont: iconFont, color: color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ struct MQTTIcon: View {
|
|||
// the last one defaults to just showing up/down if it isn't specified b/c on the mqtt config screen, there's no information about uplink/downlink and no good alternative icon
|
||||
Image(systemName: uplink && downlink ? "arrow.up.arrow.down.circle.fill" : uplink ? "arrow.up.circle.fill" : downlink ? "arrow.down.circle.fill" : "arrow.up.arrow.down.circle.fill")
|
||||
.imageScale(.large)
|
||||
.foregroundColor(connected ? .green : .gray)
|
||||
.foregroundColor(connected ? .green : .secondary)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}.popover(isPresented: self.$isPopoverOpen, arrowEdge: .bottom, content: {
|
||||
VStack(spacing: 0.5) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ struct DeviceMetricsLog: View {
|
|||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
|
||||
|
||||
@State private var isPresentingClearLogConfirm: Bool = false
|
||||
@State var isExporting = false
|
||||
|
|
@ -21,6 +22,8 @@ struct DeviceMetricsLog: View {
|
|||
@State private var airtimeChartColor: Color = .yellow
|
||||
@State private var channelUtilizationChartColor: Color = .green
|
||||
@ObservedObject var node: NodeInfoEntity
|
||||
@State private var sortOrder = [KeyPathComparator(\TelemetryEntity.time, order: .reverse)]
|
||||
@State private var selection: TelemetryEntity.ID?
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
|
|
@ -32,7 +35,6 @@ struct DeviceMetricsLog: View {
|
|||
.sorted { $0.time! < $1.time! }
|
||||
if chartData.count > 0 {
|
||||
GroupBox(label: Label("\(deviceMetrics.count) Readings Total", systemImage: "chart.xyaxis.line")) {
|
||||
|
||||
Chart {
|
||||
ForEach(chartData, id: \.self) { point in
|
||||
Plot {
|
||||
|
|
@ -57,14 +59,9 @@ struct DeviceMetricsLog: View {
|
|||
.accessibilityValue("X: \(point.time!), Y: \(point.channelUtilization)")
|
||||
.foregroundStyle(channelUtilizationChartColor)
|
||||
|
||||
RuleMark(y: .value("10% Airtime", 10))
|
||||
.lineStyle(StrokeStyle(lineWidth: 1, dash: [5, 10]))
|
||||
.foregroundStyle(.yellow)
|
||||
|
||||
RuleMark(y: .value("Network Status Orange", 25))
|
||||
.lineStyle(StrokeStyle(lineWidth: 1, dash: [5, 10]))
|
||||
.foregroundStyle(.orange)
|
||||
|
||||
RuleMark(y: .value("Network Status Red", 50))
|
||||
.lineStyle(StrokeStyle(lineWidth: 1, dash: [5, 10]))
|
||||
.foregroundStyle(.red)
|
||||
|
|
@ -87,20 +84,46 @@ struct DeviceMetricsLog: View {
|
|||
.chartXAxis(.automatic)
|
||||
.chartYScale(domain: 0...100)
|
||||
.chartForegroundStyleScale([
|
||||
"Battery Level": batteryChartColor,
|
||||
idiom == .phone ? "Battery" : "Battery Level": batteryChartColor,
|
||||
"Channel Utilization": channelUtilizationChartColor,
|
||||
"Airtime": airtimeChartColor
|
||||
])
|
||||
.chartLegend(position: .automatic, alignment: .bottom)
|
||||
}
|
||||
.frame(minHeight: 250)
|
||||
.frame(minHeight: 240)
|
||||
}
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMdjmma", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "M/d/YY j:mma").replacingOccurrences(of: ",", with: "")
|
||||
if UIScreen.main.bounds.size.width > 768 && (UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac) {
|
||||
// Add a table for mac and ipad
|
||||
// Table(Array(deviceMetrics),id: \.self) {
|
||||
Table(deviceMetrics) {
|
||||
if idiom == .phone {
|
||||
/// Single Cell Compact display for phones
|
||||
Table(deviceMetrics, selection: $selection, sortOrder: $sortOrder) {
|
||||
TableColumn("battery.level") { dm in
|
||||
HStack {
|
||||
Text(dm.time?.formattedDate(format: dateFormatString) ?? "unknown.age".localized)
|
||||
.font(.caption)
|
||||
.fontWeight(.semibold)
|
||||
Spacer()
|
||||
Image(systemName: "bolt")
|
||||
.font(.caption)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
Text("Volts \(String(format: "%.2f", dm.voltage)) ")
|
||||
.font(.caption2)
|
||||
BatteryCompact(batteryLevel: dm.batteryLevel, font: .caption, iconFont: .callout, color: .accentColor)
|
||||
}
|
||||
HStack {
|
||||
Text("Channel Utilization \(String(format: "%.2f", dm.channelUtilization))% ")
|
||||
.foregroundColor(dm.channelUtilization < 25 ? .green : (dm.channelUtilization > 50 ? .red : .orange))
|
||||
Text("Airtime \(String(format: "%.2f", dm.airUtilTx))%")
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
}
|
||||
.font(.caption)
|
||||
}
|
||||
.width(ideal: 200, max: .infinity)
|
||||
}
|
||||
} else {
|
||||
/// Multi Column table for ipads and mac
|
||||
Table(deviceMetrics, selection: $selection, sortOrder: $sortOrder) {
|
||||
TableColumn("battery.level") { dm in
|
||||
if dm.batteryLevel > 100 {
|
||||
Text("Powered")
|
||||
|
|
@ -113,6 +136,7 @@ struct DeviceMetricsLog: View {
|
|||
}
|
||||
TableColumn("channel.utilization") { dm in
|
||||
Text("\(String(format: "%.2f", dm.channelUtilization))%")
|
||||
.foregroundColor(dm.channelUtilization < 25 ? .green : (dm.channelUtilization > 50 ? .red : .orange))
|
||||
}
|
||||
TableColumn("airtime") { dm in
|
||||
Text("\(String(format: "%.2f", dm.airUtilTx))%")
|
||||
|
|
@ -123,61 +147,12 @@ struct DeviceMetricsLog: View {
|
|||
let components = (now..<later).formatted(.components(style: .narrow))
|
||||
Text(components)
|
||||
}
|
||||
.width(min: 100)
|
||||
TableColumn("timestamp") { dm in
|
||||
Text(dm.time?.formattedDate(format: dateFormatString) ?? "unknown.age".localized)
|
||||
}
|
||||
.width(min: 180)
|
||||
}
|
||||
} else {
|
||||
ScrollView {
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 20, maximum: 60), spacing: 0.1),
|
||||
GridItem(.flexible(minimum: 20, maximum: 60), spacing: 0.1),
|
||||
GridItem(.flexible(minimum: 20, maximum: 60), spacing: 0.1),
|
||||
GridItem(.flexible(minimum: 20, maximum: 60), spacing: 0.1),
|
||||
GridItem(.flexible(minimum: 100, maximum: .infinity), spacing: 0.1)
|
||||
]
|
||||
LazyVGrid(columns: columns, alignment: .leading, spacing: 1) {
|
||||
GridRow {
|
||||
Text("Batt")
|
||||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
Text("Volt")
|
||||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
Text("ChUtil")
|
||||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
Text("AirTm")
|
||||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
Text("timestamp")
|
||||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
}
|
||||
ForEach(deviceMetrics) { dm in
|
||||
GridRow {
|
||||
if dm.batteryLevel > 100 {
|
||||
Text("PWD")
|
||||
.font(.caption)
|
||||
} else {
|
||||
Text("\(String(dm.batteryLevel))%")
|
||||
.font(.caption)
|
||||
}
|
||||
Text(String(dm.voltage))
|
||||
.font(.caption)
|
||||
Text("\(String(format: "%.2f", dm.channelUtilization))%")
|
||||
.font(.caption)
|
||||
Text("\(String(format: "%.2f", dm.airUtilTx))%")
|
||||
.font(.caption)
|
||||
Text(dm.time?.formattedDate(format: dateFormatString) ?? "unknown.age".localized)
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.leading, 15)
|
||||
.padding(.trailing, 5)
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
Button(role: .destructive) {
|
||||
|
|
@ -187,7 +162,7 @@ struct DeviceMetricsLog: View {
|
|||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.controlSize(idiom == .phone ? .regular : .large)
|
||||
.padding(.bottom)
|
||||
.padding(.leading)
|
||||
.confirmationDialog(
|
||||
|
|
@ -212,7 +187,7 @@ struct DeviceMetricsLog: View {
|
|||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.controlSize(idiom == .phone ? .regular : .large)
|
||||
.padding(.bottom)
|
||||
.padding(.trailing)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ struct NodeListItem: View {
|
|||
if node.favorite {
|
||||
Spacer()
|
||||
Image(systemName: "star.fill")
|
||||
.foregroundColor(.yellow)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
}
|
||||
}
|
||||
if connected {
|
||||
|
|
@ -75,11 +75,11 @@ struct NodeListItem: View {
|
|||
HStack {
|
||||
Image(systemName: "envelope.arrow.triangle.branch")
|
||||
.font(.callout)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.frame(width: 30)
|
||||
Text("storeforward".localized)
|
||||
.font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption)
|
||||
.foregroundColor(.gray)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ struct NodeListItem: View {
|
|||
let metersAway = nodeCoord.distance(from: myCoord)
|
||||
Image(systemName: "lines.measurement.horizontal")
|
||||
.font(.callout)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.frame(width: 30)
|
||||
DistanceText(meters: metersAway)
|
||||
.font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption)
|
||||
|
|
@ -109,11 +109,11 @@ struct NodeListItem: View {
|
|||
let metersAway = nodeCoord.distance(from: myCoord)
|
||||
Image(systemName: "lines.measurement.horizontal")
|
||||
.font(.callout)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.frame(width: 30)
|
||||
DistanceText(meters: metersAway)
|
||||
.font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption)
|
||||
.foregroundColor(.gray)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -124,18 +124,17 @@ struct NodeListItem: View {
|
|||
HStack {
|
||||
Image(systemName: "\(node.channel).circle.fill")
|
||||
.font(.title2)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.frame(width: 30)
|
||||
.foregroundColor(.accentColor)
|
||||
Text("Channel")
|
||||
.foregroundColor(.gray)
|
||||
.foregroundColor(.secondary)
|
||||
.font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption)
|
||||
}
|
||||
}
|
||||
|
||||
if node.viaMqtt && connectedNode != node.num {
|
||||
Image(systemName: "dot.radiowaves.up.forward")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.font(.callout)
|
||||
.frame(width: 30)
|
||||
Text("MQTT")
|
||||
|
|
@ -165,7 +164,7 @@ struct NodeListItem: View {
|
|||
.frame(width: 30)
|
||||
}
|
||||
if node.hasEnvironmentMetrics {
|
||||
Image(systemName: "cloud.sun.rain")
|
||||
Image(systemName: "cloud.sun.rain.fill")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.callout)
|
||||
.frame(width: 30)
|
||||
|
|
@ -190,13 +189,13 @@ struct NodeListItem: View {
|
|||
HStack {
|
||||
Image(systemName: "hare")
|
||||
.font(.callout)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
Text("Hops Away:")
|
||||
.foregroundColor(.gray)
|
||||
.foregroundColor(.secondary)
|
||||
.font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption)
|
||||
Image(systemName: "\(node.hopsAway).square")
|
||||
.font(.title2)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.symbolRenderingMode(.multicolor)
|
||||
}
|
||||
} else {
|
||||
if node.snr != 0 && !node.viaMqtt {
|
||||
|
|
|
|||
|
|
@ -502,7 +502,6 @@ struct Settings: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.listStyle(.insetGrouped)
|
||||
.navigationTitle("settings")
|
||||
.navigationBarItems(
|
||||
leading: MeshtasticLogo()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue