import SwiftUI struct DogsListView: View { @State private var dogs: [Dog] = [] @State private var isLoading = false @State private var errorMessage: String? var body: some View { NavigationStack { content .navigationTitle("Hunde") .task { await load() } } } @ViewBuilder private var content: some View { if isLoading && dogs.isEmpty { ProgressView() } else if let error = errorMessage, dogs.isEmpty { ContentUnavailableView( "Konnte Hunde nicht laden", systemImage: "wifi.slash", description: Text(error) ) } else if dogs.isEmpty { ContentUnavailableView( "Keine Hunde", systemImage: "pawprint", description: Text("Lege deinen ersten Hund in der PWA an.") ) } else { List(dogs) { dog in DogRow(dog: dog) } .refreshable { await load() } } } private func load() async { isLoading = true errorMessage = nil defer { isLoading = false } do { dogs = try await APIClient.shared.get("/api/dogs") } catch { errorMessage = error.localizedDescription } } } struct DogRow: View { let dog: Dog var body: some View { HStack(spacing: 12) { avatar .frame(width: 56, height: 56) .background(.background.secondary) .clipShape(Circle()) VStack(alignment: .leading, spacing: 2) { Text(dog.name).font(.headline) if let rasse = dog.rasse, !rasse.isEmpty { Text(rasse) .font(.subheadline) .foregroundStyle(.secondary) } } } .padding(.vertical, 4) } @ViewBuilder private var avatar: some View { if let path = dog.fotoUrl, let url = URL(string: "https://banyaro.app\(path)") { AsyncImage(url: url) { phase in switch phase { case .success(let img): img.resizable().scaledToFill() default: placeholder } } } else { placeholder } } private var placeholder: some View { Image(systemName: "pawprint.fill") .font(.title2) .foregroundStyle(.secondary) .frame(maxWidth: .infinity, maxHeight: .infinity) } }