import SwiftUI struct GameView: View { let service: StreamingService @State private var isScanning = false @State private var isLoading = false @State private var alert: AlertInfo? var body: some View { ZStack { Color("Background").ignoresSafeArea() VStack(spacing: 48) { Image("AppLogo") .resizable() .scaledToFit() .frame(width: 160, height: 160) if isLoading { ProgressView() .tint(Color("Primary")) .scaleEffect(1.4) } else { Button(action: { isScanning = true }) { Text("Nächste Karte") .font(.system(size: 17, weight: .bold)) .foregroundColor(.white) .frame(width: 220, height: 56) .background(Color("Primary")) .cornerRadius(8) } } } } .navigationBarTitleDisplayMode(.inline) .sheet(isPresented: $isScanning) { QRScannerView { scannedUrl in isScanning = false handleScanned(url: scannedUrl) } } .alert(item: $alert) { info in Alert( title: Text(info.title), message: Text(info.message), dismissButton: info.scanNext ? .default(Text("Nächste Karte")) { isScanning = true } : .default(Text("OK")) ) } .onAppear { isScanning = true } } private func handleScanned(url: String) { isLoading = true Task { do { let song = try await ApiClient.shared.resolve(url: url) await MainActor.run { isLoading = false guard let song else { alert = AlertInfo( title: "Nicht gefunden", message: "Dieser QR-Code ist keiner bekannten Hitster-Karte zugeordnet.", scanNext: false ) return } guard let serviceUrl = song.url(for: service) else { alert = AlertInfo( title: "Nicht verfügbar", message: "\(song.artist) – \(song.title)\n\nist auf \(service.displayName) nicht verfügbar.\n\nBitte ziehe die nächste Karte.", scanNext: true ) return } UIApplication.shared.open(serviceUrl) } } catch { await MainActor.run { isLoading = false alert = AlertInfo(title: "Fehler", message: error.localizedDescription, scanNext: false) } } } } } private struct AlertInfo: Identifiable { let id = UUID() let title: String let message: String let scanNext: Bool }