- DashboardView: полный редизайн с приветствием по времени суток, pull-to-refresh - ReadinessCardView: анимированное кольцо, цветные факторы с иконками - MetricCardView: glassmorphism карточки, градиентные иконки, SleepCard/StepsCard - WeeklyChartView: bar chart (Sleep/HRV/Steps) без внешних библиотек - ToastView: уведомления об успехе/ошибке с автоскрытием - HealthKitService: полный сбор метрик + отправка на сервер - HealthModels: HeatmapEntry для недельных данных - Тёмная тема #0a0a1a, haptic feedback, анимации появления
86 lines
1.6 KiB
Swift
86 lines
1.6 KiB
Swift
import Foundation
|
|
|
|
struct ReadinessResponse: Codable {
|
|
let score: Int
|
|
let status: String
|
|
let recommendation: String
|
|
let date: String?
|
|
let factors: ReadinessFactors?
|
|
}
|
|
|
|
struct ReadinessFactors: Codable {
|
|
let sleep: FactorScore
|
|
let hrv: FactorScore
|
|
let rhr: FactorScore
|
|
let activity: FactorScore
|
|
}
|
|
|
|
struct FactorScore: Codable {
|
|
let score: Int
|
|
let value: String
|
|
let baseline: String?
|
|
}
|
|
|
|
struct LatestHealthResponse: Codable {
|
|
let sleep: SleepData?
|
|
let heartRate: HeartRateData?
|
|
let restingHeartRate: RestingHRData?
|
|
let hrv: HRVData?
|
|
let steps: StepsData?
|
|
let activeEnergy: EnergyData?
|
|
}
|
|
|
|
struct SleepData: Codable {
|
|
let totalSleep: Double?
|
|
let deep: Double?
|
|
let rem: Double?
|
|
let core: Double?
|
|
}
|
|
|
|
struct HeartRateData: Codable {
|
|
let avg: Int?
|
|
let min: Int?
|
|
let max: Int?
|
|
}
|
|
|
|
struct RestingHRData: Codable {
|
|
let value: Double?
|
|
}
|
|
|
|
struct HRVData: Codable {
|
|
let avg: Double?
|
|
let latest: Double?
|
|
}
|
|
|
|
struct StepsData: Codable {
|
|
let total: Int?
|
|
}
|
|
|
|
struct EnergyData: Codable {
|
|
let total: Int?
|
|
let units: String?
|
|
}
|
|
|
|
// MARK: - Heatmap / Weekly Data
|
|
|
|
struct HeatmapEntry: Codable, Identifiable {
|
|
let date: String
|
|
let score: Int?
|
|
let steps: Int?
|
|
let sleep: Double?
|
|
let hrv: Double?
|
|
let rhr: Double?
|
|
|
|
var id: String { date }
|
|
|
|
var displayDate: String {
|
|
let parts = date.split(separator: "-")
|
|
guard parts.count == 3 else { return date }
|
|
return "\(parts[2]).\(parts[1])"
|
|
}
|
|
}
|
|
|
|
struct HeatmapResponse: Codable {
|
|
let data: [HeatmapEntry]
|
|
}
|