krz/daybyday

clone: git clone https://gitbay.org/krz/daybyday.git

main: FoodCard.swift ยท raw

  1//
  2//  FoodCard.swift
  3//  DayByDay
  4//
  5
  6import SwiftUI
  7
  8/// A single large, colorful card representing one fruit or vegetable.
  9/// Tapping the card plays a bounce animation and speaks the food name aloud.
 10/// Each food displays its emoji at large size for instant recognition.
 11struct FoodCard: View {
 12    let food: LearnFood
 13    @State private var isTapped = false
 14
 15    var body: some View {
 16        ZStack {
 17            RoundedRectangle(cornerRadius: 32, style: .continuous)
 18                .fill(food.color.gradient)
 19                .shadow(color: food.color.opacity(0.4), radius: 8, y: 4)
 20
 21            VStack(spacing: 16) {
 22                Text(food.emoji)
 23                    .font(.system(size: 72))
 24
 25                Text(food.name)
 26                    .font(.system(size: 28, weight: .bold, design: .rounded))
 27                    .foregroundStyle(.white)
 28            }
 29        }
 30        .scaleEffect(isTapped ? 1.12 : 1.0)
 31        .contentShape(RoundedRectangle(cornerRadius: 32, style: .continuous))
 32        .rotation3DEffect(.degrees(isTapped ? 6 : 0), axis: (x: 1, y: 0, z: 0))
 33        .animation(.spring(response: 0.35, dampingFraction: 0.5), value: isTapped)
 34        .onTapGesture {
 35            isTapped = true
 36            SpeechSynthesizer.shared.speak(food.name)
 37            DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
 38                isTapped = false
 39            }
 40        }
 41        .accessibilityLabel(food.name)
 42        .accessibilityAddTraits(.isButton)
 43    }
 44
 45}
 46
 47// MARK: - Food model
 48
 49enum LearnFood: Int, CaseIterable, Identifiable {
 50    case apple, banana, carrot, strawberry, grapes, lemon,
 51         broccoli, watermelon, cherry, orange, corn, pear
 52
 53    var id: Int { rawValue }
 54
 55    var name: String {
 56        switch self {
 57        case .apple:      "Apple"
 58        case .banana:     "Banana"
 59        case .carrot:     "Carrot"
 60        case .strawberry: "Strawberry"
 61        case .grapes:     "Grapes"
 62        case .lemon:      "Lemon"
 63        case .broccoli:   "Broccoli"
 64        case .watermelon: "Watermelon"
 65        case .cherry:     "Cherry"
 66        case .orange:     "Orange"
 67        case .corn:       "Corn"
 68        case .pear:       "Pear"
 69        }
 70    }
 71
 72    var emoji: String {
 73        switch self {
 74        case .apple:      "๐ŸŽ"
 75        case .banana:     "๐ŸŒ"
 76        case .carrot:     "๐Ÿฅ•"
 77        case .strawberry: "๐Ÿ“"
 78        case .grapes:     "๐Ÿ‡"
 79        case .lemon:      "๐Ÿ‹"
 80        case .broccoli:   "๐Ÿฅฆ"
 81        case .watermelon: "๐Ÿ‰"
 82        case .cherry:     "๐Ÿ’"
 83        case .orange:     "๐ŸŠ"
 84        case .corn:       "๐ŸŒฝ"
 85        case .pear:       "๐Ÿ"
 86        }
 87    }
 88
 89    var color: Color {
 90        switch self {
 91        case .apple:      Color(red: 0.85, green: 0.2, blue: 0.2)    // red
 92        case .banana:     Color(red: 0.95, green: 0.8, blue: 0.2)    // yellow
 93        case .carrot:     Color(red: 1.0, green: 0.55, blue: 0.15)   // orange
 94        case .strawberry: Color(red: 0.9, green: 0.25, blue: 0.3)    // strawberry red
 95        case .grapes:     Color(red: 0.55, green: 0.3, blue: 0.7)    // purple
 96        case .lemon:      Color(red: 0.9, green: 0.8, blue: 0.2)     // lemon yellow
 97        case .broccoli:   Color(red: 0.3, green: 0.65, blue: 0.3)    // green
 98        case .watermelon: Color(red: 0.35, green: 0.7, blue: 0.4)    // watermelon green
 99        case .cherry:     Color(red: 0.7, green: 0.15, blue: 0.2)    // dark red
100        case .orange:     Color(red: 1.0, green: 0.6, blue: 0.15)    // orange
101        case .corn:       Color(red: 0.9, green: 0.75, blue: 0.2)    // golden yellow
102        case .pear:       Color(red: 0.55, green: 0.75, blue: 0.3)   // pear green
103        }
104    }
105}
106
107#Preview {
108    HStack(spacing: 24) {
109        FoodCard(food: .apple)
110            .frame(width: 200, height: 260)
111        FoodCard(food: .carrot)
112            .frame(width: 200, height: 260)
113    }
114    .padding()
115}