AutoCat/AutoCatCore/Services/LocationService/LocationService.swift

82 lines
2.3 KiB
Swift

//
// 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 {
@Service var geocoder: GeocoderProtocol
@Service var locationManager: SwiftLocationProtocol
@Service var settingsService: SettingsServiceProtocol
private var eventTask: Task<VehicleEventDto,Error>?
public init() {
}
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, addedBy: settingsService.user.email)
}
}
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
}
}
}