// Auteur : Simon-Pierre Boucher — contact@spboucher.ai // LocationManager.swift — position de l'utilisateur (demande « pendant // l'utilisation », mises à jour continues pour le point bleu et l'origine // des itinéraires). import Foundation import CoreLocation @MainActor final class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { @Published var location: CLLocationCoordinate2D? @Published var speedKmh: Double? // vitesse GPS en km/h (nil si inconnue) @Published var course: Double? // cap GPS en degrés vrais (nil si inconnu) @Published var authorized = false private let manager = CLLocationManager() override init() { super.init() manager.delegate = self manager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters } func request() { switch manager.authorizationStatus { case .notDetermined: manager.requestWhenInUseAuthorization() case .authorizedWhenInUse, .authorizedAlways: manager.startUpdatingLocation() default: break } } nonisolated func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { let status = manager.authorizationStatus Task { @MainActor in self.authorized = (status == .authorizedWhenInUse || status == .authorizedAlways) if self.authorized { self.manager.startUpdatingLocation() } } } nonisolated func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let loc = locations.last else { return } let c = loc.coordinate let kmh = loc.speed >= 0 ? loc.speed * 3.6 : nil let crs = loc.course >= 0 ? loc.course : nil Task { @MainActor in self.location = c self.speedKmh = kmh self.course = crs } } nonisolated func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {} }