Start work to fix the broken node map view

Tidy up suggested mqtt topics
This commit is contained in:
Garth Vander Houwen 2024-03-14 18:58:05 -07:00
parent d84f2ad91a
commit d5f5d70364
4 changed files with 151 additions and 115 deletions

View file

@ -28,7 +28,47 @@ enum RegionCodes: Int, CaseIterable, Identifiable {
case my_919 = 17
case sg_923 = 18
case lora24 = 13
var topic: String {
switch self {
case .unset:
"UNSET"
case .us:
"US"
case .eu433:
"EU_433"
case .eu868:
"EU_868"
case .cn:
"CN"
case .jp:
"JP"
case .anz:
"ANZ"
case .kr:
"KR"
case .tw:
"TW"
case .ru:
"RU"
case .in:
"IN"
case .nz865:
"NZ_865"
case .th:
"TH"
case .ua433:
"UA_433"
case .ua868:
"UA_868"
case .my_433:
"MY_433"
case .my_919:
"MY_919"
case .sg_923:
"SG_923"
case .lora24:
"LORA_24"
} }
var id: Int { self.rawValue }
var description: String {
switch self {

View file

@ -10,7 +10,6 @@ import CoreLocation
#if canImport(MapKit)
import MapKit
#endif
import WeatherKit
@available(iOS 17.0, macOS 14.0, *)
struct NodeMapSwiftUI: View {
@ -60,6 +59,15 @@ struct NodeMapSwiftUI: View {
Map(position: $position, bounds: MapCameraBounds(minimumDistance: 1, maximumDistance: .infinity), scope: mapScope) {
/// Node Color from node.num
let nodeColor = UIColor(hex: UInt32(node.num))
/// Convex Hull
if showConvexHull {
if lineCoords.count > 0 {
let hull = lineCoords.getConvexHull()
MapPolygon(coordinates: hull)
.stroke(Color(nodeColor.darker()), lineWidth: 3)
.foregroundStyle(Color(nodeColor).opacity(0.4))
}
}
/// Route Lines
if showRouteLines {
let gradient = LinearGradient(
@ -73,114 +81,96 @@ struct NodeMapSwiftUI: View {
MapPolyline(coordinates: lineCoords)
.stroke(gradient, style: dashed)
}
/// Convex Hull
if showConvexHull {
if lineCoords.count > 0 {
let hull = lineCoords.getConvexHull()
MapPolygon(coordinates: hull)
.stroke(Color(nodeColor.darker()), lineWidth: 3)
.foregroundStyle(Color(nodeColor).opacity(0.4))
}
}
/// Waypoint Annotations
if waypoints.count > 0 && showWaypoints {
ForEach(Array(waypoints), id: \.id) { waypoint in
Annotation(waypoint.name ?? "?", coordinate: waypoint.coordinate) {
LazyVStack {
CircleText(text: String(UnicodeScalar(Int(waypoint.icon)) ?? "📍"), color: Color.orange, circleSize: 35)
.onTapGesture(coordinateSpace: .named("nodemap")) { location in
selectedWaypoint = (selectedWaypoint == waypoint ? nil : waypoint)
}
}
}
}
}
/// Node Annotations
ForEach(positionArray, id: \.id) { position in
let pf = PositionFlags(rawValue: Int(position.nodePosition?.metadata?.positionFlags ?? 771))
let headingDegrees = Angle.degrees(Double(position.heading))
/// Reduced Precision Map Circle
if position.latest && 11...16 ~= position.precisionBits {
let pp = PositionPrecision(rawValue: Int(position.precisionBits))
let radius : CLLocationDistance = pp?.precisionMeters ?? 0
if radius > 0.0 {
MapCircle(center: position.coordinate, radius: radius)
.foregroundStyle(Color(nodeColor).opacity(0.25))
.stroke(.white, lineWidth: 2)
// /// Reduced Precision Map Circle
// if position.latest && 11...16 ~= position.precisionBits {
// let pp = PositionPrecision(rawValue: Int(position.precisionBits))
// let radius : CLLocationDistance = pp?.precisionMeters ?? 0
// if radius > 0.0 {
// MapCircle(center: position.coordinate, radius: radius)
// .foregroundStyle(Color(nodeColor).opacity(0.25))
// .stroke(.white, lineWidth: 2)
// }
// }
// Annotation(position.latest ? node.user?.shortName ?? "?": "", coordinate: position.coordinate) {
// LazyVStack {
// if position.latest {
// ZStack {
// Circle()
// .fill(Color(nodeColor.lighter()).opacity(0.4).shadow(.drop(color: Color(nodeColor).isLight() ? .black : .white, radius: 5)))
// .foregroundStyle(Color(nodeColor.lighter()).opacity(0.3))
// .frame(width: 50, height: 50)
// if pf.contains(.Heading) {
// Image(systemName: pf.contains(.Speed) && position.speed > 1 ? "location.north" : "octagon")
// .symbolEffect(.pulse.byLayer)
// .padding(5)
// .foregroundStyle(Color(nodeColor).isLight() ? .black : .white)
// .background(Color(nodeColor.darker()))
// .clipShape(Circle())
// .rotationEffect(headingDegrees)
// .onTapGesture {
// selectedPosition = (selectedPosition == position ? nil : position)
// }
// .popover(item: $selectedPosition) { selection in
// PositionPopover(position: selection)
// .padding()
// .opacity(0.8)
// .presentationCompactAdaptation(.popover)
// }
//
// } else {
// Image(systemName: "flipphone")
// .symbolEffect(.pulse.byLayer)
// .padding(5)
// .foregroundStyle(Color(nodeColor).isLight() ? .black : .white)
// .background(Color(UIColor(hex: UInt32(node.num)).darker()))
// .clipShape(Circle())
// .onTapGesture {
// selectedPosition = (selectedPosition == position ? nil : position)
// }
// .popover(item: $selectedPosition) { selection in
// PositionPopover(position: selection)
// .padding()
// .opacity(0.8)
// .presentationCompactAdaptation(.popover)
// }
//
// }
// }
// } else {
// if showNodeHistory {
// if pf.contains(.Heading) {
// Image(systemName: "location.north.circle")
// .resizable()
// .scaledToFit()
// .foregroundStyle(Color(UIColor(hex: UInt32(node.num))).isLight() ? .black : .white)
// .background(Color(UIColor(hex: UInt32(node.num))))
// .clipShape(Circle())
// .rotationEffect(headingDegrees)
// .frame(width: 16, height: 16)
//
// } else {
// Circle()
// .fill(Color(UIColor(hex: UInt32(node.num))))
// .strokeBorder(Color(UIColor(hex: UInt32(node.num))).isLight() ? .black : .white ,lineWidth: 2)
// .frame(width: 12, height: 12)
// }
// }
// }
}
}
Annotation(position.latest ? node.user?.shortName ?? "?": "", coordinate: position.coordinate) {
LazyVStack {
if position.latest {
ZStack {
Circle()
.fill(Color(nodeColor.lighter()).opacity(0.4).shadow(.drop(color: Color(nodeColor).isLight() ? .black : .white, radius: 5)))
.foregroundStyle(Color(nodeColor.lighter()).opacity(0.3))
.frame(width: 50, height: 50)
if pf.contains(.Heading) {
Image(systemName: pf.contains(.Speed) && position.speed > 1 ? "location.north" : "octagon")
.symbolEffect(.pulse.byLayer)
.padding(5)
.foregroundStyle(Color(nodeColor).isLight() ? .black : .white)
.background(Color(nodeColor.darker()))
.clipShape(Circle())
.rotationEffect(headingDegrees)
.onTapGesture {
selectedPosition = (selectedPosition == position ? nil : position)
}
.popover(item: $selectedPosition) { selection in
PositionPopover(position: selection)
.padding()
.opacity(0.8)
.presentationCompactAdaptation(.popover)
}
} else {
Image(systemName: "flipphone")
.symbolEffect(.pulse.byLayer)
.padding(5)
.foregroundStyle(Color(nodeColor).isLight() ? .black : .white)
.background(Color(UIColor(hex: UInt32(node.num)).darker()))
.clipShape(Circle())
.onTapGesture {
selectedPosition = (selectedPosition == position ? nil : position)
}
.popover(item: $selectedPosition) { selection in
PositionPopover(position: selection)
.padding()
.opacity(0.8)
.presentationCompactAdaptation(.popover)
}
}
}
} else {
if showNodeHistory {
if pf.contains(.Heading) {
Image(systemName: "location.north.circle")
.resizable()
.scaledToFit()
.foregroundStyle(Color(UIColor(hex: UInt32(node.num))).isLight() ? .black : .white)
.background(Color(UIColor(hex: UInt32(node.num))))
.clipShape(Circle())
.rotationEffect(headingDegrees)
.frame(width: 16, height: 16)
} else {
Circle()
.fill(Color(UIColor(hex: UInt32(node.num))))
.strokeBorder(Color(UIColor(hex: UInt32(node.num))).isLight() ? .black : .white ,lineWidth: 2)
.frame(width: 12, height: 12)
}
}
}
}
}
.tag(position.time)
.annotationTitles(.automatic)
.annotationSubtitles(.automatic)
}
// }
// .tag(position.time)
// .annotationTitles(.automatic)
// .annotationSubtitles(.automatic)
// }
}
.mapScope(mapScope)
.mapStyle(mapStyle)

View file

@ -26,7 +26,9 @@ struct MQTTConfig: View {
@State var root = "msh"
@State var selectedTopic = ""
@State var mqttConnected: Bool = false
@State var defaultTopic = "msh/US"
@State var nearbyTopics = [String]()
let locale = Locale.current
var body: some View {
VStack {
@ -315,6 +317,8 @@ struct MQTTConfig: View {
nearbyTopics = []
let geocoder = CLGeocoder()
if LocationsHandler.shared.locationsArray.count > 0 {
let region = RegionCodes(rawValue: Int(node?.loRaConfig?.regionCode ?? 0))?.topic
defaultTopic = "msh/" + (region ?? "UNSET")
geocoder.reverseGeocodeLocation(LocationsHandler.shared.locationsArray.first!, completionHandler: {(placemarks, error) -> Void in
if error != nil {
print("Failed to reverse geocode location")
@ -322,27 +326,29 @@ struct MQTTConfig: View {
}
if let placemarks = placemarks, let placemark = placemarks.first {
let cc = locale.region?.identifier ?? "UNK"
/// Country Topic unless you are US
if placemark.isoCountryCode ?? "unknown" != "US" {
let countryTopic = root + "/" + (placemark.isoCountryCode ?? "")
if placemark.isoCountryCode ?? "unknown" != cc {
let countryTopic = defaultTopic + "/" + (placemark.isoCountryCode ?? "")
if !countryTopic.isEmpty {
nearbyTopics.append(countryTopic)
}
}
let stateTopic = root + "/" + (placemark.administrativeArea ?? "")
let stateTopic = defaultTopic + "/" + (placemark.administrativeArea ?? "")
if !stateTopic.isEmpty {
nearbyTopics.append(stateTopic)
}
let countyTopic = root + "/" + (placemark.subAdministrativeArea?.lowercased().replacingOccurrences(of: " ", with: "") ?? "")
let countyTopic = defaultTopic + "/" + (placemark.subAdministrativeArea?.lowercased().replacingOccurrences(of: " ", with: "") ?? "")
if !countyTopic.isEmpty {
nearbyTopics.append(countyTopic)
}
let cityTopic = root + "/" + (placemark.locality?.lowercased().replacingOccurrences(of: " ", with: "") ?? "")
let cityTopic = defaultTopic + "/" + (placemark.locality?.lowercased().replacingOccurrences(of: " ", with: "") ?? "")
if !cityTopic.isEmpty {
nearbyTopics.append(cityTopic)
}
let neightborhoodTopic = root + "/" + (placemark.subLocality?.lowercased().replacingOccurrences(of: " ", with: "") ?? "")
let neightborhoodTopic = defaultTopic + "/" + (placemark.subLocality?.lowercased()
.replacingOccurrences(of: " ", with: "")
.replacingOccurrences(of: "'", with: "") ?? "")
if !neightborhoodTopic.isEmpty {
nearbyTopics.append(neightborhoodTopic)
}

View file

@ -185,13 +185,13 @@ struct TelemetryConfig: View {
}
}
func setTelemetryValues() {
self.deviceUpdateInterval = Int(node?.telemetryConfig?.deviceUpdateInterval ?? 0)
self.environmentUpdateInterval = Int(node?.telemetryConfig?.environmentUpdateInterval ?? 0)
self.deviceUpdateInterval = Int(node?.telemetryConfig?.deviceUpdateInterval ?? 900)
self.environmentUpdateInterval = Int(node?.telemetryConfig?.environmentUpdateInterval ?? 900)
self.environmentMeasurementEnabled = node?.telemetryConfig?.environmentMeasurementEnabled ?? false
self.environmentScreenEnabled = node?.telemetryConfig?.environmentScreenEnabled ?? false
self.environmentDisplayFahrenheit = node?.telemetryConfig?.environmentDisplayFahrenheit ?? false
self.powerMeasurementEnabled = node?.telemetryConfig?.powerMeasurementEnabled ?? false
self.powerUpdateInterval = Int(node?.telemetryConfig?.powerUpdateInterval ?? 0)
self.powerUpdateInterval = Int(node?.telemetryConfig?.powerUpdateInterval ?? 900)
self.powerScreenEnabled = node?.telemetryConfig?.powerScreenEnabled ?? false
self.hasChanges = false
}