Files
Reflect/Shared/Services/LocationManager.swift
Trey t 31fb2a7fe2 Add weather feature with WeatherKit integration for mood entries
Fetch and display weather data (temp, condition, hi/lo, humidity) when
users log a mood. Weather is stored as JSON on MoodEntryModel and shown
as a card in EntryDetailView. Premium-gated with location permission
prompt. Includes BGTask retry for failed fetches and full analytics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 00:16:26 -05:00

72 lines
2.1 KiB
Swift

//
// LocationManager.swift
// Reflect
//
// CoreLocation wrapper with async/await for one-shot location requests.
//
import CoreLocation
import os.log
@MainActor
final class LocationManager: NSObject {
static let shared = LocationManager()
private static let logger = Logger(
subsystem: Bundle.main.bundleIdentifier ?? "com.88oakapps.reflect",
category: "LocationManager"
)
private let manager = CLLocationManager()
private var locationContinuation: CheckedContinuation<CLLocation, Error>?
var authorizationStatus: CLAuthorizationStatus {
manager.authorizationStatus
}
private override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyKilometer
}
func requestAuthorization() {
manager.requestWhenInUseAuthorization()
}
var currentLocation: CLLocation {
get async throws {
// Return last known location if recent enough (within 10 minutes)
if let last = manager.location,
abs(last.timestamp.timeIntervalSinceNow) < 600 {
return last
}
return try await withCheckedThrowingContinuation { continuation in
self.locationContinuation = continuation
self.manager.requestLocation()
}
}
}
}
// MARK: - CLLocationManagerDelegate
extension LocationManager: CLLocationManagerDelegate {
nonisolated func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
Task { @MainActor in
guard let location = locations.first else { return }
locationContinuation?.resume(returning: location)
locationContinuation = nil
}
}
nonisolated func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
Task { @MainActor in
Self.logger.error("Location request failed: \(error.localizedDescription)")
locationContinuation?.resume(throwing: error)
locationContinuation = nil
}
}
}