import SwiftUI struct LoginView: View { @Environment(AuthSession.self) private var auth @State private var email = "" @State private var password = "" var body: some View { ScrollView { VStack(spacing: 28) { hero pitch loginCard registerCard } .padding(.horizontal, 24) .padding(.vertical, 32) } .scrollDismissesKeyboard(.interactively) } // MARK: - Hero private var hero: some View { VStack(spacing: 12) { Image("AppIconHero") .resizable() .scaledToFit() .frame(height: 120) Text("Ban Yaro Go") .font(.largeTitle.bold()) Text("Die deutschsprachige Hunde-Plattform — jetzt mit nativem GPS-Tracking.") .font(.callout) .foregroundStyle(.secondary) .multilineTextAlignment(.center) } } // MARK: - Pitch (für Neue) private var pitch: some View { VStack(alignment: .leading, spacing: 14) { feature(icon: "map.fill", title: "Gassi-Touren aufzeichnen", subtitle: "GPS-Tracking auch im Hintergrund — mit Pause, Live Activity und HealthKit-Sync.") feature(icon: "person.2.fill", title: "Hunde-Community", subtitle: "Gassi-Treffen, Tierärzte und Orte in deiner Nähe.") feature(icon: "book.fill", title: "Tagebuch & Impfpass", subtitle: "Alles rund um deinen Hund an einem Ort.") feature(icon: "exclamationmark.shield.fill", title: "Giftköder-Alarm", subtitle: "Warnungen aus deiner Region direkt aufs iPhone.") } .padding(18) .frame(maxWidth: .infinity, alignment: .leading) .background(.background.secondary, in: RoundedRectangle(cornerRadius: 16)) } private func feature(icon: String, title: String, subtitle: String) -> some View { HStack(alignment: .top, spacing: 12) { Image(systemName: icon) .font(.title3) .foregroundStyle(Color.accentColor) .frame(width: 28) VStack(alignment: .leading, spacing: 2) { Text(title).font(.subheadline.bold()) Text(subtitle) .font(.caption) .foregroundStyle(.secondary) } } } // MARK: - Login (für bestehende User) private var loginCard: some View { VStack(spacing: 12) { HStack { Text("Schon angemeldet?") .font(.headline) Spacer() } TextField("E-Mail", text: $email) .textContentType(.emailAddress) .keyboardType(.emailAddress) .textInputAutocapitalization(.never) .autocorrectionDisabled() .padding() .background(.background, in: RoundedRectangle(cornerRadius: 12)) SecureField("Passwort", text: $password) .textContentType(.password) .padding() .background(.background, in: RoundedRectangle(cornerRadius: 12)) if let error = auth.errorMessage { Text(error) .font(.footnote) .foregroundStyle(.red) .multilineTextAlignment(.center) .frame(maxWidth: .infinity) } Button { Task { await auth.login( email: email.trimmingCharacters(in: .whitespacesAndNewlines), password: password ) } } label: { Group { if auth.isLoggingIn { ProgressView().tint(.white) } else { Text("Login").bold() } } .frame(maxWidth: .infinity, minHeight: 50) } .background(Color.accentColor, in: RoundedRectangle(cornerRadius: 12)) .foregroundStyle(.white) .disabled(auth.isLoggingIn || email.isEmpty || password.isEmpty) } .padding(18) .background(.background.secondary, in: RoundedRectangle(cornerRadius: 16)) } // MARK: - Register (für Neue) private var registerCard: some View { VStack(spacing: 10) { Text("Neu hier?") .font(.headline) Text("banyaro.app ist **kostenlos**, **DSGVO-konform** und wird in Deutschland gehostet — kein App-Store-Konto nötig.") .font(.footnote) .foregroundStyle(.secondary) .multilineTextAlignment(.center) if let url = URL(string: "https://banyaro.app/#settings?tab=register") { Link(destination: url) { HStack(spacing: 8) { Image(systemName: "person.crop.circle.badge.plus") Text("Kostenlos registrieren").bold() Image(systemName: "arrow.up.right") .font(.caption.bold()) } .frame(maxWidth: .infinity, minHeight: 50) } .background(Color.accentColor.opacity(0.15), in: RoundedRectangle(cornerRadius: 12)) .foregroundStyle(Color.accentColor) } Text("Öffnet die Registrierung im Browser. Danach mit den neuen Zugangsdaten oben einloggen.") .font(.caption2) .foregroundStyle(.tertiary) .multilineTextAlignment(.center) } .padding(18) .background(.background.secondary, in: RoundedRectangle(cornerRadius: 16)) } } #Preview { LoginView() .environment(AuthSession()) }