// // LocationService.swift // AutoCatCore // // Created by Selim Mustafaev on 31.07.2024. // Copyright © 2024 Selim Mustafaev. All rights reserved. // import CoreLocation import SwiftLocation @MainActor public final class LocationService { public static let shared = LocationService(geocoder: CLGeocoder(), locationManager: Location()) private let geocoder: GeocoderProtocol private var locationManager: SwiftLocationProtocol private var eventTask: Task? public init(geocoder: GeocoderProtocol, locationManager: SwiftLocationProtocol) { self.geocoder = geocoder self.locationManager = locationManager } private func checkPermissions() async throws { switch locationManager.authorizationStatus { case .authorizedWhenInUse, .authorizedAlways: break case .notDetermined: _ = try await locationManager.requestPermission(.always) try await checkPermissions() case .denied: throw CLError(.denied) default: throw LocationError.permission } } private func requestLocation() async throws -> VehicleEventDto { try await checkPermissions() let locationEvent = try await locationManager.requestLocation(accuracy: nil, timeout: 20) guard let coordinate = locationEvent.location?.coordinate else { throw LocationError.generic } return VehicleEventDto(lat: coordinate.latitude, lon: coordinate.longitude) } } extension LocationService: LocationServiceProtocol { public func getAddressForLocation(latitude: Double, longitude: Double) async throws -> String { let location = CLLocation(latitude: latitude, longitude: longitude) let placemarks = try await geocoder.reverseGeocodeLocation(location) if let name = placemarks.first?.name { return name } else { throw LocationError.reverseGeocode } } @discardableResult public func requestCurrentLocation() async throws -> VehicleEventDto { if let eventTask { return try await eventTask.value } else { let task = Task { let location = try await requestLocation() eventTask = nil return location } eventTask = task return try await task.value } } }