// // ContentView.swift // Expiranner // // 메인 뷰: 연도 선택 + 월(1~12) 그리드 import SwiftUI import SwiftData struct ContentView: View { @State private var selectedYear = Calendar.current.component(.year, from: Date()) @State private var showScanner = false private let years = Array(2020...2040) private let columns = Array(repeating: GridItem(.flexible()), count: 3) var body: some View { NavigationStack { ZStack(alignment: .bottomTrailing) { VStack { Picker("연도", selection: $selectedYear) { ForEach(years, id: \.self) { year in Text(String(format: "%d년", year)).tag(year) } } .pickerStyle(.menu) .font(.title2) LazyVGrid(columns: columns, spacing: 16) { ForEach(1...12, id: \.self) { month in NavigationLink { MonthCalendarView(year: selectedYear, month: month) } label: { MonthCell(year: selectedYear, month: month) } .buttonStyle(.plain) } } .padding() Spacer() } FloatingScanButton { showScanner = true } } .navigationTitle("Expiranner") .fullScreenCover(isPresented: $showScanner) { ScannerView( year: Calendar.current.component(.year, from: Date()), month: Calendar.current.component(.month, from: Date()) ) } } } } /// 월 셀: 해당 월에 저장된 아이템 개수 표시 struct MonthCell: View { let year: Int let month: Int @Query private var items: [ProductItem] init(year: Int, month: Int) { self.year = year self.month = month let (start, end) = Self.monthBounds(year: year, month: month) _items = Query(filter: #Predicate { $0.date >= start && $0.date < end }) } static func monthBounds(year: Int, month: Int) -> (Date, Date) { let calendar = Calendar.current let start = calendar.date(from: DateComponents(year: year, month: month, day: 1)) ?? Date() let end = calendar.date(byAdding: .month, value: 1, to: start) ?? start return (start, end) } var body: some View { VStack(spacing: 4) { Text("\(month)월") .font(.title3) Text(items.isEmpty ? " " : "\(items.count)개") .font(.caption) .foregroundStyle(.red) } .frame(maxWidth: .infinity) .padding(.vertical, 16) .background(Color(.secondarySystemBackground)) .clipShape(RoundedRectangle(cornerRadius: 10)) } } /// 플로팅 액션 버튼 (카메라 스캐너 실행) struct FloatingScanButton: View { let action: () -> Void var body: some View { Button(action: action) { Image(systemName: "camera.fill") .font(.title2) .foregroundStyle(.white) .padding(18) .background(Circle().fill(.blue)) .shadow(radius: 4) } .padding(24) } } #Preview { ContentView() .modelContainer(for: ProductItem.self, inMemory: true) }