- 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>
53 lines
1.5 KiB
Swift
53 lines
1.5 KiB
Swift
import SwiftUI
|
|
|
|
struct ScoreRing: View {
|
|
let score: Int
|
|
@State private var animatedProgress: Double = 0
|
|
|
|
var body: some View {
|
|
VStack(spacing: 8) {
|
|
ZStack {
|
|
// Background circle
|
|
Circle()
|
|
.stroke(lineWidth: 12)
|
|
.opacity(0.2)
|
|
.foregroundColor(scoreColor)
|
|
|
|
// Progress circle
|
|
Circle()
|
|
.trim(from: 0, to: animatedProgress)
|
|
.stroke(style: StrokeStyle(lineWidth: 12, lineCap: .round))
|
|
.foregroundColor(scoreColor)
|
|
.rotationEffect(.degrees(-90))
|
|
|
|
// Score text
|
|
VStack(spacing: 2) {
|
|
Text("\(score)")
|
|
.font(.system(size: 32, weight: .bold, design: .rounded))
|
|
Text("/ 100")
|
|
.font(.caption)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
}
|
|
.frame(width: 100, height: 100)
|
|
|
|
Text("Health Score")
|
|
.font(.caption)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
.onAppear {
|
|
withAnimation(.easeOut(duration: 1.0)) {
|
|
animatedProgress = Double(score) / 100.0
|
|
}
|
|
}
|
|
}
|
|
|
|
private var scoreColor: Color {
|
|
switch score {
|
|
case 80...100: return .green
|
|
case 50..<80: return .yellow
|
|
case 30..<50: return .orange
|
|
default: return .red
|
|
}
|
|
}
|
|
}
|