0.10.6
This commit is contained in:
commit
92660a4ba0
228 files changed
+24496
No files matched your search
@@ -0,0 +1,148 @@
|
||||
import CoreLocation
|
||||
import Combine
|
||||
import Foundation
|
||||
import MapKit
|
||||
import SwiftUI
|
||||
|
||||
@MainActor
|
||||
struct LocationPickerView: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@StateObject private var locationProvider = LocationProvider()
|
||||
@State private var cameraPosition: MapCameraPosition = .automatic
|
||||
@State private var selectedCoordinate: CLLocationCoordinate2D?
|
||||
|
||||
let onSend: (GeoLocation) -> Void
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
ZStack {
|
||||
Map(position: $cameraPosition) {
|
||||
UserAnnotation()
|
||||
}
|
||||
.mapStyle(.standard(elevation: .realistic))
|
||||
.onMapCameraChange(frequency: .onEnd) { context in
|
||||
selectedCoordinate = context.region.center
|
||||
}
|
||||
|
||||
Image(systemName: "mappin.circle.fill")
|
||||
.font(.system(size: 42, weight: .semibold))
|
||||
.symbolRenderingMode(.palette)
|
||||
.foregroundStyle(.white, Color.accentColor)
|
||||
.shadow(color: .black.opacity(0.28), radius: 4, y: 2)
|
||||
.offset(y: -20)
|
||||
.allowsHitTesting(false)
|
||||
|
||||
VStack {
|
||||
if let message = locationProvider.errorMessage {
|
||||
Text(message)
|
||||
.font(.caption)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 8)
|
||||
.background(.regularMaterial, in: Capsule())
|
||||
.padding()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
Button(action: centerOnCurrentLocation) {
|
||||
Group {
|
||||
if locationProvider.isLocating {
|
||||
ProgressView()
|
||||
} else {
|
||||
Image(systemName: "location.fill")
|
||||
}
|
||||
}
|
||||
.frame(width: 44, height: 44)
|
||||
.background(.regularMaterial, in: Circle())
|
||||
.shadow(color: .black.opacity(0.16), radius: 5, y: 2)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel("Показать мою геопозицию")
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.bottom, 10)
|
||||
}
|
||||
}
|
||||
.safeAreaInset(edge: .bottom) {
|
||||
VStack(spacing: 10) {
|
||||
Text(coordinateText)
|
||||
.font(.caption.monospacedDigit())
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
Button(action: sendSelection) {
|
||||
Label("Отправить эту геопозицию", systemImage: "location.fill")
|
||||
.font(.headline)
|
||||
.foregroundStyle(.white)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 12)
|
||||
.background(Color.accentColor, in: RoundedRectangle(cornerRadius: 14))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(selectedCoordinate == nil)
|
||||
}
|
||||
.padding(16)
|
||||
.background(.regularMaterial)
|
||||
}
|
||||
.navigationTitle("Геопозиция")
|
||||
#if os(iOS)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
#endif
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Отмена") { dismiss() }
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
locationProvider.requestCurrentLocation()
|
||||
}
|
||||
.onReceive(locationProvider.$location.compactMap { $0 }) { location in
|
||||
selectedCoordinate = location.coordinate
|
||||
cameraPosition = .region(
|
||||
MKCoordinateRegion(
|
||||
center: location.coordinate,
|
||||
latitudinalMeters: 1_200,
|
||||
longitudinalMeters: 1_200
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private var coordinateText: String {
|
||||
guard let selectedCoordinate else { return "Переместите карту, чтобы выбрать точку" }
|
||||
return String(
|
||||
format: "%.6f, %.6f",
|
||||
locale: Locale(identifier: "en_US_POSIX"),
|
||||
selectedCoordinate.latitude,
|
||||
selectedCoordinate.longitude
|
||||
)
|
||||
}
|
||||
|
||||
private func centerOnCurrentLocation() {
|
||||
if let location = locationProvider.location {
|
||||
selectedCoordinate = location.coordinate
|
||||
cameraPosition = .region(
|
||||
MKCoordinateRegion(
|
||||
center: location.coordinate,
|
||||
latitudinalMeters: 1_200,
|
||||
longitudinalMeters: 1_200
|
||||
)
|
||||
)
|
||||
} else {
|
||||
locationProvider.requestCurrentLocation()
|
||||
}
|
||||
}
|
||||
|
||||
private func sendSelection() {
|
||||
guard let selectedCoordinate,
|
||||
let location = GeoLocation(
|
||||
latitude: selectedCoordinate.latitude,
|
||||
longitude: selectedCoordinate.longitude
|
||||
) else { return }
|
||||
onSend(location)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user