mycode/myApp/Expiranner/IOS/ContentView.swift
2026-07-09 19:23:40 +09:00

116 lines
3.5 KiB
Swift

//
// 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<ProductItem> { $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)
}