import SwiftUI struct WatchContentView: View { @Environment(WatchCardStore.self) private var cardStore @State private var selectedCardID: UUID? private var displayCards: [WatchCard] { cardStore.cards } private var defaultSelection: UUID? { cardStore.defaultCardID ?? displayCards.first?.id } var body: some View { if displayCards.isEmpty { WatchEmptyStateView() } else if displayCards.count == 1 { WatchQRCodeCardView(card: displayCards[0]) } else { TabView(selection: Binding( get: { selectedCardID ?? defaultSelection ?? displayCards[0].id }, set: { selectedCardID = $0 } )) { ForEach(displayCards) { card in WatchQRCodeCardView(card: card) .tag(card.id) } } .tabViewStyle(.page(indexDisplayMode: .never)) } } } private struct WatchEmptyStateView: View { var body: some View { VStack(spacing: WatchDesign.Spacing.medium) { Image(systemName: "rectangle.stack") .font(.title) .foregroundStyle(Color.WatchPalette.muted) Text("No Cards") .font(.headline) .foregroundStyle(Color.WatchPalette.text) Text("Open the iPhone app to create cards") .font(.caption) .foregroundStyle(Color.WatchPalette.muted) .multilineTextAlignment(.center) } .padding(WatchDesign.Spacing.large) } } private enum WatchQRMode: String, CaseIterable { case vCard = "vCard" case appClip = "App Clip" } private struct WatchQRCodeCardView: View { let card: WatchCard @State private var selectedQRIndex = 0 private var hasAppClipQR: Bool { card.appClipQRCodeImage != nil } private var qrPages: [(WatchQRMode, Image?)] { var pages: [(WatchQRMode, Image?)] = [(.vCard, card.qrCodeImage)] if hasAppClipQR { pages.append((.appClip, card.appClipQRCodeImage)) } return pages } var body: some View { VStack(spacing: WatchDesign.Spacing.small) { if qrPages.count > 1 { // Swipeable QR codes (vCard ↔ App Clip) - no buttons, just swipe TabView(selection: $selectedQRIndex) { ForEach(Array(qrPages.enumerated()), id: \.offset) { index, item in qrCodeContent(image: item.1) .tag(index) } } .tabViewStyle(.page(indexDisplayMode: .never)) .frame(height: WatchDesign.Size.qrSize + WatchDesign.Spacing.medium * 2) } else { // Single QR code qrCodeContent(image: card.qrCodeImage ?? card.appClipQRCodeImage) } VStack(spacing: WatchDesign.Spacing.extraSmall) { Text(card.fullName) .font(.headline) .foregroundStyle(Color.WatchPalette.text) .lineLimit(1) Text(card.role) .font(.caption) .foregroundStyle(Color.WatchPalette.muted) .lineLimit(1) } } .padding(WatchDesign.Spacing.medium) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.WatchPalette.background) .accessibilityElement(children: .ignore) .accessibilityLabel(String(localized: "QR code")) .accessibilityValue("\(card.fullName), \(card.role)") .accessibilityHint(hasAppClipQR ? String(localized: "Swipe left or right to switch QR code type") : "") } @ViewBuilder private func qrCodeContent(image: Image?) -> some View { if let image { image .resizable() .interpolation(.none) .scaledToFit() .frame(width: WatchDesign.Size.qrSize, height: WatchDesign.Size.qrSize) .padding(WatchDesign.Spacing.small) .background(Color.WatchPalette.card) .clipShape(.rect(cornerRadius: WatchDesign.CornerRadius.large)) } else { VStack(spacing: WatchDesign.Spacing.small) { Image(systemName: "qrcode") .font(.largeTitle) .foregroundStyle(Color.WatchPalette.muted) Text("Sync from iPhone") .font(.caption2) .foregroundStyle(Color.WatchPalette.muted) } .frame(width: WatchDesign.Size.qrSize, height: WatchDesign.Size.qrSize) .background(Color.WatchPalette.card) .clipShape(.rect(cornerRadius: WatchDesign.CornerRadius.large)) } } } #Preview { WatchContentView() .environment(WatchCardStore()) }