mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Make current location nilable, remove log spam
This commit is contained in:
parent
fe17333ac8
commit
90dd5b2141
7 changed files with 91 additions and 129 deletions
|
|
@ -15976,22 +15976,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Generated from your private key and sent to other nodes on the mesh so they can compute a shared secret key." : {
|
||||
"localizations" : {
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "秘密キーから生成され、メッシュ上の他のノードに送信されて、共有秘密キーの計算を可能にします。"
|
||||
}
|
||||
},
|
||||
"sr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Генерисано из твог приватног кључа и послато другим чворовима на мрежи како би им омогућило да израчунају заједнички тајни кључ.\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Get custom waterproof solar and detection sensor router nodes, aluminium desktop nodes and rugged handsets." : {
|
||||
"localizations" : {
|
||||
"it" : {
|
||||
|
|
@ -42335,6 +42319,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Your public key is generated from your private key and sent to other nodes on the mesh so they can compute a shared secret key with you." : {
|
||||
|
||||
},
|
||||
"Your region has a %lld%% duty cycle. MQTT is not advised when you are duty cycle restricted, the extra traffic will quickly overwhelm your LoRa mesh." : {
|
||||
"localizations" : {
|
||||
|
|
@ -42428,4 +42415,4 @@
|
|||
}
|
||||
},
|
||||
"version" : "1.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -21,27 +21,27 @@ extension PositionEntity {
|
|||
request.returnsDistinctResults = true
|
||||
request.sortDescriptors = [NSSortDescriptor(key: "time", ascending: false)]
|
||||
let positionPredicate = NSPredicate(format: "nodePosition != nil && (nodePosition.user.shortName != nil || nodePosition.user.shortName != '') && latest == true")
|
||||
|
||||
let pointOfInterest = LocationsHandler.currentLocation
|
||||
|
||||
if pointOfInterest.latitude != LocationsHandler.DefaultLocation.latitude && pointOfInterest.longitude != LocationsHandler.DefaultLocation.longitude {
|
||||
let d: Double = UserDefaults.meshMapDistance * 1.1
|
||||
let r: Double = 6371009
|
||||
let meanLatitidue = pointOfInterest.latitude * .pi / 180
|
||||
let deltaLatitude = d / r * 180 / .pi
|
||||
let deltaLongitude = d / (r * cos(meanLatitidue)) * 180 / .pi
|
||||
let minLatitude: Double = pointOfInterest.latitude - deltaLatitude
|
||||
let maxLatitude: Double = pointOfInterest.latitude + deltaLatitude
|
||||
let minLongitude: Double = pointOfInterest.longitude - deltaLongitude
|
||||
let maxLongitude: Double = pointOfInterest.longitude + deltaLongitude
|
||||
let distancePredicate = NSPredicate(format: "(%lf <= (longitudeI / 1e7)) AND ((longitudeI / 1e7) <= %lf) AND (%lf <= (latitudeI / 1e7)) AND ((latitudeI / 1e7) <= %lf)", minLongitude, maxLongitude, minLatitude, maxLatitude)
|
||||
request.predicate = NSCompoundPredicate(type: .and, subpredicates: [positionPredicate, distancePredicate])
|
||||
} else {
|
||||
request.predicate = positionPredicate
|
||||
|
||||
if let pointOfInterest = LocationsHandler.currentLocation {
|
||||
|
||||
if pointOfInterest.latitude != LocationsHandler.DefaultLocation.latitude && pointOfInterest.longitude != LocationsHandler.DefaultLocation.longitude {
|
||||
let d: Double = UserDefaults.meshMapDistance * 1.1
|
||||
let r: Double = 6371009
|
||||
let meanLatitidue = pointOfInterest.latitude * .pi / 180
|
||||
let deltaLatitude = d / r * 180 / .pi
|
||||
let deltaLongitude = d / (r * cos(meanLatitidue)) * 180 / .pi
|
||||
let minLatitude: Double = pointOfInterest.latitude - deltaLatitude
|
||||
let maxLatitude: Double = pointOfInterest.latitude + deltaLatitude
|
||||
let minLongitude: Double = pointOfInterest.longitude - deltaLongitude
|
||||
let maxLongitude: Double = pointOfInterest.longitude + deltaLongitude
|
||||
let distancePredicate = NSPredicate(format: "(%lf <= (longitudeI / 1e7)) AND ((longitudeI / 1e7) <= %lf) AND (%lf <= (latitudeI / 1e7)) AND ((latitudeI / 1e7) <= %lf)", minLongitude, maxLongitude, minLatitude, maxLatitude)
|
||||
request.predicate = NSCompoundPredicate(type: .and, subpredicates: [positionPredicate, distancePredicate])
|
||||
} else {
|
||||
request.predicate = positionPredicate
|
||||
}
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
var latitude: Double? {
|
||||
|
||||
let d = Double(latitudeI)
|
||||
|
|
|
|||
|
|
@ -220,50 +220,18 @@ import OSLog
|
|||
// If not recording, only keep the latest location.
|
||||
locationsArray = [location]
|
||||
}
|
||||
// Store the last known location in UserDefaults for persistence.
|
||||
UserDefaults.standard.set(location.coordinate.latitude, forKey: "lastKnownLatitude")
|
||||
UserDefaults.standard.set(location.coordinate.longitude, forKey: "lastKnownLongitude")
|
||||
UserDefaults.standard.set(Date().timeIntervalSince1970, forKey: "lastKnownLocationTimestamp")
|
||||
return true
|
||||
}
|
||||
// Default location (Apple Park) used as a fallback.
|
||||
// nonisolated because it is never mutated
|
||||
nonisolated static let DefaultLocation = CLLocationCoordinate2D(latitude: 37.3346, longitude: -122.0090)
|
||||
/// Provides the current location, falling back to last known or a default if necessary.
|
||||
static var currentLocation: CLLocationCoordinate2D {
|
||||
static var currentLocation: CLLocationCoordinate2D? {
|
||||
// Attempt to get the most recent location from the manager.
|
||||
if let location = shared.manager.location {
|
||||
return location.coordinate
|
||||
} else {
|
||||
// If manager.location is nil, check authorization status and potentially request.
|
||||
let status = shared.manager.authorizationStatus
|
||||
switch status {
|
||||
case .notDetermined:
|
||||
Logger.services.info("📍 [App] Location permission not determined, requesting authorization (WhenInUse)")
|
||||
// Requesting WhenInUse authorization here. For "Always" authorization,
|
||||
// `requestLocationAlwaysPermissions()` should be called explicitly,
|
||||
// typically from a user action or app setup.
|
||||
shared.manager.requestWhenInUseAuthorization()
|
||||
case .denied, .restricted:
|
||||
Logger.services.warning("📍 [App] Location access denied or restricted. Please enable location services in Settings to get accurate positioning!")
|
||||
// Requesting WhenInUse authorization again, though user interaction is needed for denied/restricted.
|
||||
shared.manager.requestWhenInUseAuthorization()
|
||||
default:
|
||||
break // For .authorizedAlways, .authorizedWhenInUse, .limited
|
||||
}
|
||||
// Fallback 1: Last known location from UserDefaults if it's recent (within 4 hours).
|
||||
if let lat = UserDefaults.standard.object(forKey: "lastKnownLatitude") as? Double,
|
||||
let lon = UserDefaults.standard.object(forKey: "lastKnownLongitude") as? Double,
|
||||
let timestamp = UserDefaults.standard.object(forKey: "lastKnownLocationTimestamp") as? Double,
|
||||
lat >= -90 && lat <= 90, // Validate latitude
|
||||
lon >= -180 && lon <= 180, // Validate longitude
|
||||
Date().timeIntervalSince1970 - timestamp <= 14_400 { // 4 hours in seconds
|
||||
Logger.services.info("📍 [App] Falling back to last known location (age: \(Int(Date().timeIntervalSince1970 - timestamp)) seconds)")
|
||||
return CLLocationCoordinate2D(latitude: lat, longitude: lon)
|
||||
}
|
||||
// Fallback 2: Default location if no other location is available.
|
||||
Logger.services.warning("📍 [App] No Location and no last known location, check your location settings. Falling back to default location.")
|
||||
return DefaultLocation
|
||||
return nil
|
||||
}
|
||||
}
|
||||
/// Estimates the number of satellites in view based on horizontal and vertical accuracy.
|
||||
|
|
|
|||
|
|
@ -211,9 +211,12 @@ struct NodeWeatherForecast {
|
|||
|
||||
struct NodeWeatherForecastView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NodeWeatherForecastView(location: CLLocation(latitude: LocationsHandler.currentLocation.latitude, longitude: LocationsHandler.currentLocation.longitude) )
|
||||
.aspectRatio(2, contentMode: .fit)
|
||||
.padding()
|
||||
.previewLayout(.sizeThatFits)
|
||||
|
||||
if let cl = LocationsHandler.currentLocation {
|
||||
NodeWeatherForecastView(location: CLLocation(latitude: cl.latitude, longitude: cl.longitude) )
|
||||
.aspectRatio(2, contentMode: .fit)
|
||||
.padding()
|
||||
.previewLayout(.sizeThatFits)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -290,19 +290,20 @@ fileprivate extension NodeFilterParameters {
|
|||
}
|
||||
// Distance
|
||||
if distanceFilter {
|
||||
let pointOfInterest = LocationsHandler.currentLocation
|
||||
if pointOfInterest.latitude != LocationsHandler.DefaultLocation.latitude && pointOfInterest.longitude != LocationsHandler.DefaultLocation.longitude {
|
||||
let d: Double = maxDistance * 1.1
|
||||
let r: Double = 6371009
|
||||
let meanLatitidue = pointOfInterest.latitude * .pi / 180
|
||||
let deltaLatitude = d / r * 180 / .pi
|
||||
let deltaLongitude = d / (r * cos(meanLatitidue)) * 180 / .pi
|
||||
let minLatitude: Double = pointOfInterest.latitude - deltaLatitude
|
||||
let maxLatitude: Double = pointOfInterest.latitude + deltaLatitude
|
||||
let minLongitude: Double = pointOfInterest.longitude - deltaLongitude
|
||||
let maxLongitude: Double = pointOfInterest.longitude + deltaLongitude
|
||||
let distancePredicate = NSPredicate(format: "(SUBQUERY(userNode.positions, $position, $position.latest == TRUE && (%lf <= ($position.longitudeI / 1e7)) AND (($position.longitudeI / 1e7) <= %lf) AND (%lf <= ($position.latitudeI / 1e7)) AND (($position.latitudeI / 1e7) <= %lf))).@count > 0", minLongitude, maxLongitude, minLatitude, maxLatitude)
|
||||
predicates.append(distancePredicate)
|
||||
if let pointOfInterest = LocationsHandler.currentLocation {
|
||||
if pointOfInterest.latitude != LocationsHandler.DefaultLocation.latitude && pointOfInterest.longitude != LocationsHandler.DefaultLocation.longitude {
|
||||
let d: Double = maxDistance * 1.1
|
||||
let r: Double = 6371009
|
||||
let meanLatitidue = pointOfInterest.latitude * .pi / 180
|
||||
let deltaLatitude = d / r * 180 / .pi
|
||||
let deltaLongitude = d / (r * cos(meanLatitidue)) * 180 / .pi
|
||||
let minLatitude: Double = pointOfInterest.latitude - deltaLatitude
|
||||
let maxLatitude: Double = pointOfInterest.latitude + deltaLatitude
|
||||
let minLongitude: Double = pointOfInterest.longitude - deltaLongitude
|
||||
let maxLongitude: Double = pointOfInterest.longitude + deltaLongitude
|
||||
let distancePredicate = NSPredicate(format: "(SUBQUERY(userNode.positions, $position, $position.latest == TRUE && (%lf <= ($position.longitudeI / 1e7)) AND (($position.longitudeI / 1e7) <= %lf) AND (%lf <= ($position.latitudeI / 1e7)) AND (($position.latitudeI / 1e7) <= %lf))).@count > 0", minLongitude, maxLongitude, minLatitude, maxLatitude)
|
||||
predicates.append(distancePredicate)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Always apply unmessagable and connected node filters
|
||||
|
|
|
|||
|
|
@ -40,21 +40,21 @@ struct WaypointForm: View {
|
|||
.font(.largeTitle)
|
||||
Divider()
|
||||
Form {
|
||||
let distance = CLLocation(latitude: LocationsHandler.currentLocation.latitude, longitude: LocationsHandler.currentLocation.longitude).distance(from: CLLocation(latitude: waypoint.coordinate.latitude, longitude: waypoint.coordinate.longitude ))
|
||||
Section(header: Text("Coordinate") ) {
|
||||
HStack {
|
||||
Text("Location:")
|
||||
.foregroundColor(.secondary)
|
||||
Text("\(String(format: "%.5f", waypoint.coordinate.latitude) + "," + String(format: "%.5f", waypoint.coordinate.longitude))")
|
||||
.textSelection(.enabled)
|
||||
.foregroundColor(.secondary)
|
||||
.font(.caption)
|
||||
|
||||
}
|
||||
if let cl = LocationsHandler.currentLocation {
|
||||
let distance = CLLocation(latitude: cl.latitude, longitude: cl.longitude).distance(from: CLLocation(latitude: waypoint.coordinate.latitude, longitude: waypoint.coordinate.longitude ))
|
||||
Section(header: Text("Coordinate") ) {
|
||||
HStack {
|
||||
Text("Location:")
|
||||
.foregroundColor(.secondary)
|
||||
Text("\(String(format: "%.5f", waypoint.coordinate.latitude) + "," + String(format: "%.5f", waypoint.coordinate.longitude))")
|
||||
.textSelection(.enabled)
|
||||
.foregroundColor(.secondary)
|
||||
.font(.caption)
|
||||
|
||||
}
|
||||
Button {
|
||||
let currentLoc = LocationsHandler.currentLocation
|
||||
waypoint.coordinate.longitude = currentLoc.longitude
|
||||
waypoint.coordinate.latitude = currentLoc.latitude
|
||||
waypoint.coordinate.longitude = cl.longitude
|
||||
waypoint.coordinate.latitude = cl.latitude
|
||||
} label: {
|
||||
HStack {
|
||||
Text("Use my Location")
|
||||
|
|
@ -62,10 +62,11 @@ struct WaypointForm: View {
|
|||
}
|
||||
}
|
||||
.accessibilityLabel("Set to current location")
|
||||
HStack {
|
||||
if waypoint.coordinate.latitude != 0 && waypoint.coordinate.longitude != 0 {
|
||||
DistanceText(meters: distance)
|
||||
.foregroundColor(Color.gray)
|
||||
HStack {
|
||||
if waypoint.coordinate.latitude != 0 && waypoint.coordinate.longitude != 0 {
|
||||
DistanceText(meters: distance)
|
||||
.foregroundColor(Color.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -374,17 +375,19 @@ struct WaypointForm: View {
|
|||
.padding(.bottom, 5)
|
||||
}
|
||||
/// Distance
|
||||
if LocationsHandler.currentLocation.distance(from: LocationsHandler.DefaultLocation) > 0.0 {
|
||||
let metersAway = waypoint.coordinate.distance(from: LocationsHandler.currentLocation)
|
||||
Label {
|
||||
Text("Distance".localized + ": \(distanceFormatter.string(fromDistance: Double(metersAway)))")
|
||||
.foregroundColor(.primary)
|
||||
} icon: {
|
||||
Image(systemName: "lines.measurement.horizontal")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.frame(width: 35)
|
||||
if let cl = LocationsHandler.currentLocation {
|
||||
if cl.distance(from: cl) > 0.0 {
|
||||
let metersAway = waypoint.coordinate.distance(from: cl)
|
||||
Label {
|
||||
Text("Distance".localized + ": \(distanceFormatter.string(fromDistance: Double(metersAway)))")
|
||||
.foregroundColor(.primary)
|
||||
} icon: {
|
||||
Image(systemName: "lines.measurement.horizontal")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.frame(width: 35)
|
||||
}
|
||||
.padding(.bottom, 5)
|
||||
}
|
||||
.padding(.bottom, 5)
|
||||
}
|
||||
}
|
||||
.padding(.top)
|
||||
|
|
|
|||
|
|
@ -341,23 +341,23 @@ fileprivate extension NodeFilterParameters {
|
|||
|
||||
// Distance filter
|
||||
if distanceFilter {
|
||||
let pointOfInterest = LocationsHandler.currentLocation
|
||||
|
||||
if pointOfInterest.latitude != LocationsHandler.DefaultLocation.latitude && pointOfInterest.longitude != LocationsHandler.DefaultLocation.longitude {
|
||||
let d: Double = maxDistance * 1.1
|
||||
let r: Double = 6371009
|
||||
let meanLatitidue = pointOfInterest.latitude * .pi / 180
|
||||
let deltaLatitude = d / r * 180 / .pi
|
||||
let deltaLongitude = d / (r * cos(meanLatitidue)) * 180 / .pi
|
||||
let minLatitude: Double = pointOfInterest.latitude - deltaLatitude
|
||||
let maxLatitude: Double = pointOfInterest.latitude + deltaLatitude
|
||||
let minLongitude: Double = pointOfInterest.longitude - deltaLongitude
|
||||
let maxLongitude: Double = pointOfInterest.longitude + deltaLongitude
|
||||
let distancePredicate = NSPredicate(format: "(SUBQUERY(positions, $position, $position.latest == TRUE && (%lf <= ($position.longitudeI / 1e7)) AND (($position.longitudeI / 1e7) <= %lf) AND (%lf <= ($position.latitudeI / 1e7)) AND (($position.latitudeI / 1e7) <= %lf))).@count > 0", minLongitude, maxLongitude, minLatitude, maxLatitude)
|
||||
predicates.append(distancePredicate)
|
||||
if let pointOfInterest = LocationsHandler.currentLocation {
|
||||
|
||||
if pointOfInterest.latitude != LocationsHandler.DefaultLocation.latitude && pointOfInterest.longitude != LocationsHandler.DefaultLocation.longitude {
|
||||
let d: Double = maxDistance * 1.1
|
||||
let r: Double = 6371009
|
||||
let meanLatitidue = pointOfInterest.latitude * .pi / 180
|
||||
let deltaLatitude = d / r * 180 / .pi
|
||||
let deltaLongitude = d / (r * cos(meanLatitidue)) * 180 / .pi
|
||||
let minLatitude: Double = pointOfInterest.latitude - deltaLatitude
|
||||
let maxLatitude: Double = pointOfInterest.latitude + deltaLatitude
|
||||
let minLongitude: Double = pointOfInterest.longitude - deltaLongitude
|
||||
let maxLongitude: Double = pointOfInterest.longitude + deltaLongitude
|
||||
let distancePredicate = NSPredicate(format: "(SUBQUERY(positions, $position, $position.latest == TRUE && (%lf <= ($position.longitudeI / 1e7)) AND (($position.longitudeI / 1e7) <= %lf) AND (%lf <= ($position.latitudeI / 1e7)) AND (($position.latitudeI / 1e7) <= %lf))).@count > 0", minLongitude, maxLongitude, minLatitude, maxLatitude)
|
||||
predicates.append(distancePredicate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return predicates.isEmpty ? nil : NSCompoundPredicate(type: .and, subpredicates: predicates)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue