remindwall / RWPureSwift / Sources / TrafficAPI / PlaceSearch.swift
Back to remindwall — Current RemindWall
import CoreLocation
import Dependencies
import DependenciesMacros
import Foundation
import MapKit
/// One MKLocalSearch hit as plain values, for destination and home-origin
/// picking in the alerts settings.
public struct FoundPlace: Equatable, Identifiable, Sendable {
public let id: String
public let name: String
public let address: String
public let latitude: Double
public let longitude: Double
public init(id: String, name: String, address: String, latitude: Double, longitude: Double) {
self.id = id
self.name = name
self.address = address
self.latitude = latitude
self.longitude = longitude
}
}
@DependencyClient
public struct PlaceSearchClient: Sendable {
/// Natural-language place lookup via Apple Maps.
public var search: @Sendable (_ query: String) async throws -> [FoundPlace]
}
extension PlaceSearchClient: DependencyKey {
public static var liveValue: Self {
Self(
search: { query in
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = query
let response = try await MKLocalSearch(request: request).start()
return response.mapItems.compactMap { item in
guard let name = item.name else { return nil }
let coordinate = item.placemark.coordinate
return FoundPlace(
id: "\(name)|\(coordinate.latitude)|\(coordinate.longitude)",
name: name,
address: item.placemark.title ?? "",
latitude: coordinate.latitude,
longitude: coordinate.longitude
)
}
}
)
}
}
extension PlaceSearchClient: TestDependencyKey {
public static let testValue = Self()
public static var previewValue: Self {
Self(
search: { query in
[
FoundPlace(
id: "preview-1", name: "Maple Elementary",
address: "402 School Rd, Seattle",
latitude: 47.5423, longitude: -122.3866
),
FoundPlace(
id: "preview-2", name: "\(query) Learning Ctr",
address: "98 Pine Ave, Renton",
latitude: 47.48, longitude: -122.2
),
]
}
)
}
}
extension DependencyValues {
public var placeSearch: PlaceSearchClient {
get { self[PlaceSearchClient.self] }
set { self[PlaceSearchClient.self] = newValue }
}
}