92 lines
3.8 KiB
Swift
92 lines
3.8 KiB
Swift
import SwiftUI
|
|
import MapKit
|
|
|
|
struct LeadLocationSection: View {
|
|
let name: String
|
|
let address: LeadAddress
|
|
var locationService: any CustomerLocationService = AppleMapsCustomerLocationService()
|
|
@State private var coordinate: CLLocationCoordinate2D?
|
|
@State private var position: MapCameraPosition = .automatic
|
|
@State private var errorMessage: LocalizedStringResource?
|
|
@State private var retryID = 0
|
|
|
|
static let mapHeight: CGFloat = 328
|
|
|
|
private var addressText: String {
|
|
[address.street, "\(address.postalCode) \(address.city)"]
|
|
.compactMap { $0 }
|
|
.joined(separator: ", ")
|
|
}
|
|
|
|
private var mapsURL: URL? {
|
|
var components = URLComponents(string: "https://maps.apple.com/")
|
|
components?.queryItems = [URLQueryItem(name: "q", value: addressText)]
|
|
return components?.url
|
|
}
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
LeadSectionHeading(title: "STANDORT")
|
|
ZStack {
|
|
LeadDetailStyle.card
|
|
if let coordinate {
|
|
Map(position: $position) {
|
|
Marker(name, coordinate: coordinate)
|
|
.tint(LeadDetailStyle.blue)
|
|
}
|
|
.mapStyle(.standard(pointsOfInterest: .excludingAll))
|
|
.accessibilityLabel("Standort von \(name), \(addressText)")
|
|
} else if let errorMessage {
|
|
ContentUnavailableView {
|
|
Label("Standort nicht verfügbar", systemImage: "mappin.slash")
|
|
} description: {
|
|
Text(errorMessage)
|
|
} actions: {
|
|
Button("Erneut versuchen") { retryID += 1 }
|
|
}
|
|
} else {
|
|
ProgressView("Standort wird geladen")
|
|
}
|
|
}
|
|
.safeAreaInset(edge: .bottom, spacing: 0) {
|
|
if let mapsURL {
|
|
Link(destination: mapsURL) {
|
|
Label("In Apple Maps öffnen", systemImage: "map")
|
|
.font(.subheadline.weight(.semibold))
|
|
.frame(maxWidth: .infinity, minHeight: 48)
|
|
.foregroundStyle(.white)
|
|
.background(LeadDetailStyle.blue)
|
|
}
|
|
.buttonStyle(.plain)
|
|
}
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
.frame(height: Self.mapHeight)
|
|
.clipShape(.rect(cornerRadius: 12))
|
|
}
|
|
.task(id: addressText + "#\(retryID)") {
|
|
coordinate = nil
|
|
errorMessage = nil
|
|
do {
|
|
let result = try await locationService.coordinate(for: addressText)
|
|
try Task.checkCancellation()
|
|
position = .region(MKCoordinateRegion(
|
|
center: result, latitudinalMeters: 800, longitudinalMeters: 800
|
|
))
|
|
coordinate = result
|
|
} catch is CancellationError {
|
|
} catch {
|
|
guard !Task.isCancelled else { return }
|
|
if error is CustomerLocationError {
|
|
errorMessage = "Für diese Anschrift wurde kein Standort gefunden."
|
|
} else if let networkError = error as? URLError,
|
|
[.notConnectedToInternet, .networkConnectionLost, .timedOut].contains(networkError.code) {
|
|
errorMessage = "Keine Verbindung zu Apple Maps. Bitte prüfe deine Internetverbindung und versuche es erneut."
|
|
} else {
|
|
errorMessage = "Apple Maps konnte den Standort gerade nicht ermitteln. Bitte versuche es erneut."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|