128 lines
4.7 KiB
Swift
128 lines
4.7 KiB
Swift
import SwiftUI
|
|
|
|
struct WatchContentView: View {
|
|
@Environment(WatchCardStore.self) private var cardStore
|
|
private let qrService = WatchQRCodeService()
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(spacing: WatchDesign.Spacing.large) {
|
|
if let card = cardStore.defaultCard {
|
|
WatchQRCodeCardView(card: card, qrService: qrService)
|
|
} else if cardStore.cards.isEmpty {
|
|
WatchEmptyStateView()
|
|
}
|
|
|
|
if !cardStore.cards.isEmpty {
|
|
WatchCardPickerView()
|
|
}
|
|
}
|
|
.padding(WatchDesign.Spacing.medium)
|
|
}
|
|
.background(Color.WatchPalette.background)
|
|
.onAppear {
|
|
cardStore.loadCards()
|
|
}
|
|
}
|
|
}
|
|
|
|
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 struct WatchQRCodeCardView: View {
|
|
let card: WatchCard
|
|
let qrService: WatchQRCodeService
|
|
|
|
var body: some View {
|
|
VStack(spacing: WatchDesign.Spacing.small) {
|
|
Text("Default Card")
|
|
.font(.headline)
|
|
.foregroundStyle(Color.WatchPalette.text)
|
|
|
|
if let image = qrService.qrCode(from: card.vCardPayload) {
|
|
Image(decorative: image, scale: 1)
|
|
.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))
|
|
}
|
|
|
|
Text(card.displayName)
|
|
.font(.subheadline)
|
|
.foregroundStyle(Color.WatchPalette.text)
|
|
Text(card.role)
|
|
.font(.caption)
|
|
.foregroundStyle(Color.WatchPalette.muted)
|
|
}
|
|
.padding(WatchDesign.Spacing.medium)
|
|
.background(Color.WatchPalette.card)
|
|
.clipShape(.rect(cornerRadius: WatchDesign.CornerRadius.large))
|
|
.accessibilityElement(children: .ignore)
|
|
.accessibilityLabel(String(localized: "Default card QR code"))
|
|
.accessibilityValue("\(card.displayName), \(card.role)")
|
|
}
|
|
}
|
|
|
|
private struct WatchCardPickerView: View {
|
|
@Environment(WatchCardStore.self) private var cardStore
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: WatchDesign.Spacing.small) {
|
|
Text("Choose default")
|
|
.font(.headline)
|
|
.foregroundStyle(Color.WatchPalette.text)
|
|
|
|
ForEach(cardStore.cards) { card in
|
|
Button {
|
|
cardStore.setDefault(card)
|
|
} label: {
|
|
HStack {
|
|
Text(card.displayName)
|
|
.foregroundStyle(Color.WatchPalette.text)
|
|
Spacer()
|
|
if card.id == cardStore.defaultCardID {
|
|
Image(systemName: "checkmark")
|
|
.foregroundStyle(Color.WatchPalette.accent)
|
|
}
|
|
}
|
|
}
|
|
.buttonStyle(.plain)
|
|
.padding(.vertical, WatchDesign.Spacing.small)
|
|
.padding(.horizontal, WatchDesign.Spacing.medium)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.background(card.id == cardStore.defaultCardID ? Color.WatchPalette.accent.opacity(WatchDesign.Opacity.strong) : Color.WatchPalette.card)
|
|
.clipShape(.rect(cornerRadius: WatchDesign.CornerRadius.medium))
|
|
.accessibilityValue(card.id == cardStore.defaultCardID ? String(localized: "Selected") : String(localized: "Not selected"))
|
|
}
|
|
}
|
|
.padding(WatchDesign.Spacing.medium)
|
|
.background(Color.WatchPalette.card.opacity(WatchDesign.Opacity.hint))
|
|
.clipShape(.rect(cornerRadius: WatchDesign.CornerRadius.large))
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
WatchContentView()
|
|
.environment(WatchCardStore())
|
|
}
|