From bbe10d7d28d9225e0d3494fb1c73976cb1eec884 Mon Sep 17 00:00:00 2001 From: Justin Oros Date: Mon, 5 May 2025 17:49:07 -0700 Subject: [PATCH] Added comments. Added comments for easier understanding. --- Speedo/LocationManager.swift | 71 ++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/Speedo/LocationManager.swift b/Speedo/LocationManager.swift index 92b2eb5..d23ae5e 100644 --- a/Speedo/LocationManager.swift +++ b/Speedo/LocationManager.swift @@ -7,38 +7,62 @@ import Foundation import CoreLocation -import SwiftUI // Import SwiftUI for Alert +import SwiftUI +/// A class responsible for managing and publishing location and speed updates. class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { + + /// The underlying Core Location manager instance. private let manager = CLLocationManager() - @Published var speed: Int = 0 // MPH as whole number + // MARK: - Published Properties (UI-bound) + + /// Current speed in MPH (calculated from CLLocation speed). + @Published var speed: Int = 0 + + /// Most recent known location. @Published var location: CLLocation? + + /// Horizontal accuracy in meters. @Published var accuracy: Double = 0.0 + + /// Current authorization status. @Published var authorizationStatus: CLAuthorizationStatus = .notDetermined + + /// Flag to show alert when location permissions are problematic. @Published var showAlert = false + + /// Message to display in the alert. @Published var alertMessage = "" + // MARK: - Initialization + override init() { super.init() manager.delegate = self manager.activityType = .automotiveNavigation manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation - manager.distanceFilter = 1 // Update on movement of 1 meter + manager.distanceFilter = 1 // Update for every meter moved + print("LocationManager initialized") - requestAuthorization() // Request authorization in init - startUpdatingLocationIfNeeded() // Start updates if already authorized + + requestAuthorization() + startUpdatingLocationIfNeeded() } + // MARK: - Authorization + + /// Requests location permission from the user. private func requestAuthorization() { print("Requesting location authorization") - manager.requestAlwaysAuthorization() // Request "Always" permission + manager.requestWhenInUseAuthorization() } + /// Starts updating location only if authorization is granted. private func startUpdatingLocationIfNeeded() { if authorizationStatus == .authorizedAlways || authorizationStatus == .authorizedWhenInUse { print("Attempting to start location updates") - manager.startUpdatingLocation() // Start receiving location updates + manager.startUpdatingLocation() } else if authorizationStatus == .denied || authorizationStatus == .restricted { print("Location updates not started due to denied/restricted authorization") DispatchQueue.main.async { @@ -46,17 +70,20 @@ class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { self.alertMessage = "Location services are disabled. Please enable them in Settings." } } else { - print("Authorization not yet determined, or other status: \(authorizationStatus)") + print("Authorization not yet determined: \(authorizationStatus.rawValue)") } } - func locationManagerDidChangeAuthorization(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + /// Called whenever the app's location authorization status changes. + func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { + let status = manager.authorizationStatus DispatchQueue.main.async { self.authorizationStatus = status - print("Authorization status changed: \(status)") - self.startUpdatingLocationIfNeeded() // Check and start updates on authorization change + print("Authorization status changed: \(status.rawValue)") + self.startUpdatingLocationIfNeeded() } + // Handle alert messaging for denied or restricted access switch status { case .authorizedAlways: print("Location authorization: Authorized Always") @@ -76,35 +103,41 @@ class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { } case .notDetermined: print("Location authorization: Not Determined") - // Authorization request will be triggered in init - break @unknown default: print("Location authorization: Unknown status") } } + // MARK: - Location Updates + + /// Called whenever new location data is available. func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let latest = locations.last else { - print("No latest location found in didUpdateLocations") + print("No latest location found") return } - // Debugging output - print("New location received: \(latest.coordinate.latitude), \(latest.coordinate.longitude)") + // Logging raw location data for debugging + print("New location: \(latest.coordinate.latitude), \(latest.coordinate.longitude)") print("Speed (m/s): \(latest.speed)") print("Speed (MPH): \(latest.speed * 2.23694)") print("Accuracy: \(latest.horizontalAccuracy)") DispatchQueue.main.async { - // Update speed - let rawSpeed = max(latest.speed, 0) // Avoid negative values - let mph = rawSpeed * 2.23694 // Convert m/s to MPH + // Ensure speed is non-negative (as negative = invalid) + let rawSpeed = max(latest.speed, 0) + + // Convert from meters per second to MPH + let mph = rawSpeed * 2.23694 + + // Update published properties to refresh UI self.speed = Int(mph.rounded()) self.location = latest self.accuracy = latest.horizontalAccuracy } } + /// Called when location updates fail. func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("Location update failed: \(error.localizedDescription)") DispatchQueue.main.async {