Bump version and protos

This commit is contained in:
Garth Vander Houwen 2024-03-09 20:07:12 -08:00
parent b22ca2db81
commit 2ba208fa8e
13 changed files with 250 additions and 101 deletions

View file

@ -1584,7 +1584,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.2.27;
MARKETING_VERSION = 2.3.0;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
@ -1618,7 +1618,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.2.27;
MARKETING_VERSION = 2.3.0;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
@ -1740,7 +1740,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.2.27;
MARKETING_VERSION = 2.3.0;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1773,7 +1773,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.2.27;
MARKETING_VERSION = 2.3.0;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

View file

@ -147,6 +147,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
newNode.channel = Int32(packet.channel)
if let nodeInfoMessage = try? NodeInfo(serializedData: packet.decoded.payload) {
newNode.channel = Int32(nodeInfoMessage.channel)
newNode.hopsAway = Int32(truncatingIfNeeded: nodeInfoMessage.hopsAway)
}
if let newUserMessage = try? User(serializedData: packet.decoded.payload) {
@ -215,6 +216,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
if let nodeInfoMessage = try? NodeInfo(serializedData: packet.decoded.payload) {
fetchedNode[0].channel = Int32(nodeInfoMessage.channel)
fetchedNode[0].hopsAway = Int32(truncatingIfNeeded: nodeInfoMessage.hopsAway)
if nodeInfoMessage.hasDeviceMetrics {
let telemetry = TelemetryEntity(context: context)
telemetry.batteryLevel = Int32(nodeInfoMessage.deviceMetrics.batteryLevel)

View file

@ -254,6 +254,20 @@ struct NodeInfoLite {
set {_uniqueStorage()._channel = newValue}
}
///
/// True if we witnessed the node over MQTT instead of LoRA transport
var viaMqtt: Bool {
get {return _storage._viaMqtt}
set {_uniqueStorage()._viaMqtt = newValue}
}
///
/// Number of hops away from us this node is (0 if adjacent)
var hopsAway: UInt32 {
get {return _storage._hopsAway}
set {_uniqueStorage()._hopsAway = newValue}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
@ -583,6 +597,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
5: .standard(proto: "last_heard"),
6: .standard(proto: "device_metrics"),
7: .same(proto: "channel"),
8: .standard(proto: "via_mqtt"),
9: .standard(proto: "hops_away"),
]
fileprivate class _StorageClass {
@ -593,6 +609,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
var _lastHeard: UInt32 = 0
var _deviceMetrics: DeviceMetrics? = nil
var _channel: UInt32 = 0
var _viaMqtt: Bool = false
var _hopsAway: UInt32 = 0
static let defaultInstance = _StorageClass()
@ -606,6 +624,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
_lastHeard = source._lastHeard
_deviceMetrics = source._deviceMetrics
_channel = source._channel
_viaMqtt = source._viaMqtt
_hopsAway = source._hopsAway
}
}
@ -631,6 +651,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
case 5: try { try decoder.decodeSingularFixed32Field(value: &_storage._lastHeard) }()
case 6: try { try decoder.decodeSingularMessageField(value: &_storage._deviceMetrics) }()
case 7: try { try decoder.decodeSingularUInt32Field(value: &_storage._channel) }()
case 8: try { try decoder.decodeSingularBoolField(value: &_storage._viaMqtt) }()
case 9: try { try decoder.decodeSingularUInt32Field(value: &_storage._hopsAway) }()
default: break
}
}
@ -664,6 +686,12 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
if _storage._channel != 0 {
try visitor.visitSingularUInt32Field(value: _storage._channel, fieldNumber: 7)
}
if _storage._viaMqtt != false {
try visitor.visitSingularBoolField(value: _storage._viaMqtt, fieldNumber: 8)
}
if _storage._hopsAway != 0 {
try visitor.visitSingularUInt32Field(value: _storage._hopsAway, fieldNumber: 9)
}
}
try unknownFields.traverse(visitor: &visitor)
}
@ -680,6 +708,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
if _storage._lastHeard != rhs_storage._lastHeard {return false}
if _storage._deviceMetrics != rhs_storage._deviceMetrics {return false}
if _storage._channel != rhs_storage._channel {return false}
if _storage._viaMqtt != rhs_storage._viaMqtt {return false}
if _storage._hopsAway != rhs_storage._hopsAway {return false}
return true
}
if !storagesAreEqual {return false}

View file

@ -1434,8 +1434,7 @@ struct MeshPacket {
}
///
/// The (immediatSee Priority description for more details.y should be fixed32 instead, this encoding only
/// hurts the ble link though.
/// The (immediate) destination for this packet
var to: UInt32 {
get {return _storage._to}
set {_uniqueStorage()._to = newValue}
@ -1566,6 +1565,14 @@ struct MeshPacket {
set {_uniqueStorage()._viaMqtt = newValue}
}
///
/// Hop limit with which the original packet started. Sent via LoRa using three bits in the unencrypted header.
/// When receiving a packet, the difference between hop_start and hop_limit gives how many hops it traveled.
var hopStart: UInt32 {
get {return _storage._hopStart}
set {_uniqueStorage()._hopStart = newValue}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
enum OneOf_PayloadVariant: Equatable {
@ -1779,62 +1786,86 @@ struct NodeInfo {
///
/// The node number
var num: UInt32 = 0
var num: UInt32 {
get {return _storage._num}
set {_uniqueStorage()._num = newValue}
}
///
/// The user info for this node
var user: User {
get {return _user ?? User()}
set {_user = newValue}
get {return _storage._user ?? User()}
set {_uniqueStorage()._user = newValue}
}
/// Returns true if `user` has been explicitly set.
var hasUser: Bool {return self._user != nil}
var hasUser: Bool {return _storage._user != nil}
/// Clears the value of `user`. Subsequent reads from it will return its default value.
mutating func clearUser() {self._user = nil}
mutating func clearUser() {_uniqueStorage()._user = nil}
///
/// This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true.
/// Position.time now indicates the last time we received a POSITION from that node.
var position: Position {
get {return _position ?? Position()}
set {_position = newValue}
get {return _storage._position ?? Position()}
set {_uniqueStorage()._position = newValue}
}
/// Returns true if `position` has been explicitly set.
var hasPosition: Bool {return self._position != nil}
var hasPosition: Bool {return _storage._position != nil}
/// Clears the value of `position`. Subsequent reads from it will return its default value.
mutating func clearPosition() {self._position = nil}
mutating func clearPosition() {_uniqueStorage()._position = nil}
///
/// Returns the Signal-to-noise ratio (SNR) of the last received message,
/// as measured by the receiver. Return SNR of the last received message in dB
var snr: Float = 0
var snr: Float {
get {return _storage._snr}
set {_uniqueStorage()._snr = newValue}
}
///
/// Set to indicate the last time we received a packet from this node
var lastHeard: UInt32 = 0
var lastHeard: UInt32 {
get {return _storage._lastHeard}
set {_uniqueStorage()._lastHeard = newValue}
}
///
/// The latest device metrics for the node.
var deviceMetrics: DeviceMetrics {
get {return _deviceMetrics ?? DeviceMetrics()}
set {_deviceMetrics = newValue}
get {return _storage._deviceMetrics ?? DeviceMetrics()}
set {_uniqueStorage()._deviceMetrics = newValue}
}
/// Returns true if `deviceMetrics` has been explicitly set.
var hasDeviceMetrics: Bool {return self._deviceMetrics != nil}
var hasDeviceMetrics: Bool {return _storage._deviceMetrics != nil}
/// Clears the value of `deviceMetrics`. Subsequent reads from it will return its default value.
mutating func clearDeviceMetrics() {self._deviceMetrics = nil}
mutating func clearDeviceMetrics() {_uniqueStorage()._deviceMetrics = nil}
///
/// local channel index we heard that node on. Only populated if its not the default channel.
var channel: UInt32 = 0
var channel: UInt32 {
get {return _storage._channel}
set {_uniqueStorage()._channel = newValue}
}
///
/// True if we witnessed the node over MQTT instead of LoRA transport
var viaMqtt: Bool {
get {return _storage._viaMqtt}
set {_uniqueStorage()._viaMqtt = newValue}
}
///
/// Number of hops away from us this node is (0 if adjacent)
var hopsAway: UInt32 {
get {return _storage._hopsAway}
set {_uniqueStorage()._hopsAway = newValue}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _user: User? = nil
fileprivate var _position: Position? = nil
fileprivate var _deviceMetrics: DeviceMetrics? = nil
fileprivate var _storage = _StorageClass.defaultInstance
}
///
@ -3369,6 +3400,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
12: .standard(proto: "rx_rssi"),
13: .same(proto: "delayed"),
14: .standard(proto: "via_mqtt"),
15: .standard(proto: "hop_start"),
]
fileprivate class _StorageClass {
@ -3385,6 +3417,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
var _rxRssi: Int32 = 0
var _delayed: MeshPacket.Delayed = .noDelay
var _viaMqtt: Bool = false
var _hopStart: UInt32 = 0
static let defaultInstance = _StorageClass()
@ -3404,6 +3437,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
_rxRssi = source._rxRssi
_delayed = source._delayed
_viaMqtt = source._viaMqtt
_hopStart = source._hopStart
}
}
@ -3455,6 +3489,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
case 12: try { try decoder.decodeSingularInt32Field(value: &_storage._rxRssi) }()
case 13: try { try decoder.decodeSingularEnumField(value: &_storage._delayed) }()
case 14: try { try decoder.decodeSingularBoolField(value: &_storage._viaMqtt) }()
case 15: try { try decoder.decodeSingularUInt32Field(value: &_storage._hopStart) }()
default: break
}
}
@ -3514,6 +3549,9 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
if _storage._viaMqtt != false {
try visitor.visitSingularBoolField(value: _storage._viaMqtt, fieldNumber: 14)
}
if _storage._hopStart != 0 {
try visitor.visitSingularUInt32Field(value: _storage._hopStart, fieldNumber: 15)
}
}
try unknownFields.traverse(visitor: &visitor)
}
@ -3536,6 +3574,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
if _storage._rxRssi != rhs_storage._rxRssi {return false}
if _storage._delayed != rhs_storage._delayed {return false}
if _storage._viaMqtt != rhs_storage._viaMqtt {return false}
if _storage._hopStart != rhs_storage._hopStart {return false}
return true
}
if !storagesAreEqual {return false}
@ -3575,63 +3614,123 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
5: .standard(proto: "last_heard"),
6: .standard(proto: "device_metrics"),
7: .same(proto: "channel"),
8: .standard(proto: "via_mqtt"),
9: .standard(proto: "hops_away"),
]
fileprivate class _StorageClass {
var _num: UInt32 = 0
var _user: User? = nil
var _position: Position? = nil
var _snr: Float = 0
var _lastHeard: UInt32 = 0
var _deviceMetrics: DeviceMetrics? = nil
var _channel: UInt32 = 0
var _viaMqtt: Bool = false
var _hopsAway: UInt32 = 0
static let defaultInstance = _StorageClass()
private init() {}
init(copying source: _StorageClass) {
_num = source._num
_user = source._user
_position = source._position
_snr = source._snr
_lastHeard = source._lastHeard
_deviceMetrics = source._deviceMetrics
_channel = source._channel
_viaMqtt = source._viaMqtt
_hopsAway = source._hopsAway
}
}
fileprivate mutating func _uniqueStorage() -> _StorageClass {
if !isKnownUniquelyReferenced(&_storage) {
_storage = _StorageClass(copying: _storage)
}
return _storage
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// 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.decodeSingularUInt32Field(value: &self.num) }()
case 2: try { try decoder.decodeSingularMessageField(value: &self._user) }()
case 3: try { try decoder.decodeSingularMessageField(value: &self._position) }()
case 4: try { try decoder.decodeSingularFloatField(value: &self.snr) }()
case 5: try { try decoder.decodeSingularFixed32Field(value: &self.lastHeard) }()
case 6: try { try decoder.decodeSingularMessageField(value: &self._deviceMetrics) }()
case 7: try { try decoder.decodeSingularUInt32Field(value: &self.channel) }()
default: break
_ = _uniqueStorage()
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// 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.decodeSingularUInt32Field(value: &_storage._num) }()
case 2: try { try decoder.decodeSingularMessageField(value: &_storage._user) }()
case 3: try { try decoder.decodeSingularMessageField(value: &_storage._position) }()
case 4: try { try decoder.decodeSingularFloatField(value: &_storage._snr) }()
case 5: try { try decoder.decodeSingularFixed32Field(value: &_storage._lastHeard) }()
case 6: try { try decoder.decodeSingularMessageField(value: &_storage._deviceMetrics) }()
case 7: try { try decoder.decodeSingularUInt32Field(value: &_storage._channel) }()
case 8: try { try decoder.decodeSingularBoolField(value: &_storage._viaMqtt) }()
case 9: try { try decoder.decodeSingularUInt32Field(value: &_storage._hopsAway) }()
default: break
}
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if self.num != 0 {
try visitor.visitSingularUInt32Field(value: self.num, fieldNumber: 1)
}
try { if let v = self._user {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
} }()
try { if let v = self._position {
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
} }()
if self.snr != 0 {
try visitor.visitSingularFloatField(value: self.snr, fieldNumber: 4)
}
if self.lastHeard != 0 {
try visitor.visitSingularFixed32Field(value: self.lastHeard, fieldNumber: 5)
}
try { if let v = self._deviceMetrics {
try visitor.visitSingularMessageField(value: v, fieldNumber: 6)
} }()
if self.channel != 0 {
try visitor.visitSingularUInt32Field(value: self.channel, fieldNumber: 7)
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if _storage._num != 0 {
try visitor.visitSingularUInt32Field(value: _storage._num, fieldNumber: 1)
}
try { if let v = _storage._user {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
} }()
try { if let v = _storage._position {
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
} }()
if _storage._snr != 0 {
try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4)
}
if _storage._lastHeard != 0 {
try visitor.visitSingularFixed32Field(value: _storage._lastHeard, fieldNumber: 5)
}
try { if let v = _storage._deviceMetrics {
try visitor.visitSingularMessageField(value: v, fieldNumber: 6)
} }()
if _storage._channel != 0 {
try visitor.visitSingularUInt32Field(value: _storage._channel, fieldNumber: 7)
}
if _storage._viaMqtt != false {
try visitor.visitSingularBoolField(value: _storage._viaMqtt, fieldNumber: 8)
}
if _storage._hopsAway != 0 {
try visitor.visitSingularUInt32Field(value: _storage._hopsAway, fieldNumber: 9)
}
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: NodeInfo, rhs: NodeInfo) -> Bool {
if lhs.num != rhs.num {return false}
if lhs._user != rhs._user {return false}
if lhs._position != rhs._position {return false}
if lhs.snr != rhs.snr {return false}
if lhs.lastHeard != rhs.lastHeard {return false}
if lhs._deviceMetrics != rhs._deviceMetrics {return false}
if lhs.channel != rhs.channel {return false}
if lhs._storage !== rhs._storage {
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0
let rhs_storage = _args.1
if _storage._num != rhs_storage._num {return false}
if _storage._user != rhs_storage._user {return false}
if _storage._position != rhs_storage._position {return false}
if _storage._snr != rhs_storage._snr {return false}
if _storage._lastHeard != rhs_storage._lastHeard {return false}
if _storage._deviceMetrics != rhs_storage._deviceMetrics {return false}
if _storage._channel != rhs_storage._channel {return false}
if _storage._viaMqtt != rhs_storage._viaMqtt {return false}
if _storage._hopsAway != rhs_storage._hopsAway {return false}
return true
}
if !storagesAreEqual {return false}
}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}

View file

@ -58,25 +58,25 @@ enum PortNum: SwiftProtobuf.Enum {
///
/// The built-in position messaging app.
/// Payload is a [Position](/docs/developers/protobufs/api#position) message
/// Payload is a Position message.
/// ENCODING: Protobuf
case positionApp // = 3
///
/// The built-in user info app.
/// Payload is a [User](/docs/developers/protobufs/api#user) message
/// Payload is a User message.
/// ENCODING: Protobuf
case nodeinfoApp // = 4
///
/// Protocol control packets for mesh protocol use.
/// Payload is a [Routing](/docs/developers/protobufs/api#routing) message
/// Payload is a Routing message.
/// ENCODING: Protobuf
case routingApp // = 5
///
/// Admin control packets.
/// Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message
/// Payload is a AdminMessage message.
/// ENCODING: Protobuf
case adminApp // = 6
@ -90,7 +90,7 @@ enum PortNum: SwiftProtobuf.Enum {
///
/// Waypoint payloads.
/// Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message
/// Payload is a Waypoint message.
/// ENCODING: Protobuf
case waypointApp // = 8

View file

@ -84,6 +84,10 @@ enum TelemetrySensorType: SwiftProtobuf.Enum {
///
/// INA3221 3 Channel Voltage / Current Sensor
case ina3221 // = 14
///
/// BMP085/BMP180 High accuracy temperature and pressure (older Version of BMP280)
case bmp085 // = 15
case UNRECOGNIZED(Int)
init() {
@ -107,6 +111,7 @@ enum TelemetrySensorType: SwiftProtobuf.Enum {
case 12: self = .sht31
case 13: self = .pmsa003I
case 14: self = .ina3221
case 15: self = .bmp085
default: self = .UNRECOGNIZED(rawValue)
}
}
@ -128,6 +133,7 @@ enum TelemetrySensorType: SwiftProtobuf.Enum {
case .sht31: return 12
case .pmsa003I: return 13
case .ina3221: return 14
case .bmp085: return 15
case .UNRECOGNIZED(let i): return i
}
}
@ -154,6 +160,7 @@ extension TelemetrySensorType: CaseIterable {
.sht31,
.pmsa003I,
.ina3221,
.bmp085,
]
}
@ -450,6 +457,7 @@ extension TelemetrySensorType: SwiftProtobuf._ProtoNameProviding {
12: .same(proto: "SHT31"),
13: .same(proto: "PMSA003I"),
14: .same(proto: "INA3221"),
15: .same(proto: "BMP085"),
]
}

View file

@ -157,6 +157,7 @@ struct UserList: View {
.listStyle(.plain)
.navigationTitle(String.localizedStringWithFormat("contacts %@".localized, String(users.count == 0 ? 0 : users.count - 1)))
.searchable(text: usersQuery, placement: users.count > 10 ? .navigationBarDrawer(displayMode: .always) : .automatic, prompt: "Find a contact")
.disableAutocorrection(true)
}
}
}

View file

@ -21,18 +21,9 @@ struct NodeListItem: View {
LazyVStack(alignment: .leading) {
HStack {
VStack(alignment: .leading) {
CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 70)
.padding(.trailing, 5)
if node.hopsAway == 0 {
HStack {
Image(systemName: "hare")
.font(.callout)
.symbolRenderingMode(.hierarchical)
Image(systemName: "\(node.hopsAway).square")
.font(.title2)
.symbolRenderingMode(.hierarchical)
}
}
BatteryLevelCompact(node: node, font: .caption, iconFont: .callout, color: .accentColor)
.padding(.trailing, 5)
}
@ -128,26 +119,42 @@ struct NodeListItem: View {
}
}
HStack {
if node.channel > 0 {
Image(systemName: "fibrechannel")
.font(.callout)
.symbolRenderingMode(.hierarchical)
.frame(width: 30)
Text("Channel: \(node.channel)")
.foregroundColor(.gray)
.font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption)
if node.channel >= 0 {
HStack {
Image(systemName: "\(node.channel).circle.fill")
.font(.title2)
.symbolRenderingMode(.hierarchical)
.frame(width: 30)
.foregroundColor(.accentColor)
Text("Channel")
.foregroundColor(.gray)
.font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption)
}
}
if node.viaMqtt && connectedNode != node.num {
Image(systemName: "network")
.symbolRenderingMode(.hierarchical)
.font(.callout)
.frame(width: 30)
Text("Via MQTT")
Text("MQTT")
.foregroundColor(.gray)
.font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption)
}
}
if node.hopsAway > 0 {
HStack {
Image(systemName: "hare")
.font(.callout)
.symbolRenderingMode(.hierarchical)
Text("Hops Away:")
.foregroundColor(.gray)
.font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption)
Image(systemName: "\(node.hopsAway).square")
.font(.title2)
.symbolRenderingMode(.hierarchical)
}
}
if node.hasPositions || node.hasEnvironmentMetrics || node.hasDetectionSensorMetrics || node.hasTraceRoutes {
HStack {
Image(systemName: "scroll")

View file

@ -123,6 +123,7 @@ struct MeshMap: View {
if radius > 0.0 {
MapCircle(center: position.coordinate, radius: radius)
.foregroundStyle(Color(nodeColor).opacity(0.25))
.stroke(.white, lineWidth: 2)
}
}
/// Routes

View file

@ -161,6 +161,7 @@ struct NodeList: View {
}
}
.searchable(text: $searchState.searchText, placement: nodes.count > 10 ? .navigationBarDrawer(displayMode: .always) : .automatic, prompt: "Find a node")
.disableAutocorrection(true)
.searchScopes($searchState.searchScope) {
ForEach(NodeSearchState.SearchScopes.allCases) { scope in
Text(scope.title).tag(scope)

View file

@ -111,11 +111,11 @@ struct PaxCounterLog: View {
} else {
ScrollView {
let columns = [
GridItem(.flexible(minimum: 20, maximum: 55), spacing: 0.1),
GridItem(.flexible(minimum: 20, maximum: 55), spacing: 0.1),
GridItem(.flexible(minimum: 20, maximum: 55), spacing: 0.1),
GridItem(.flexible(minimum: 60, maximum: 100), spacing: 0.1),
GridItem(.flexible(minimum: 130, maximum: 200), spacing: 0.1)
GridItem(.flexible(minimum: 20, maximum: 50), spacing: 0.1),
GridItem(.flexible(minimum: 20, maximum: 50), spacing: 0.1),
GridItem(.flexible(minimum: 20, maximum: 50), spacing: 0.1),
GridItem(.flexible(minimum: 60, maximum: 140), spacing: 0.1),
GridItem(.flexible(minimum: 100, maximum: 160), spacing: 0.1)
]
LazyVGrid(columns: columns, alignment: .leading, spacing: 1) {
GridRow {

View file

@ -268,7 +268,7 @@ struct Channels: View {
if !preciseLocation {
VStack(alignment: .leading) {
Label("Reduce Precision", systemImage: "location.viewfinder")
Label("Approximate Location", systemImage: "location.slash.circle.fill")
Slider(
value: $positionPrecision,
in: 11...16,

@ -1 +1 @@
Subproject commit 5241583565ccbbb4986180bf4c6eb7f8a0dec285
Subproject commit 5a97acb17543a10e114675a205e3274a83e721af