Move fetch requests to mapcontent

This commit is contained in:
Garth Vander Houwen 2024-03-25 15:21:38 -07:00
parent b0101ab4ce
commit 7eb6659c0c
11 changed files with 88 additions and 84 deletions

View file

@ -60,7 +60,7 @@ enum MeshMapDistances: Double, CaseIterable, Identifiable {
var id: Double { self.rawValue }
var description: String {
let distanceFormatter = MKDistanceFormatter()
return "\(distanceFormatter.string(fromDistance: Double(self.rawValue))) away"
return "up to \(distanceFormatter.string(fromDistance: Double(self.rawValue))) away"
}
}

View file

@ -13,8 +13,10 @@ extension WaypointEntity {
static func allWaypointssFetchRequest() -> NSFetchRequest<WaypointEntity> {
let request: NSFetchRequest<WaypointEntity> = WaypointEntity.fetchRequest()
//request.fetchLimit = 100
request.fetchLimit = 50
//request.fetchBatchSize = 1
//request.returnsObjectsAsFaults = false
//request.includesSubentities = true
request.returnsDistinctResults = true
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: false)]
request.predicate = NSPredicate(format: "expire == nil || expire >= %@", Date() as NSDate)

View file

@ -28,9 +28,9 @@ func generateMessageMarkdown (message: String) -> String {
let phone = messageWithMarkdown[range]
messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: phone, with: "[\(phone)](tel:\(phone))")
} else if match.resultType == .link {
let start = match.range.lowerBound
let stop = match.range.upperBound
if stop > start {
if (match.range.location != NSNotFound) {
let start = match.range.lowerBound
let stop = match.range.upperBound
let url = message[start ..< stop]
let absoluteUrl = match.url?.absoluteString ?? ""
let markdownUrl = "[\(url)](\(absoluteUrl))"

View file

@ -14,8 +14,7 @@ import MapKit
@available(iOS 17.0, macOS 14.0, *)
struct MeshMapContent: MapContent {
@State var positions: [PositionEntity] = []
@State var waypoints: [WaypointEntity] = []
//@State var waypoints: [WaypointEntity] = []
@State var routes: [RouteEntity] = []
/// Parameters
@Binding var showUserLocation: Bool
@ -29,13 +28,19 @@ struct MeshMapContent: MapContent {
@Binding var selectedPosition: PositionEntity?
@Binding var showWaypoints: Bool
@Binding var selectedWaypoint: WaypointEntity?
@FetchRequest(fetchRequest: PositionEntity.allPositionsFetchRequest(), animation: .easeIn)
var positions: FetchedResults<PositionEntity>
@FetchRequest(fetchRequest: WaypointEntity.allWaypointssFetchRequest(), animation: .none)
var waypoints: FetchedResults<WaypointEntity>
var delay: Double = 0
@State private var scale: CGFloat = 0.5
@MapContentBuilder
var meshMap: some MapContent {
let lineCoords = positions.compactMap({(position) -> CLLocationCoordinate2D in
let lineCoords = Array(positions).compactMap({(position) -> CLLocationCoordinate2D in
return position.nodeCoordinate ?? LocationsHandler.DefaultLocation
})
/// Convex Hull
@ -148,7 +153,7 @@ struct MeshMapContent: MapContent {
}
}
/// Routes
ForEach(Array(routes), id: \.id) { route in
ForEach(Array(routes)) { route in
let routeLocations = Array(route.locations!) as! [LocationEntity]
let routeCoords = routeLocations.compactMap({(loc) -> CLLocationCoordinate2D in
return loc.locationCoordinate ?? LocationHelper.DefaultLocation
@ -183,13 +188,15 @@ struct MeshMapContent: MapContent {
/// Waypoint Annotations
if waypoints.count > 0 && showWaypoints {
ForEach(Array(waypoints), id: \.id) { waypoint in
ForEach(Array(waypoints) as! [WaypointEntity], id: \.self) { waypoint in
Annotation(waypoint.name ?? "?", coordinate: waypoint.coordinate) {
LazyVStack {
CircleText(text: String(UnicodeScalar(Int(waypoint.icon)) ?? "📍"), color: Color.orange, circleSize: 40)
.onTapGesture(perform: { location in
selectedWaypoint = (selectedWaypoint == waypoint ? nil : waypoint)
})
ZStack {
CircleText(text: String(UnicodeScalar(Int(waypoint.icon)) ?? "📍"), color: Color.orange, circleSize: 40)
.onTapGesture(perform: { location in
selectedWaypoint = (selectedWaypoint == waypoint ? nil : waypoint)
})
}
}
}
}
@ -199,5 +206,6 @@ struct MeshMapContent: MapContent {
@MapContentBuilder
var body: some MapContent {
meshMap
}
}

View file

@ -29,8 +29,6 @@ struct NodeMapContent: MapContent {
@State var isShowingAltitude = false
@State var isEditingSettings = false
@State var selectedPosition: PositionEntity?
@State var showWaypoints = false
@State var selectedWaypoint: WaypointEntity?
@State var isMeshMap = false
//let region: MKCoordinateRegion

View file

@ -41,22 +41,15 @@ struct MapSettingsForm: View {
UserDefaults.mapLayer = newMapLayer
}
if meshMap {
VStack {
HStack {
Label("Show nodes", systemImage: "lines.measurement.horizontal")
Picker("", selection: $meshMapDistance) {
ForEach(MeshMapDistances.allCases) { di in
Text(di.description)
.tag(di.id)
}
HStack {
Label("Show nodes", systemImage: "lines.measurement.horizontal")
Picker("", selection: $meshMapDistance) {
ForEach(MeshMapDistances.allCases) { di in
Text(di.description)
.tag(di.id)
}
.pickerStyle(DefaultPickerStyle())
}
.listRowSeparator(.hidden)
Text("You will need to close and re-open the app for this to take effect.")
.font(.callout)
.foregroundColor(.gray)
.listRowSeparator(/*@START_MENU_TOKEN@*/.visible/*@END_MENU_TOKEN@*/)
.pickerStyle(DefaultPickerStyle())
}
.onChange(of: meshMapDistance) { newMeshMapDistance in
UserDefaults.meshMapDistance = newMeshMapDistance

View file

@ -36,8 +36,6 @@ struct NodeMapSwiftUI: View {
@State var isShowingAltitude = false
@State var isEditingSettings = false
@State var selectedPosition: PositionEntity?
@State var showWaypoints = false
@State var selectedWaypoint: WaypointEntity?
@State var isMeshMap = false
@State private var mapRegion = MKCoordinateRegion.init()
@ -88,10 +86,6 @@ struct NodeMapSwiftUI: View {
.padding(.horizontal, 20)
}
}
.sheet(item: $selectedWaypoint) { selection in
WaypointForm(waypoint: selection)
.padding()
}
.sheet(isPresented: $isEditingSettings) {
MapSettingsForm(nodeHistory: $showNodeHistory, routeLines: $showRouteLines, convexHull: $showConvexHull, traffic: $showTraffic, pointsOfInterest: $showPointsOfInterest, mapLayer: $selectedMapLayer, meshMapDistance: $meshMapDistance, meshMap: $isMeshMap)
.onChange(of: (selectedMapLayer)) { newMapLayer in
@ -162,21 +156,6 @@ struct NodeMapSwiftUI: View {
.tint(Color(UIColor.secondarySystemBackground))
.foregroundColor(.accentColor)
.buttonStyle(.borderedProminent)
/// Show / Hide Waypoints Button
if waypoints.count > 0 {
Button(action: {
withAnimation {
showWaypoints = !showWaypoints
}
}) {
Image(systemName: showWaypoints ? "signpost.right.and.left.fill" : "signpost.right.and.left")
.padding(.vertical, 5)
}
.tint(Color(UIColor.secondarySystemBackground))
.foregroundColor(.accentColor)
.buttonStyle(.borderedProminent)
}
/// Look Around Button
if self.scene != nil {
Button(action: {

View file

@ -37,17 +37,12 @@ struct MeshMap: View {
@State var position = MapCameraPosition.automatic
@State var isEditingSettings = false
@State var selectedPosition: PositionEntity?
@State var showWaypoints = false
@State var showWaypoints = true
@State var editingWaypoint: WaypointEntity?
@State var selectedWaypoint: WaypointEntity?
@State var newWaypointCoord: CLLocationCoordinate2D?
@State var isMeshMap = true
@FetchRequest(fetchRequest: PositionEntity.allPositionsFetchRequest(), animation: .none)
var positions: FetchedResults<PositionEntity>
@FetchRequest(fetchRequest: WaypointEntity.allWaypointssFetchRequest(), animation: .none)
var waypoints: FetchedResults<WaypointEntity>
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "name", ascending: true)],
predicate: NSPredicate(format: "enabled == true", ""), animation: .none)
@ -59,7 +54,7 @@ struct MeshMap: View {
ZStack {
MapReader { reader in
Map(position: $position, bounds: MapCameraBounds(minimumDistance: 1, maximumDistance: .infinity), scope: mapScope) {
MeshMapContent(positions: Array(positions), waypoints: Array(waypoints), routes: Array(routes), showUserLocation: $showUserLocation, showNodeHistory: $showNodeHistory, showRouteLines: $showRouteLines, showConvexHull: $showConvexHull, showTraffic: $showTraffic, showPointsOfInterest: $showPointsOfInterest, selectedMapLayer: $selectedMapLayer, selectedPosition: $selectedPosition, showWaypoints: $showWaypoints, selectedWaypoint: $selectedWaypoint)
MeshMapContent(routes: Array(routes), showUserLocation: $showUserLocation, showNodeHistory: $showNodeHistory, showRouteLines: $showRouteLines, showConvexHull: $showConvexHull, showTraffic: $showTraffic, showPointsOfInterest: $showPointsOfInterest, selectedMapLayer: $selectedMapLayer, selectedPosition: $selectedPosition, showWaypoints: $showWaypoints, selectedWaypoint: $selectedWaypoint)
}
.mapScope(mapScope)
@ -142,12 +137,12 @@ struct MeshMap: View {
print("Waypoint id not found")
return
}
guard let waypoint = waypoints.first(where: { $0.id == Int64(waypointId) }) else {
print("Waypoint not found")
return
}
// guard let waypoint = waypoints.first(where: { $0.id == Int64(waypointId) }) else {
// print("Waypoint not found")
// return
// }
showWaypoints = true
position = .camera(MapCamera(centerCoordinate: waypoint.coordinate, distance: 1000, heading: 0, pitch: 60))
//position = .camera(MapCamera(centerCoordinate: waypoint.coordinate, distance: 1000, heading: 0, pitch: 60))
}
}
.onChange(of: (selectedMapLayer)) { newMapLayer in
@ -179,26 +174,25 @@ struct MeshMap: View {
.foregroundColor(.accentColor)
.buttonStyle(.borderedProminent)
/// Show / Hide Waypoints Button
if waypoints.count > 0 {
Button(action: {
withAnimation {
showWaypoints = !showWaypoints
}
}) {
Image(systemName: showWaypoints ? "signpost.right.and.left.fill" : "signpost.right.and.left")
.padding(.vertical, 5)
Button(action: {
withAnimation {
showWaypoints = !showWaypoints
}
.tint(Color(UIColor.secondarySystemBackground))
.foregroundColor(.accentColor)
.buttonStyle(.borderedProminent)
}) {
Image(systemName: showWaypoints ? "signpost.right.and.left.fill" : "signpost.right.and.left")
.padding(.vertical, 5)
}
.tint(Color(UIColor.secondarySystemBackground))
.foregroundColor(.accentColor)
.buttonStyle(.borderedProminent)
}
.controlSize(.regular)
.padding(5)
}
}
.navigationTitle("\(positions.count) Nodes")
.navigationTitle("Mesh Map")
.navigationBarItems(leading: MeshtasticLogo(), trailing: ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?")
})

View file

@ -159,6 +159,25 @@ struct NodeList: View {
Text("Any missed messages will be delivered again.")
}
}
.safeAreaInset(edge: .bottom, alignment: .trailing) {
HStack {
Button(action: {
withAnimation {
//isEditingSettings = !isEditingSettings
}
}) {
Image(systemName: true ? "line.3.horizontal.decrease.circle" : "line.3.horizontal.decrease.circle.fill")
.padding(.vertical, 5)
}
.tint(Color(UIColor.secondarySystemBackground))
.foregroundColor(.accentColor)
.buttonStyle(.borderedProminent)
}
.controlSize(.regular)
.padding(5)
}
.padding(.bottom, 5)
.searchable(text: $searchState.searchText, placement: nodes.count > 10 ? .navigationBarDrawer(displayMode: .always) : .automatic, prompt: "Find a node")
.disableAutocorrection(true)
.scrollDismissesKeyboard(.immediately)
@ -220,7 +239,7 @@ struct NodeList: View {
name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?", phoneOnly: true)
})
}
.padding(.bottom, 5)
} else {
if #available (iOS 17, *) {
ContentUnavailableView("select.node", systemImage: "flipphone")

View file

@ -72,6 +72,10 @@ struct PositionConfig: View {
/// walking speeds are likely to be error prone like the compass
@State var includeHeading = false
/// Minimum Version for fixed postion admin messages
@State var minimumVersion = "2.3.3"
@State private var supportedVersion = true
var body: some View {
VStack {
Form {
@ -159,6 +163,15 @@ struct PositionConfig: View {
Text("If enabled your current phone location will be sent to the device and will broadcast over the mesh on the position interval. Fixed position will always use the most recent position the device has.")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
.onChange(of: fixedPosition) { newFixed in
if node != nil && node!.positionConfig != nil {
if newFixed != node!.positionConfig!.fixedPosition { hasChanges = true }
}
if supportedVersion && hasChanges && !newFixed {
// Send Admin message to remove the fixed position
}
}
}
}
@ -316,6 +329,9 @@ struct PositionConfig: View {
self.bleManager.context = context
}
setPositionValues()
supportedVersion = bleManager.connectedVersion == "0.0.0" || self.minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedSame
// Need to request a PositionConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.positionConfig == nil {
print("empty position config")
@ -355,11 +371,6 @@ struct PositionConfig: View {
if newSmartPositionEnabled != node!.positionConfig!.smartPositionEnabled { hasChanges = true }
}
}
.onChange(of: fixedPosition) { newFixed in
if node != nil && node!.positionConfig != nil {
if newFixed != node!.positionConfig!.fixedPosition { hasChanges = true }
}
}
.onChange(of: positionBroadcastSeconds) { newPositionBroadcastSeconds in
if node != nil && node!.positionConfig != nil {
if newPositionBroadcastSeconds != node!.positionConfig!.positionBroadcastSeconds { hasChanges = true }

View file

@ -12,7 +12,7 @@ struct Firmware: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
var node: NodeInfoEntity?
@State var minimumVersion = "2.3.0"
@State var minimumVersion = "2.3.2"
@State var version = ""
@State private var currentDevice: DeviceHardware?
@State private var latestStable: FirmwareRelease?