feat: Full redesign — glassmorphism, weekly charts, HealthKit sync, toast notifications
- DashboardView: полный редизайн с приветствием по времени суток, pull-to-refresh - ReadinessCardView: анимированное кольцо, цветные факторы с иконками - MetricCardView: glassmorphism карточки, градиентные иконки, SleepCard/StepsCard - WeeklyChartView: bar chart (Sleep/HRV/Steps) без внешних библиотек - ToastView: уведомления об успехе/ошибке с автоскрытием - HealthKitService: полный сбор метрик + отправка на сервер - HealthModels: HeatmapEntry для недельных данных - Тёмная тема #0a0a1a, haptic feedback, анимации появления
This commit is contained in:
@@ -1,19 +1,85 @@
|
||||
import Foundation
|
||||
|
||||
struct ReadinessResponse: Codable {
|
||||
let score: Int; let status: String; let recommendation: String
|
||||
let date: String?; let factors: ReadinessFactors?
|
||||
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
|
||||
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 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?
|
||||
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]
|
||||
}
|
||||
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? }
|
||||
|
||||
Reference in New Issue
Block a user