SwiftUI/SwiftData iOS-Client, redet mit https://banyaro.app FastAPI-Backend. Bundle-ID app.banyaro.ios, Xcode-26-Projekt mit synchronisierten Ordnern. Drin: - APIClient (URLSession + Bearer + convertFromSnakeCase Decoder) - KeychainStore + AuthSession (@Observable) für persistenten Login - LoginView, MainTabView, SettingsView (mit Logout) - RoutesListView + RouteDetailView mit MapKit-Polyline aus preview_track - DogsListView mit Foto-Avatar - App-Icon (Pfote auf Banyaro-Amber)
42 lines
1.5 KiB
Swift
42 lines
1.5 KiB
Swift
import SwiftUI
|
|
import MapKit
|
|
|
|
/// Non-interactive map showing a polyline for a GPS track. Suitable for
|
|
/// list-row previews as well as larger detail headers.
|
|
struct MiniRouteMap: View {
|
|
let track: [GPSPoint]
|
|
var lineWidth: CGFloat = 3
|
|
|
|
var body: some View {
|
|
Map(initialPosition: .region(region)) {
|
|
MapPolyline(coordinates: coordinates)
|
|
.stroke(Color.accentColor, style: StrokeStyle(lineWidth: lineWidth, lineJoin: .round))
|
|
}
|
|
.mapStyle(.standard(elevation: .flat, pointsOfInterest: .excludingAll))
|
|
.allowsHitTesting(false)
|
|
}
|
|
|
|
private var coordinates: [CLLocationCoordinate2D] {
|
|
track.map { CLLocationCoordinate2D(latitude: $0.lat, longitude: $0.lon) }
|
|
}
|
|
|
|
private var region: MKCoordinateRegion {
|
|
let lats = track.map(\.lat)
|
|
let lons = track.map(\.lon)
|
|
let minLat = lats.min() ?? 0
|
|
let maxLat = lats.max() ?? 0
|
|
let minLon = lons.min() ?? 0
|
|
let maxLon = lons.max() ?? 0
|
|
let center = CLLocationCoordinate2D(
|
|
latitude: (minLat + maxLat) / 2,
|
|
longitude: (minLon + maxLon) / 2
|
|
)
|
|
// Padding ~20% beyond bounding box; minimum span so very small tracks stay visible.
|
|
let latDelta = max((maxLat - minLat) * 1.4, 0.002)
|
|
let lonDelta = max((maxLon - minLon) * 1.4, 0.002)
|
|
return MKCoordinateRegion(
|
|
center: center,
|
|
span: MKCoordinateSpan(latitudeDelta: latDelta, longitudeDelta: lonDelta)
|
|
)
|
|
}
|
|
}
|