Просмотр исходного кода

Continue some restructuring WIP

Deniz Cengiz 1 год назад
Родитель
Сommit
88ea5d911e

+ 8 - 8
FreeAPS.xcodeproj/project.pbxproj

@@ -316,8 +316,8 @@
 		BD1661312B82ADAB00256551 /* CustomProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD1661302B82ADAB00256551 /* CustomProgressView.swift */; };
 		BD249D862D42FBEC00412DEB /* BareStatisticsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D852D42FBE600412DEB /* BareStatisticsView.swift */; };
 		BD249D882D42FC0000412DEB /* BolusStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D872D42FBFB00412DEB /* BolusStatsView.swift */; };
-		BD249D8A2D42FC1200412DEB /* GlucoseAreaChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D892D42FC0E00412DEB /* GlucoseAreaChart.swift */; };
-		BD249D8C2D42FC2C00412DEB /* GlucoseStackedAreaChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D8B2D42FC2500412DEB /* GlucoseStackedAreaChart.swift */; };
+		BD249D8A2D42FC1200412DEB /* GlucosePercentileChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D892D42FC0E00412DEB /* GlucosePercentileChart.swift */; };
+		BD249D8C2D42FC2C00412DEB /* GlucoseDistributionChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D8B2D42FC2500412DEB /* GlucoseDistributionChart.swift */; };
 		BD249D8E2D42FC3900412DEB /* LoopStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D8D2D42FC3600412DEB /* LoopStatsView.swift */; };
 		BD249D902D42FC4500412DEB /* MealStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D8F2D42FC4300412DEB /* MealStatsView.swift */; };
 		BD249D922D42FC5300412DEB /* SectorChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D912D42FC5000412DEB /* SectorChart.swift */; };
@@ -1039,8 +1039,8 @@
 		BD1CF8B72C1A4A8400CB930A /* ConfigOverride.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ConfigOverride.xcconfig; sourceTree = "<group>"; };
 		BD249D852D42FBE600412DEB /* BareStatisticsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BareStatisticsView.swift; sourceTree = "<group>"; };
 		BD249D872D42FBFB00412DEB /* BolusStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusStatsView.swift; sourceTree = "<group>"; };
-		BD249D892D42FC0E00412DEB /* GlucoseAreaChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseAreaChart.swift; sourceTree = "<group>"; };
-		BD249D8B2D42FC2500412DEB /* GlucoseStackedAreaChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseStackedAreaChart.swift; sourceTree = "<group>"; };
+		BD249D892D42FC0E00412DEB /* GlucosePercentileChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucosePercentileChart.swift; sourceTree = "<group>"; };
+		BD249D8B2D42FC2500412DEB /* GlucoseDistributionChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseDistributionChart.swift; sourceTree = "<group>"; };
 		BD249D8D2D42FC3600412DEB /* LoopStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopStatsView.swift; sourceTree = "<group>"; };
 		BD249D8F2D42FC4300412DEB /* MealStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealStatsView.swift; sourceTree = "<group>"; };
 		BD249D912D42FC5000412DEB /* SectorChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectorChart.swift; sourceTree = "<group>"; };
@@ -2517,8 +2517,8 @@
 				BD249D912D42FC5000412DEB /* SectorChart.swift */,
 				BD249D8F2D42FC4300412DEB /* MealStatsView.swift */,
 				BD249D8D2D42FC3600412DEB /* LoopStatsView.swift */,
-				BD249D8B2D42FC2500412DEB /* GlucoseStackedAreaChart.swift */,
-				BD249D892D42FC0E00412DEB /* GlucoseAreaChart.swift */,
+				BD249D8B2D42FC2500412DEB /* GlucoseDistributionChart.swift */,
+				BD249D892D42FC0E00412DEB /* GlucosePercentileChart.swift */,
 				BD249D872D42FBFB00412DEB /* BolusStatsView.swift */,
 				BD249D852D42FBE600412DEB /* BareStatisticsView.swift */,
 			);
@@ -3630,7 +3630,7 @@
 				CE1F6DE92BAF37C90064EB8D /* TidepoolConfigView.swift in Sources */,
 				3811DE5D25C9D4D500A708ED /* Publisher.swift in Sources */,
 				E00EEC0727368630002FF094 /* APSAssembly.swift in Sources */,
-				BD249D8A2D42FC1200412DEB /* GlucoseAreaChart.swift in Sources */,
+				BD249D8A2D42FC1200412DEB /* GlucosePercentileChart.swift in Sources */,
 				38B4F3AF25E2979F00E76A18 /* IndexedCollection.swift in Sources */,
 				58D08B222C8DAA8E00AA37D3 /* OverrideView.swift in Sources */,
 				BD0B2EF32C5998E600B3298F /* MealPresetView.swift in Sources */,
@@ -3685,7 +3685,7 @@
 				191F62682AD6B05A004D7911 /* NightscoutSettings.swift in Sources */,
 				3811DEAB25C9D88300A708ED /* HTTPResponseStatus.swift in Sources */,
 				3811DE5F25C9D4D500A708ED /* ProgressBar.swift in Sources */,
-				BD249D8C2D42FC2C00412DEB /* GlucoseStackedAreaChart.swift in Sources */,
+				BD249D8C2D42FC2C00412DEB /* GlucoseDistributionChart.swift in Sources */,
 				38E87408274F9AD000975559 /* UserNotificationsManager.swift in Sources */,
 				CE82E02528E867BA00473A9C /* AlertStorage.swift in Sources */,
 				DD1745372C55B74200211FAC /* AlgorithmSettings.swift in Sources */,

+ 58 - 86
FreeAPS/Sources/Modules/Stat/View/StatRootView.swift

@@ -41,7 +41,7 @@ extension Stat {
 
         enum GlucoseChartType: String, CaseIterable {
             case percentile = "Percentile"
-            case stacked = "Distribution"
+            case distribution = "Distribution"
         }
 
         enum InsulinChartType: String, CaseIterable {
@@ -51,8 +51,8 @@ extension Stat {
 
         enum LoopingChartType: String, CaseIterable {
             case loopingPerformance = "Looping Performance"
-            case trioUpTime = "Trio Up Time"
             case cgmConnectionTrace = "CGM Connection Trace"
+            case trioUpTime = "Trio Up-Time"
         }
 
         enum MealChartType: String, CaseIterable {
@@ -62,10 +62,30 @@ extension Stat {
 
         var body: some View {
             VStack {
-                segmentedPicker
-
-                contentView
-                    .animation(.easeInOut, value: selectedView)
+                Picker("View", selection: $selectedView) {
+                    ForEach(StatisticViewType.allCases) { viewType in
+                        Text(viewType.title).tag(viewType)
+                    }
+                }
+                .pickerStyle(.segmented)
+                .padding(.horizontal)
+
+                ScrollView {
+                    VStack(spacing: Constants.spacing) {
+                        switch selectedView {
+                        case .glucose:
+                            glucoseView
+                        case .insulin:
+                            insulinView
+                        case .looping:
+                            loopingView
+                        case .meals:
+                            mealsView
+                        }
+                    }
+                    .padding()
+                }
+                .animation(.easeInOut, value: selectedView)
             }
             .background(appState.trioBackgroundColor(for: colorScheme))
             .onAppear(perform: configureView)
@@ -73,51 +93,17 @@ extension Stat {
             .navigationTitle("Statistics")
             .toolbar {
                 ToolbarItem(placement: .topBarLeading) {
-                    closeButton
-                }
-            }
-        }
-
-        // MARK: - Views
-
-        private var segmentedPicker: some View {
-            Picker("View", selection: $selectedView) {
-                ForEach(StatisticViewType.allCases) { viewType in
-                    Text(viewType.title).tag(viewType)
-                }
-            }
-            .pickerStyle(.segmented)
-            .padding(.horizontal)
-        }
-
-        @ViewBuilder private var contentView: some View {
-            ScrollView {
-                VStack(spacing: Constants.spacing) {
-                    switch selectedView {
-                    case .glucose:
-                        glucoseView()
-                    case .insulin:
-                        insulinView()
-                    case .looping:
-                        loopingView()
-                    case .meals:
-                        mealsView()
+                    Button(action: state.hideModal) {
+                        Text("Close")
+                            .foregroundColor(.tabBar)
                     }
                 }
-                .padding()
-            }
-        }
-
-        private var closeButton: some View {
-            Button(action: state.hideModal) {
-                Text("Close")
-                    .foregroundColor(.tabBar)
             }
         }
 
         // MARK: - Stats View
 
-        @ViewBuilder func glucoseView() -> some View {
+        @ViewBuilder var glucoseView: some View {
             HStack {
                 Text("Chart Type")
                     .font(.headline)
@@ -151,7 +137,7 @@ extension Stat {
             }
         }
 
-        @ViewBuilder func insulinView() -> some View {
+        @ViewBuilder var insulinView: some View {
             HStack {
                 Text("Chart Type")
                     .font(.headline)
@@ -224,7 +210,7 @@ extension Stat {
                 VStack(spacing: Constants.spacing) {
                     switch selectedGlucoseChartType {
                     case .percentile:
-                        GlucoseAreaChart(
+                        GlucosePercentileChart(
                             glucose: state.glucoseFromPersistence,
                             highLimit: state.highLimit,
                             lowLimit: state.lowLimit,
@@ -232,8 +218,8 @@ extension Stat {
                             units: state.units,
                             hourlyStats: state.hourlyStats
                         )
-                    case .stacked:
-                        GlucoseStackedAreaChart(
+                    case .distribution:
+                        GlucoseDistributionChart(
                             glucose: state.glucoseFromPersistence,
                             highLimit: state.highLimit,
                             lowLimit: state.lowLimit,
@@ -281,7 +267,7 @@ extension Stat {
             }
         }
 
-        @ViewBuilder func loopingView() -> some View {
+        @ViewBuilder var loopingView: some View {
             HStack {
                 Text("Chart Type")
                     .font(.headline)
@@ -295,21 +281,13 @@ extension Stat {
                 }.pickerStyle(.menu)
             }.padding(.horizontal)
 
-            Picker("Duration", selection: $state.selectedDuration) {
+            Picker("Duration", selection: $state.selectedDurationForLoopStats) {
                 ForEach(StateModel.Duration.allCases, id: \.self) { duration in
                     Text(duration.rawValue)
                 }
             }
             .pickerStyle(.segmented)
 
-            // TODO: ensure looping uses same day selection
-//            Picker("Duration", selection: $state.selectedDurationForLoopStats) {
-//                ForEach(StateModel.Duration.allCases, id: \.self) { duration in
-//                    Text(duration.rawValue)
-//                }
-//            }
-//            .pickerStyle(.menu)
-
             switch selectedLoopingChartType {
             case .loopingPerformance:
                 if state.loopStatRecords.isEmpty {
@@ -355,7 +333,7 @@ extension Stat {
             }
         }
 
-        @ViewBuilder func mealsView() -> some View {
+        @ViewBuilder var mealsView: some View {
             HStack {
                 Text("Chart Type")
                     .font(.headline)
@@ -369,41 +347,35 @@ extension Stat {
                 }.pickerStyle(.menu)
             }.padding(.horizontal)
 
-            Picker("Duration", selection: $state.selectedDuration) {
+            Picker("Duration", selection: $state.selectedDurationForMealStats) {
                 ForEach(StateModel.Duration.allCases, id: \.self) { duration in
                     Text(duration.rawValue)
                 }
             }
             .pickerStyle(.segmented)
 
-            // TODO: adjust this so all tabs use the same selected days
-//            Picker("Duration", selection: $state.selectedDurationForMealStats) {
-//                ForEach(StateModel.Duration.allCases, id: \.self) { duration in
-//                    Text(duration.rawValue)
-//                }
-//            }
-//            .pickerStyle(.menu)
-
-            switch selectedMealChartType {
-            case .totalMeals:
-                var hasMealData: Bool {
-                    state.mealStats.contains { $0.carbs > 0 || $0.fat > 0 || $0.protein > 0 }
-                }
+            StatCard {
+                switch selectedMealChartType {
+                case .totalMeals:
+                    var hasMealData: Bool {
+                        state.mealStats.contains { $0.carbs > 0 || $0.fat > 0 || $0.protein > 0 }
+                    }
 
-                if state.mealStats.isEmpty || !hasMealData {
-                    ContentUnavailableView(
-                        "No Meal Data",
-                        systemImage: "fork.knife",
-                        description: Text("Meal statistics will appear here once data is available.")
-                    )
-                } else {
-                    MealStatsView(
-                        mealStats: state.mealStats,
-                        selectedDuration: state.selectedDurationForMealStats
-                    )
+                    if state.mealStats.isEmpty || !hasMealData {
+                        ContentUnavailableView(
+                            "No Meal Data",
+                            systemImage: "fork.knife",
+                            description: Text("Meal statistics will appear here once data is available.")
+                        )
+                    } else {
+                        MealStatsView(
+                            mealStats: state.mealStats,
+                            selectedDuration: state.selectedDurationForMealStats
+                        )
+                    }
+                case .mealToHypoHyperDistribution:
+                    Text("TODO: Meal to Hypoglycemia/Hyperglycemia Distribution")
                 }
-            case .mealToHypoHyperDistribution:
-                Text("TODO: Meal to Hypoglycemia/Hyperglycemia Distribution")
             }
         }
     }

+ 7 - 1
FreeAPS/Sources/Modules/Stat/View/ViewElements/BolusStatsView.swift

@@ -39,7 +39,7 @@ struct BolusStatsView: View {
                     "SMB": Color.blue,
                     "External": Color.purple
                 ])
-                .chartLegend(position: .top, alignment: .leading, spacing: 12)
+                .chartLegend(position: .bottom, alignment: .leading, spacing: 12)
                 .frame(height: 200)
                 .chartXAxis {
                     bolusStatsChartXAxisMarks
@@ -48,6 +48,12 @@ struct BolusStatsView: View {
                     bolusStatsChartYAxisMarks
                 }
             }
+
+            List {
+                ForEach(bolusStats) { _ in
+                    Text("")
+                }
+            }
         }
     }
 

+ 4 - 1
FreeAPS/Sources/Modules/Stat/View/ViewElements/GlucoseStackedAreaChart.swift

@@ -1,7 +1,7 @@
 import Charts
 import SwiftUI
 
-struct GlucoseStackedAreaChart: View {
+struct GlucoseDistributionChart: View {
     let glucose: [GlucoseStored]
     let highLimit: Decimal
     let lowLimit: Decimal
@@ -11,6 +11,9 @@ struct GlucoseStackedAreaChart: View {
 
     var body: some View {
         VStack(alignment: .leading, spacing: 8) {
+            Text("Glucose Distribution")
+                .font(.headline)
+
             Chart(glucoseRangeStats) { range in
                 ForEach(range.values, id: \.hour) { value in
                     AreaMark(

+ 56 - 49
FreeAPS/Sources/Modules/Stat/View/ViewElements/GlucoseAreaChart.swift

@@ -1,7 +1,7 @@
 import Charts
 import SwiftUI
 
-struct GlucoseAreaChart: View {
+struct GlucosePercentileChart: View {
     let glucose: [GlucoseStored]
     let highLimit: Decimal
     let lowLimit: Decimal
@@ -11,53 +11,60 @@ struct GlucoseAreaChart: View {
 
     var body: some View {
         VStack(alignment: .leading, spacing: 8) {
+            Text("Ambulatory Glucose Profile (AGP)")
+                .font(.headline)
+
             Chart {
-                if isTodayOrLast24h {
-                    // Single day line chart
-                    ForEach(glucose.sorted(by: { ($0.date ?? Date()) < ($1.date ?? Date()) }), id: \.id) { reading in
-                        LineMark(
-                            x: .value("Time", reading.date ?? Date()),
-                            y: .value("Glucose", Double(reading.glucose))
-                        )
-                        .lineStyle(StrokeStyle(lineWidth: 2))
-                        .foregroundStyle(.blue)
-                    }
-                } else {
-                    // Statistical view for longer periods
-                    // 10-90 percentile area
-                    ForEach(hourlyStats, id: \.hour) { stats in
-                        AreaMark(
-                            x: .value("Hour", Calendar.current.dateForChartHour(stats.hour)),
-                            yStart: .value("10th Percentile", stats.percentile10),
-                            yEnd: .value("90th Percentile", stats.percentile90),
-                            series: .value("10-90", "10-90")
-                        )
-                        .foregroundStyle(.blue.opacity(0.2))
-                    }
-
-                    // 25-75 percentile area
-                    ForEach(hourlyStats, id: \.hour) { stats in
-                        AreaMark(
-                            x: .value("Hour", Calendar.current.dateForChartHour(stats.hour)),
-                            yStart: .value("25th Percentile", stats.percentile25),
-                            yEnd: .value("75th Percentile", stats.percentile75),
-                            series: .value("25-75", "25-75")
-                        )
-                        .foregroundStyle(.blue.opacity(0.3))
-                    }
-
-                    // Median line
-                    ForEach(hourlyStats, id: \.hour) { stats in
-                        LineMark(
-                            x: .value("Hour", Calendar.current.dateForChartHour(stats.hour)),
-                            y: .value("Median", stats.median),
-                            series: .value("Median", "Median")
-                        )
-                        .lineStyle(StrokeStyle(lineWidth: 2))
-                        .foregroundStyle(.blue)
-                    }
+//                if isTodayOrLast24h {
+//                    // Single day line chart
+//                    ForEach(glucose.sorted(by: { ($0.date ?? Date()) < ($1.date ?? Date()) }), id: \.id) { reading in
+//                        LineMark(
+//                            x: .value("Time", reading.date ?? Date()),
+//                            y: .value("Glucose", Double(reading.glucose))
+//                        )
+//                        .lineStyle(StrokeStyle(lineWidth: 2))
+//                        .foregroundStyle(.blue)
+//                    }
+//                } else {
+
+                // TODO: ensure data is still correct
+                // TODO: ensure area marks and line mark take color of respective range
+
+                // Statistical view for longer periods
+                // 10-90 percentile area
+                ForEach(hourlyStats, id: \.hour) { stats in
+                    AreaMark(
+                        x: .value("Hour", Calendar.current.dateForChartHour(stats.hour)),
+                        yStart: .value("10th Percentile", stats.percentile10),
+                        yEnd: .value("90th Percentile", stats.percentile90),
+                        series: .value("10-90", "10-90")
+                    )
+                    .foregroundStyle(.blue.opacity(stats.median > 0 ? 0.2 : 0))
                 }
 
+                // 25-75 percentile area
+                ForEach(hourlyStats, id: \.hour) { stats in
+                    AreaMark(
+                        x: .value("Hour", Calendar.current.dateForChartHour(stats.hour)),
+                        yStart: .value("25th Percentile", stats.percentile25),
+                        yEnd: .value("75th Percentile", stats.percentile75),
+                        series: .value("25-75", "25-75")
+                    )
+                    .foregroundStyle(.blue.opacity(stats.median > 0 ? 0.3 : 0))
+                }
+
+                // Median line
+                ForEach(hourlyStats.filter { $0.median > 0 }, id: \.hour) { stats in
+                    LineMark(
+                        x: .value("Hour", Calendar.current.dateForChartHour(stats.hour)),
+                        y: .value("Median", stats.median),
+                        series: .value("Median", "Median")
+                    )
+                    .lineStyle(StrokeStyle(lineWidth: 2))
+                    .foregroundStyle(.blue)
+                }
+//                }
+
                 // High/Low limit lines
                 RuleMark(y: .value("High Limit", Double(highLimit)))
                     .lineStyle(StrokeStyle(lineWidth: 1, dash: [5, 5]))
@@ -67,7 +74,7 @@ struct GlucoseAreaChart: View {
                     .lineStyle(StrokeStyle(lineWidth: 1, dash: [5, 5]))
                     .foregroundStyle(.red)
             }
-            .chartYScale(domain: 40 ... 400)
+//            .chartYScale(domain: 40 ... 400)
             .chartYAxis {
                 AxisMarks(position: .leading)
             }
@@ -86,9 +93,9 @@ struct GlucoseAreaChart: View {
             .frame(height: 200)
 
             // Legend
-            if !isTodayOrLast24h {
-                legend
-            }
+//            if !isTodayOrLast24h {
+            legend
+//            }
         }
     }
 

+ 41 - 43
FreeAPS/Sources/Modules/Stat/View/ViewElements/MealStatsView.swift

@@ -6,52 +6,50 @@ struct MealStatsView: View {
     let selectedDuration: Stat.StateModel.Duration
 
     var body: some View {
-        StatCard {
-            VStack(alignment: .leading, spacing: 8) {
-                Text("Macronutrients")
-                    .font(.headline)
+        VStack(alignment: .leading, spacing: 8) {
+            Text("Macronutrients")
+                .font(.headline)
 
-                Chart(mealStats) { stat in
-                    // Carbs Bar
-                    BarMark(
-                        x: .value("Date", stat.date, unit: .day),
-                        y: .value("Amount", stat.carbs),
-                        width: .ratio(0.6)
-                    )
-                    .foregroundStyle(Color.orange)
-                    .position(by: .value("Nutrient", "Carbs"))
+            Chart(mealStats) { stat in
+                // Carbs Bar
+                BarMark(
+                    x: .value("Date", stat.date, unit: .day),
+                    y: .value("Amount", stat.carbs),
+                    width: .ratio(0.6)
+                )
+                .foregroundStyle(Color.orange)
+                .position(by: .value("Nutrient", "Carbs"))
 
-                    // Fat Bar
-                    BarMark(
-                        x: .value("Date", stat.date, unit: .day),
-                        y: .value("Amount", stat.fat),
-                        width: .ratio(0.6)
-                    )
-                    .foregroundStyle(Color.yellow)
-                    .position(by: .value("Nutrient", "Fat"))
+                // Fat Bar
+                BarMark(
+                    x: .value("Date", stat.date, unit: .day),
+                    y: .value("Amount", stat.fat),
+                    width: .ratio(0.6)
+                )
+                .foregroundStyle(Color.yellow)
+                .position(by: .value("Nutrient", "Fat"))
 
-                    // Protein Bar
-                    BarMark(
-                        x: .value("Date", stat.date, unit: .day),
-                        y: .value("Amount", stat.protein),
-                        width: .ratio(0.6)
-                    )
-                    .foregroundStyle(Color.green)
-                    .position(by: .value("Nutrient", "Protein"))
-                }
-                .chartForegroundStyleScale([
-                    "Carbs": Color.orange,
-                    "Fat": Color.yellow,
-                    "Protein": Color.green
-                ])
-                .chartLegend(position: .top, alignment: .leading, spacing: 12)
-                .frame(height: 200)
-                .chartXAxis {
-                    mealChartXAxisMarks
-                }
-                .chartYAxis {
-                    mealChartYAxisMarks
-                }
+                // Protein Bar
+                BarMark(
+                    x: .value("Date", stat.date, unit: .day),
+                    y: .value("Amount", stat.protein),
+                    width: .ratio(0.6)
+                )
+                .foregroundStyle(Color.green)
+                .position(by: .value("Nutrient", "Protein"))
+            }
+            .chartForegroundStyleScale([
+                "Carbs": Color.orange,
+                "Fat": Color.yellow,
+                "Protein": Color.green
+            ])
+            .chartLegend(position: .bottom, alignment: .leading, spacing: 12)
+            .frame(height: 200)
+            .chartXAxis {
+                mealChartXAxisMarks
+            }
+            .chartYAxis {
+                mealChartYAxisMarks
             }
         }
     }