import ManaCore import SwiftUI /// Liste der vom User blockierten Marketplace-Authors. Entblock-Action /// per Swipe — analog zur iOS-Mail-Inbox. /// /// App-Store-Guideline 5.1.1(v) verlangt: Block-Mechanismus für UGC /// muss verwaltbar sein. Diese View ist der Verwaltungs-Endpunkt. struct BlockedAuthorsView: View { @Environment(AuthClient.self) private var auth @State private var blocks: [BlockEntry] = [] @State private var isLoading = false @State private var errorMessage: String? var body: some View { ZStack { CardsTheme.background.ignoresSafeArea() content } .navigationTitle("Blockierte Authors") #if os(iOS) .navigationBarTitleDisplayMode(.inline) #endif .task { await load() } .refreshable { await load() } } @ViewBuilder private var content: some View { if isLoading, blocks.isEmpty { ProgressView().tint(CardsTheme.primary) } else if blocks.isEmpty { ContentUnavailableView( "Keine blockierten Authors", systemImage: "hand.raised.slash", description: Text("Blockiere Authors über das Menü oben rechts auf Marketplace-Decks.") ) .foregroundStyle(CardsTheme.mutedForeground) } else { List { ForEach(blocks) { block in VStack(alignment: .leading, spacing: 2) { Text(block.displayName) .font(.subheadline.weight(.semibold)) Text("@\(block.authorSlug)") .font(.caption) .foregroundStyle(CardsTheme.mutedForeground) } .swipeActions { Button("Entblocken") { Task { await unblock(block) } } .tint(CardsTheme.primary) } } } .listStyle(.plain) .scrollContentBackground(.hidden) if let errorMessage { Text(errorMessage) .font(.caption) .foregroundStyle(CardsTheme.error) .padding(.horizontal, 16) } } } private func load() async { isLoading = true defer { isLoading = false } let api = CardsAPI(auth: auth) do { blocks = try await api.myBlocks() } catch { errorMessage = (error as? LocalizedError)?.errorDescription ?? String(describing: error) } } private func unblock(_ block: BlockEntry) async { let api = CardsAPI(auth: auth) do { try await api.unblockAuthor(slug: block.authorSlug) blocks.removeAll { $0.id == block.id } } catch { errorMessage = (error as? LocalizedError)?.errorDescription ?? String(describing: error) } } }