MealStatsView.swift 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import Charts
  2. import SwiftUI
  3. struct MealStatsView: View {
  4. let mealStats: [MealStats]
  5. let selectedDuration: Stat.StateModel.Duration
  6. private var hasData: Bool {
  7. mealStats.contains { $0.carbs > 0 || $0.fat > 0 || $0.protein > 0 }
  8. }
  9. var body: some View {
  10. ScrollView {
  11. if mealStats.isEmpty || !hasData {
  12. ContentUnavailableView(
  13. "No Meal Data",
  14. systemImage: "fork.knife",
  15. description: Text("Meal statistics will appear here once data is available.")
  16. )
  17. } else {
  18. StatCard {
  19. VStack(alignment: .leading, spacing: 8) {
  20. Text("Macronutrients")
  21. .font(.headline)
  22. Chart(mealStats) { stat in
  23. // Carbs Bar
  24. BarMark(
  25. x: .value("Date", stat.date, unit: .day),
  26. y: .value("Amount", stat.carbs),
  27. width: .ratio(0.6)
  28. )
  29. .foregroundStyle(Color.orange)
  30. .position(by: .value("Nutrient", "Carbs"))
  31. // Fat Bar
  32. BarMark(
  33. x: .value("Date", stat.date, unit: .day),
  34. y: .value("Amount", stat.fat),
  35. width: .ratio(0.6)
  36. )
  37. .foregroundStyle(Color.yellow)
  38. .position(by: .value("Nutrient", "Fat"))
  39. // Protein Bar
  40. BarMark(
  41. x: .value("Date", stat.date, unit: .day),
  42. y: .value("Amount", stat.protein),
  43. width: .ratio(0.6)
  44. )
  45. .foregroundStyle(Color.green)
  46. .position(by: .value("Nutrient", "Protein"))
  47. }
  48. .chartForegroundStyleScale([
  49. "Carbs": Color.orange,
  50. "Fat": Color.yellow,
  51. "Protein": Color.green
  52. ])
  53. .chartLegend(position: .top, alignment: .leading, spacing: 12)
  54. .frame(height: 200)
  55. .chartXAxis {
  56. mealChartXAxisMarks
  57. }
  58. .chartYAxis {
  59. mealChartYAxisMarks
  60. }
  61. }
  62. }
  63. .padding()
  64. }
  65. }
  66. }
  67. private var mealChartXAxisMarks: some AxisContent {
  68. AxisMarks { value in
  69. if let date = value.as(Date.self) {
  70. AxisValueLabel {
  71. switch selectedDuration {
  72. case .Day,
  73. .Today,
  74. .Week:
  75. Text(date, format: .dateTime.weekday(.abbreviated))
  76. case .Month,
  77. .Total:
  78. Text(date, format: .dateTime.day().month(.defaultDigits))
  79. }
  80. }
  81. AxisGridLine()
  82. }
  83. }
  84. }
  85. private var mealChartYAxisMarks: some AxisContent {
  86. AxisMarks(position: .leading) { value in
  87. if let amount = value.as(Double.self) {
  88. AxisValueLabel {
  89. Text("\(Int(amount))g")
  90. }
  91. AxisGridLine()
  92. }
  93. }
  94. }
  95. }