feat: Initial iOS Health Dashboard app (Swift + SwiftUI)
This commit is contained in:
57
PulseHealth/Views/ReadinessCardView.swift
Normal file
57
PulseHealth/Views/ReadinessCardView.swift
Normal file
@@ -0,0 +1,57 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ReadinessCardView: View {
|
||||
let readiness: ReadinessResponse
|
||||
var statusColor: Color {
|
||||
switch readiness.status {
|
||||
case "ready": return Color(hex: "00d4aa")
|
||||
case "moderate": return Color(hex: "ffa500")
|
||||
default: return Color(hex: "ff6b6b")
|
||||
}
|
||||
}
|
||||
var statusEmoji: String {
|
||||
switch readiness.status { case "ready": return "💪"; case "moderate": return "🚶"; default: return "😴" }
|
||||
}
|
||||
var body: some View {
|
||||
VStack(spacing: 16) {
|
||||
Text("Готовность").font(.headline).foregroundColor(.white.opacity(0.7))
|
||||
ZStack {
|
||||
Circle().stroke(Color.white.opacity(0.1), lineWidth: 12).frame(width: 140, height: 140)
|
||||
Circle().trim(from: 0, to: CGFloat(readiness.score) / 100)
|
||||
.stroke(statusColor, style: StrokeStyle(lineWidth: 12, lineCap: .round))
|
||||
.frame(width: 140, height: 140).rotationEffect(.degrees(-90))
|
||||
.animation(.easeInOut(duration: 1), value: readiness.score)
|
||||
VStack(spacing: 4) {
|
||||
Text("\(readiness.score)").font(.system(size: 44, weight: .bold)).foregroundColor(statusColor)
|
||||
Text(statusEmoji).font(.title2)
|
||||
}
|
||||
}
|
||||
Text(readiness.recommendation).font(.subheadline).foregroundColor(.white.opacity(0.8)).multilineTextAlignment(.center).padding(.horizontal)
|
||||
if let f = readiness.factors {
|
||||
VStack(spacing: 8) {
|
||||
FactorRow(name: "Сон", score: f.sleep.score, value: f.sleep.value)
|
||||
FactorRow(name: "HRV", score: f.hrv.score, value: f.hrv.value)
|
||||
FactorRow(name: "Пульс", score: f.rhr.score, value: f.rhr.value)
|
||||
FactorRow(name: "Активность", score: f.activity.score, value: f.activity.value)
|
||||
}.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
.padding(24).background(Color.white.opacity(0.05)).cornerRadius(20).padding(.horizontal)
|
||||
}
|
||||
}
|
||||
|
||||
struct FactorRow: View {
|
||||
let name: String; let score: Int; let value: String
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text(name).font(.caption).foregroundColor(.white.opacity(0.6)).frame(width: 70, alignment: .leading)
|
||||
GeometryReader { geo in
|
||||
ZStack(alignment: .leading) {
|
||||
RoundedRectangle(cornerRadius: 4).fill(Color.white.opacity(0.1))
|
||||
RoundedRectangle(cornerRadius: 4).fill(Color(hex: "00d4aa")).frame(width: geo.size.width * CGFloat(score) / 100)
|
||||
}
|
||||
}.frame(height: 6)
|
||||
Text(value).font(.caption).foregroundColor(.white.opacity(0.6)).frame(width: 60, alignment: .trailing)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user