- SwiftUI + async/await architecture - Barcode scanning with AVFoundation - Product display with score ring, NOVA badge, nutrition - Alternatives with sort/filter - Auth (login/register) - Favorites & history - Account management - Dark theme - Connected to food.payfrit.com API (Open Food Facts proxy) Co-Authored-By: Claude <noreply@anthropic.com>
68 lines
2.2 KiB
Swift
68 lines
2.2 KiB
Swift
import SwiftUI
|
|
|
|
struct ManualEntrySheet: View {
|
|
@Environment(\.dismiss) private var dismiss
|
|
@State private var barcode = ""
|
|
@FocusState private var isFocused: Bool
|
|
|
|
let onSubmit: (String) -> Void
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
VStack(spacing: 24) {
|
|
Image(systemName: "barcode")
|
|
.font(.system(size: 60))
|
|
.foregroundColor(.green)
|
|
.padding(.top, 40)
|
|
|
|
Text("Enter Barcode")
|
|
.font(.title2.bold())
|
|
|
|
Text("Type the numbers below the barcode on the product package.")
|
|
.font(.subheadline)
|
|
.foregroundColor(.secondary)
|
|
.multilineTextAlignment(.center)
|
|
.padding(.horizontal)
|
|
|
|
TextField("Barcode number", text: $barcode)
|
|
.keyboardType(.numberPad)
|
|
.textFieldStyle(.roundedBorder)
|
|
.font(.title3.monospacedDigit())
|
|
.multilineTextAlignment(.center)
|
|
.padding(.horizontal, 40)
|
|
.focused($isFocused)
|
|
|
|
Button {
|
|
if !barcode.isEmpty {
|
|
dismiss()
|
|
onSubmit(barcode)
|
|
}
|
|
} label: {
|
|
Text("Look Up Product")
|
|
.font(.headline)
|
|
.foregroundColor(.black)
|
|
.frame(maxWidth: .infinity)
|
|
.padding()
|
|
.background(barcode.isEmpty ? Color.gray : Color.green)
|
|
.cornerRadius(12)
|
|
}
|
|
.disabled(barcode.isEmpty)
|
|
.padding(.horizontal, 40)
|
|
|
|
Spacer()
|
|
}
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar {
|
|
ToolbarItem(placement: .navigationBarLeading) {
|
|
Button("Cancel") {
|
|
dismiss()
|
|
}
|
|
}
|
|
}
|
|
.onAppear {
|
|
isFocused = true
|
|
}
|
|
}
|
|
.presentationDetents([.medium])
|
|
}
|
|
}
|