diff --git a/Meshtastic/Enums/AppSettingsEnums.swift b/Meshtastic/Enums/AppSettingsEnums.swift index dd0a94ed..fd4fe088 100644 --- a/Meshtastic/Enums/AppSettingsEnums.swift +++ b/Meshtastic/Enums/AppSettingsEnums.swift @@ -50,6 +50,20 @@ enum MeshMapTypes: Int, CaseIterable, Identifiable { } } +enum MeshMapDistances: Double, CaseIterable, Identifiable { + case fiftyMiles = 80467.2 + case oneHundredMiles = 160934 + case twoHundredMiles = 321869 + case fiveHundredMiles = 804672 + case oneThousandMiles = 1609000 + case twoThousandMiles = 3218688 + var id: Double { self.rawValue } + var description: String { + let distanceFormatter = MKDistanceFormatter() + return "\(distanceFormatter.string(fromDistance: Double(self.rawValue))) away" + } +} + enum UserTrackingModes: Int, CaseIterable, Identifiable { case none = 0 case follow = 1 diff --git a/Meshtastic/Extensions/CoreData/PositionEntityExtension.swift b/Meshtastic/Extensions/CoreData/PositionEntityExtension.swift index 5d5e2fa5..44777bb3 100644 --- a/Meshtastic/Extensions/CoreData/PositionEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/PositionEntityExtension.swift @@ -21,13 +21,13 @@ extension PositionEntity { request.returnsDistinctResults = true request.sortDescriptors = [NSSortDescriptor(key: "time", ascending: false)] - let positionPredicate = NSPredicate(format: "nodePosition != nil && nodePosition.user.shortName != nil && latest == true && time >= %@", Calendar.current.date(byAdding: .day, value: -2, to: Date())! as NSDate) + let positionPredicate = NSPredicate(format: "nodePosition != nil && (nodePosition.user.shortName != nil || nodePosition.user.shortName != '') && latest == true && time >= %@", Calendar.current.date(byAdding: .day, value: -2, to: Date())! as NSDate) let pointOfInterest = LocationHelper.currentLocation if pointOfInterest.latitude != LocationHelper.DefaultLocation.latitude && pointOfInterest.longitude != LocationHelper.DefaultLocation.longitude { /// Lets just get nodes within about 500 miles - let D: Double = 800000 * 1.1 + let D: Double = UserDefaults.meshMapDistance * 1.1 let R: Double = 6371009 let meanLatitidue = pointOfInterest.latitude * .pi / 180 let deltaLatitude = D / R * 180 / .pi diff --git a/Meshtastic/Extensions/String.swift b/Meshtastic/Extensions/String.swift index 6ac1672a..6255b151 100644 --- a/Meshtastic/Extensions/String.swift +++ b/Meshtastic/Extensions/String.swift @@ -67,4 +67,29 @@ extension String { : $0 + String($1) } } + + var length: Int { + return count + } + + subscript (i: Int) -> String { + return self[i ..< i + 1] + } + + func substring(fromIndex: Int) -> String { + return self[min(fromIndex, length) ..< length] + } + + func substring(toIndex: Int) -> String { + return self[0 ..< max(0, toIndex)] + } + + subscript (r: Range) -> String { + let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)), + upper: min(length, max(0, r.upperBound)))) + let start = index(startIndex, offsetBy: range.lowerBound) + let end = index(start, offsetBy: range.upperBound - range.lowerBound) + return String(self[start ..< end]) + } + } diff --git a/Meshtastic/Extensions/UserDefaults.swift b/Meshtastic/Extensions/UserDefaults.swift index c42ee9bc..b497495d 100644 --- a/Meshtastic/Extensions/UserDefaults.swift +++ b/Meshtastic/Extensions/UserDefaults.swift @@ -34,6 +34,7 @@ extension UserDefaults { case provideLocation case provideLocationInterval case mapLayer + case meshMapDistance case meshMapRecentering case meshMapShowNodeHistory case meshMapShowRouteLines @@ -76,6 +77,9 @@ extension UserDefaults { @UserDefault(.mapLayer, defaultValue: .standard) static var mapLayer: MapLayer + @UserDefault(.meshMapDistance, defaultValue: 800000) + static var meshMapDistance: Double + @UserDefault(.enableMapRecentering, defaultValue: false) static var enableMapRecentering: Bool diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index e89aeb82..2e1e31cf 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -15,7 +15,7 @@ import ActivityKit func generateMessageMarkdown (message: String) -> String { let types: NSTextCheckingResult.CheckingType = [.address, .link, .phoneNumber] let detector = try! NSDataDetector(types: types.rawValue) - let matches = detector.matches(in: message, options: [], range: NSRange(location: 0, length: message.utf16.count)) + let matches = detector.matches(in: message, options: [], range: NSRange(location: 0, length: message.utf8.count)) var messageWithMarkdown = message if matches.count > 0 { for match in matches { @@ -28,9 +28,14 @@ func generateMessageMarkdown (message: String) -> String { let phone = messageWithMarkdown[range] messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: phone, with: "[\(phone)](tel:\(phone))") } else if match.resultType == .link { - let url = messageWithMarkdown[range] - let absoluteUrl = match.url?.absoluteString ?? "" - messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: url, with: "[\(String(match.url?.host ?? "Link"))\(String(match.url?.path ?? ""))](\(absoluteUrl))") + let start = match.range.lowerBound + let stop = match.range.upperBound + if stop > start { + let url = message[start ..< stop] + let absoluteUrl = match.url?.absoluteString ?? "" + let markdownUrl = "[\(url)](\(absoluteUrl))" + messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: url, with: markdownUrl) + } } } } diff --git a/Meshtastic/Views/Nodes/Helpers/Map/MapSettingsForm.swift b/Meshtastic/Views/Nodes/Helpers/Map/MapSettingsForm.swift index 4c18ef19..55b11484 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/MapSettingsForm.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/MapSettingsForm.swift @@ -19,6 +19,7 @@ struct MapSettingsForm: View { @Binding var traffic: Bool @Binding var pointsOfInterest: Bool @Binding var mapLayer: MapLayer + @Binding var meshMapDistance: Double @Binding var meshMap: Bool var body: some View { @@ -56,6 +57,27 @@ struct MapSettingsForm: View { self.routeLines.toggle() UserDefaults.enableMapRouteLines = self.routeLines } + } else { + VStack { + HStack { + Label("Show nodes up to", 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@*/) + } + .onChange(of: meshMapDistance) { newMeshMapDistance in + UserDefaults.meshMapDistance = newMeshMapDistance + } } Toggle(isOn: $convexHull) { Label("Convex Hull", systemImage: "button.angledbottom.horizontal.right") diff --git a/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift b/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift index cf6d90e3..3f2fb0fb 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift @@ -20,6 +20,7 @@ struct NodeMapSwiftUI: View { @State var showUserLocation: Bool = false @State var positions: [PositionEntity] = [] /// Map State User Defaults + @AppStorage("meshMapDistance") private var meshMapDistance: Double = 800000 @AppStorage("meshMapShowNodeHistory") private var showNodeHistory = false @AppStorage("meshMapShowRouteLines") private var showRouteLines = false @AppStorage("enableMapConvexHull") private var showConvexHull = false @@ -92,7 +93,7 @@ struct NodeMapSwiftUI: View { .padding() } .sheet(isPresented: $isEditingSettings) { - MapSettingsForm(nodeHistory: $showNodeHistory, routeLines: $showRouteLines, convexHull: $showConvexHull, traffic: $showTraffic, pointsOfInterest: $showPointsOfInterest, mapLayer: $selectedMapLayer, meshMap: $isMeshMap) + MapSettingsForm(nodeHistory: $showNodeHistory, routeLines: $showRouteLines, convexHull: $showConvexHull, traffic: $showTraffic, pointsOfInterest: $showPointsOfInterest, mapLayer: $selectedMapLayer, meshMapDistance: $meshMapDistance, meshMap: $isMeshMap) .onChange(of: (selectedMapLayer)) { newMapLayer in switch selectedMapLayer { case .standard: diff --git a/Meshtastic/Views/Nodes/MeshMap.swift b/Meshtastic/Views/Nodes/MeshMap.swift index d17c24cd..780ebde2 100644 --- a/Meshtastic/Views/Nodes/MeshMap.swift +++ b/Meshtastic/Views/Nodes/MeshMap.swift @@ -24,6 +24,7 @@ struct MeshMap: View { /// Parameters @State var showUserLocation: Bool = true /// Map State User Defaults + @AppStorage("meshMapDistance") private var meshMapDistance: Double = 800000 @AppStorage("meshMapShowNodeHistory") private var showNodeHistory = false @AppStorage("meshMapShowRouteLines") private var showRouteLines = false @AppStorage("enableMapConvexHull") private var showConvexHull = false @@ -32,8 +33,8 @@ struct MeshMap: View { @AppStorage("mapLayer") private var selectedMapLayer: MapLayer = .standard // Map Configuration @Namespace var mapScope - @State var mapStyle: MapStyle = MapStyle.standard(elevation: .flat, emphasis: MapStyle.StandardEmphasis.muted ,pointsOfInterest: .all, showsTraffic: true) - @State var position = MapCameraPosition.camera(MapCamera(centerCoordinate: LocationHelper.currentLocation, distance: 2500000, heading: 0, pitch: 0)) + @State var mapStyle: MapStyle = MapStyle.standard(elevation: .flat, emphasis: MapStyle.StandardEmphasis.muted ,pointsOfInterest: .excludingAll, showsTraffic: false) + @State var position = MapCameraPosition.automatic @State var isEditingSettings = false @State var selectedPosition: PositionEntity? @State var showWaypoints = false @@ -120,7 +121,7 @@ struct MeshMap: View { .padding() } .sheet(isPresented: $isEditingSettings) { - MapSettingsForm(nodeHistory: $showNodeHistory, routeLines: $showRouteLines, convexHull: $showConvexHull, traffic: $showTraffic, pointsOfInterest: $showPointsOfInterest, mapLayer: $selectedMapLayer, meshMap: $isMeshMap) + MapSettingsForm(nodeHistory: $showNodeHistory, routeLines: $showRouteLines, convexHull: $showConvexHull, traffic: $showTraffic, pointsOfInterest: $showPointsOfInterest, mapLayer: $selectedMapLayer, meshMapDistance: $meshMapDistance, meshMap: $isMeshMap) } .onChange(of: (appState.navigationPath)) { newPath in diff --git a/Meshtastic/Views/Settings/Channels/ChannelForm.swift b/Meshtastic/Views/Settings/Channels/ChannelForm.swift index 7176d802..da6127df 100644 --- a/Meshtastic/Views/Settings/Channels/ChannelForm.swift +++ b/Meshtastic/Views/Settings/Channels/ChannelForm.swift @@ -245,7 +245,7 @@ struct ChannelForm: View { } } } - .presentationDetents([.fraction(0.45), .fraction(0.65)]) + .presentationDetents([.large]) .presentationDragIndicator(.visible) } }