Files
Luma/Sources/Shared/Services/LocationProvider.swift
T
2026-07-30 20:07:51 +07:00

95 lines
3.5 KiB
Swift

import CoreLocation
import Combine
import Foundation
@MainActor
final class LocationProvider: NSObject, ObservableObject {
@Published private(set) var location: CLLocation?
@Published private(set) var authorizationStatus: CLAuthorizationStatus
@Published private(set) var errorMessage: String?
@Published private(set) var isLocating = false
private let manager: CLLocationManager
override init() {
let manager = CLLocationManager()
self.manager = manager
authorizationStatus = manager.authorizationStatus
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
}
func requestCurrentLocation() {
errorMessage = nil
switch manager.authorizationStatus {
case .notDetermined:
isLocating = true
manager.requestWhenInUseAuthorization()
case .authorizedAlways, .authorizedWhenInUse:
isLocating = true
manager.requestLocation()
case .denied, .restricted:
isLocating = false
errorMessage = "Доступ к геопозиции выключен. Можно выбрать точку на карте вручную."
@unknown default:
isLocating = false
errorMessage = "Не удалось определить статус доступа к геопозиции."
}
}
}
extension LocationProvider: CLLocationManagerDelegate {
nonisolated func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
let status = manager.authorizationStatus
Task { @MainActor [weak self] in
guard let self else { return }
authorizationStatus = status
switch status {
case .authorizedAlways, .authorizedWhenInUse:
isLocating = true
self.manager.requestLocation()
case .denied, .restricted:
isLocating = false
errorMessage = "Доступ к геопозиции выключен. Можно выбрать точку на карте вручную."
case .notDetermined:
break
@unknown default:
isLocating = false
}
}
}
nonisolated func locationManager(
_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]
) {
guard let newest = locations.last else { return }
let latitude = newest.coordinate.latitude
let longitude = newest.coordinate.longitude
let altitude = newest.altitude
let horizontalAccuracy = newest.horizontalAccuracy
let verticalAccuracy = newest.verticalAccuracy
let timestamp = newest.timestamp
Task { @MainActor [weak self] in
self?.location = CLLocation(
coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude),
altitude: altitude,
horizontalAccuracy: horizontalAccuracy,
verticalAccuracy: verticalAccuracy,
timestamp: timestamp
)
self?.isLocating = false
self?.errorMessage = nil
}
}
nonisolated func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
let description = error.localizedDescription
Task { @MainActor [weak self] in
self?.isLocating = false
self?.errorMessage = "Не удалось получить текущую геопозицию: \(description)"
}
}
}