diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 8e1b5c2b..4cd9deb0 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -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 = ""; diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 341004f7..cdd0d91e 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -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) diff --git a/Meshtastic/Protobufs/meshtastic/deviceonly.pb.swift b/Meshtastic/Protobufs/meshtastic/deviceonly.pb.swift index 821b9370..048c99aa 100644 --- a/Meshtastic/Protobufs/meshtastic/deviceonly.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/deviceonly.pb.swift @@ -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} diff --git a/Meshtastic/Protobufs/meshtastic/mesh.pb.swift b/Meshtastic/Protobufs/meshtastic/mesh.pb.swift index caa1f1bc..bdc8da97 100644 --- a/Meshtastic/Protobufs/meshtastic/mesh.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/mesh.pb.swift @@ -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(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(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 } diff --git a/Meshtastic/Protobufs/meshtastic/portnums.pb.swift b/Meshtastic/Protobufs/meshtastic/portnums.pb.swift index ea5ce5bd..937ff635 100644 --- a/Meshtastic/Protobufs/meshtastic/portnums.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/portnums.pb.swift @@ -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 diff --git a/Meshtastic/Protobufs/meshtastic/telemetry.pb.swift b/Meshtastic/Protobufs/meshtastic/telemetry.pb.swift index debcff60..72d378bc 100644 --- a/Meshtastic/Protobufs/meshtastic/telemetry.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/telemetry.pb.swift @@ -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"), ] } diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 542e7650..6b4ded5f 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -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) } } } diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift index 67922046..b309c925 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift @@ -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") diff --git a/Meshtastic/Views/Nodes/MeshMap.swift b/Meshtastic/Views/Nodes/MeshMap.swift index 1859993a..4394efce 100644 --- a/Meshtastic/Views/Nodes/MeshMap.swift +++ b/Meshtastic/Views/Nodes/MeshMap.swift @@ -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 diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 122f8f10..8d446b18 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -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) diff --git a/Meshtastic/Views/Nodes/PaxCounterLog.swift b/Meshtastic/Views/Nodes/PaxCounterLog.swift index b47ba1a1..df85fc01 100644 --- a/Meshtastic/Views/Nodes/PaxCounterLog.swift +++ b/Meshtastic/Views/Nodes/PaxCounterLog.swift @@ -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 { diff --git a/Meshtastic/Views/Settings/Channels.swift b/Meshtastic/Views/Settings/Channels.swift index ea91d13b..0f5cc6e5 100644 --- a/Meshtastic/Views/Settings/Channels.swift +++ b/Meshtastic/Views/Settings/Channels.swift @@ -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, diff --git a/protobufs b/protobufs index 52415835..5a97acb1 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 5241583565ccbbb4986180bf4c6eb7f8a0dec285 +Subproject commit 5a97acb17543a10e114675a205e3274a83e721af