Explorar o código

Refactoring cont'd; carb ratio and basal rates WIP

Deniz Cengiz hai 1 ano
pai
achega
79c159933a

+ 1 - 33
Trio/Sources/Localizations/Main/Localizable.xcstrings

@@ -6038,6 +6038,7 @@
       }
       }
     },
     },
     "%@ g/U" : {
     "%@ g/U" : {
+      "extractionState" : "stale",
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
           "stringUnit" : {
           "stringUnit" : {
@@ -6438,9 +6439,6 @@
         }
         }
       }
       }
     },
     },
-    "%@ U/h" : {
-
-    },
     "%@ U/hr" : {
     "%@ U/hr" : {
       "comment" : "Number of units per hour",
       "comment" : "Number of units per hour",
       "localizations" : {
       "localizations" : {
@@ -11796,9 +11794,6 @@
         }
         }
       }
       }
     },
     },
-    "• Lower rates are typically needed during sleep or periods of activity" : {
-
-    },
     "• Maximum Duration" : {
     "• Maximum Duration" : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -12099,9 +12094,6 @@
         }
         }
       }
       }
     },
     },
-    "• Morning hours may require more insulin due to 'dawn phenomenon'" : {
-
-    },
     "• Nightscout" : {
     "• Nightscout" : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -12702,9 +12694,6 @@
         }
         }
       }
       }
     },
     },
-    "• Rates should be adjusted based on your body's varying insulin needs" : {
-
-    },
     "• Secondary Font Size: Adjust text size for values in split layouts." : {
     "• Secondary Font Size: Adjust text size for values in split layouts." : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -13205,9 +13194,6 @@
         }
         }
       }
       }
     },
     },
-    "• The basal profile provides background insulin throughout the day" : {
-
-    },
     "• xDrip4iOS" : {
     "• xDrip4iOS" : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -44093,9 +44079,6 @@
         }
         }
       }
       }
     },
     },
-    "Carb Ratio Profile" : {
-
-    },
     "Carb Ratio:" : {
     "Carb Ratio:" : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -48698,12 +48681,6 @@
     "Choose type of time in range to be used for Trio's statistics." : {
     "Choose type of time in range to be used for Trio's statistics." : {
 
 
     },
     },
-    "Choose when this basal rate should start" : {
-
-    },
-    "Choose when this carb ratio should start" : {
-
-    },
     "Choose when this sensitivity factor should start" : {
     "Choose when this sensitivity factor should start" : {
 
 
     },
     },
@@ -185333,9 +185310,6 @@
         }
         }
       }
       }
     },
     },
-    "Unable to Save Basal Profile" : {
-
-    },
     "Unable to Save ISF Profile" : {
     "Unable to Save ISF Profile" : {
 
 
     },
     },
@@ -195902,12 +195876,6 @@
     "You've successfully completed the initial setup of Trio. Your settings have been saved and you're ready to start using the app." : {
     "You've successfully completed the initial setup of Trio. Your settings have been saved and you're ready to start using the app." : {
 
 
     },
     },
-    "Your basal insulin profile determines how much background insulin you receive throughout the day." : {
-
-    },
-    "Your carb ratio tells how many grams of carbohydrates one unit of insulin will cover." : {
-
-    },
     "Your entered amount was limited by your max Bolus setting of %d%@" : {
     "Your entered amount was limited by your max Bolus setting of %d%@" : {
       "comment" : "For the  Bolus View pop-up",
       "comment" : "For the  Bolus View pop-up",
       "extractionState" : "manual",
       "extractionState" : "manual",

+ 44 - 2
Trio/Sources/Modules/Onboarding/OnboardingStateModel.swift

@@ -201,9 +201,9 @@ extension Onboarding {
             settingsManager.settings = settingsCopy
             settingsManager.settings = settingsCopy
         }
         }
 
 
-        func getTherapyItems(from targets: [TargetsEditor.Item]) -> [TherapySettingItem] {
+        func getTargetTherapyItems(from targets: [TargetsEditor.Item]) -> [TherapySettingItem] {
             targets.map {
             targets.map {
-                return TherapySettingItem(
+                TherapySettingItem(
                     id: UUID(),
                     id: UUID(),
                     time: targetTimeValues[$0.timeIndex],
                     time: targetTimeValues[$0.timeIndex],
                     value: Double(targetRateValues[$0.lowIndex])
                     value: Double(targetRateValues[$0.lowIndex])
@@ -221,6 +221,48 @@ extension Onboarding {
                 return TargetsEditor.Item(lowIndex: closestRate, highIndex: closestRate, timeIndex: timeIndex)
                 return TargetsEditor.Item(lowIndex: closestRate, highIndex: closestRate, timeIndex: timeIndex)
             }
             }
         }
         }
+
+        func getBasalTherapyItems(from basalRates: [BasalProfileEditor.Item]) -> [TherapySettingItem] {
+            basalRates.map {
+                TherapySettingItem(
+                    id: UUID(),
+                    time: basalProfileTimeValues[$0.timeIndex],
+                    value: Double(basalProfileRateValues[$0.rateIndex])
+                )
+            }
+        }
+
+        func updateBasalRates(from therapyItems: [TherapySettingItem]) {
+            basalProfileItems = therapyItems.map { item in
+                let timeIndex = basalProfileTimeValues.firstIndex(where: { $0 == item.time }) ?? 0
+                let closestRate = basalProfileRateValues.enumerated().min(by: {
+                    abs(Double($0.element) - item.value) < abs(Double($1.element) - item.value)
+                })?.offset ?? 0
+
+                return BasalProfileEditor.Item(rateIndex: closestRate, timeIndex: timeIndex)
+            }
+        }
+
+        func getCarbRatioTherapyItems(from basalRates: [CarbRatioEditor.Item]) -> [TherapySettingItem] {
+            basalRates.map {
+                TherapySettingItem(
+                    id: UUID(),
+                    time: carbRatioTimeValues[$0.timeIndex],
+                    value: Double(carbRatioRateValues[$0.rateIndex])
+                )
+            }
+        }
+
+        func updateCarbRatios(from therapyItems: [TherapySettingItem]) {
+            carbRatioItems = therapyItems.map { item in
+                let timeIndex = carbRatioTimeValues.firstIndex(where: { $0 == item.time }) ?? 0
+                let closestRate = carbRatioRateValues.enumerated().min(by: {
+                    abs(Double($0.element) - item.value) < abs(Double($1.element) - item.value)
+                })?.offset ?? 0
+
+                return CarbRatioEditor.Item(rateIndex: closestRate, timeIndex: timeIndex)
+            }
+        }
     }
     }
 }
 }
 
 

+ 31 - 189
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/BasalProfileStepView.swift

@@ -11,11 +11,8 @@ import UIKit
 /// Basal profile step view for setting basal insulin rates.
 /// Basal profile step view for setting basal insulin rates.
 struct BasalProfileStepView: View {
 struct BasalProfileStepView: View {
     @Bindable var state: Onboarding.StateModel
     @Bindable var state: Onboarding.StateModel
-    @State private var showTimeSelector = false
-    @State private var selectedBasalIndex: Int?
-    @State private var showAlert = false
-    @State private var errorMessage = ""
     @State private var refreshUI = UUID() // to update chart when slider value changes
     @State private var refreshUI = UUID() // to update chart when slider value changes
+    @State private var therapyItems: [TherapySettingItem] = []
 
 
     // For chart scaling
     // For chart scaling
     private let chartScale = Calendar.current
     private let chartScale = Calendar.current
@@ -37,148 +34,24 @@ struct BasalProfileStepView: View {
 
 
     var body: some View {
     var body: some View {
         ScrollView {
         ScrollView {
-            VStack(alignment: .leading, spacing: 20) {
-                Text("Your basal insulin profile determines how much background insulin you receive throughout the day.")
-                    .font(.subheadline)
-                    .foregroundColor(.secondary)
-                    .padding(.horizontal)
-
+            VStack(alignment: .leading, spacing: 0) {
                 // Chart visualization
                 // Chart visualization
                 if !state.basalProfileItems.isEmpty {
                 if !state.basalProfileItems.isEmpty {
                     VStack(alignment: .leading) {
                     VStack(alignment: .leading) {
-                        Text("Basal Profile")
-                            .font(.headline)
-                            .padding(.horizontal)
-
                         basalProfileChart
                         basalProfileChart
                             .frame(height: 180)
                             .frame(height: 180)
                             .padding(.horizontal)
                             .padding(.horizontal)
                     }
                     }
-                    .padding(.vertical, 5)
-                    .background(Color.purple.opacity(0.05))
+                    .padding(.vertical)
+                    .background(Color.chart.opacity(0.45))
                     .cornerRadius(10)
                     .cornerRadius(10)
                 }
                 }
 
 
-                // Basal rates list
-                VStack(alignment: .leading, spacing: 10) {
-                    HStack {
-                        Text("Basal Rates")
-                            .font(.headline)
-
-                        Spacer()
-
-                        // Add new basal rate button
-                        if state.basalProfileItems.count < 24 {
-                            Button(action: {
-                                showTimeSelector = true
-                            }) {
-                                HStack {
-                                    Image(systemName: "plus.circle.fill")
-                                    Text("Add Rate")
-                                }
-                                .foregroundColor(.purple)
-                            }
-                            .disabled(!canAddBasalRate)
-                        }
-                    }
-                    .padding(.horizontal)
-
-                    // List of basal rates
-                    VStack(spacing: 2) {
-                        ForEach(Array(state.basalProfileItems.enumerated()), id: \.element.id) { index, item in
-                            HStack {
-                                // Time display
-                                Text(
-                                    dateFormatter
-                                        .string(from: Date(
-                                            timeIntervalSince1970: state
-                                                .basalProfileTimeValues[item.timeIndex]
-                                        ))
-                                )
-                                .frame(width: 80, alignment: .leading)
-                                .padding(.leading)
-
-                                // Rate slider
-                                Slider(
-                                    value: Binding(
-                                        get: {
-                                            guard !state.basalProfileRateValues.isEmpty,
-                                                  item.rateIndex < state.basalProfileRateValues.count
-                                            else {
-                                                return 0.0
-                                            }
-                                            return Double(
-                                                truncating: state
-                                                    .basalProfileRateValues[item.rateIndex] as NSNumber
-                                            )
-                                        },
-                                        set: { newValue in
-                                            guard !state.basalProfileRateValues.isEmpty else { return }
-
-                                            // Find closest match in rateValues array
-                                            let newIndex = state.basalProfileRateValues
-                                                .firstIndex { abs(Double($0) - newValue) < 0.005 } ?? item.rateIndex
-
-                                            // Ensure index is valid before updating
-                                            if newIndex < state.basalProfileRateValues.count,
-                                               index < state.basalProfileItems.count
-                                            {
-                                                state.basalProfileItems[index].rateIndex = newIndex
-                                                // Force refresh when slider changes
-                                                refreshUI = UUID()
-                                            }
-                                        }
-                                    ),
-                                    in: state.basalProfileRateValues.isEmpty ? 0 ... 1 :
-                                        Double(truncating: state.basalProfileRateValues.first! as NSNumber) ...
-                                        Double(truncating: state.basalProfileRateValues.last! as NSNumber),
-                                    step: 0.05
-                                )
-                                .accentColor(.purple)
-                                .padding(.horizontal, 5)
-                                .onChange(of: state.basalProfileItems[index].rateIndex) { _, _ in
-                                    // Trigger immediate UI update when slider value changes
-                                    let impact = UIImpactFeedbackGenerator(style: .light)
-                                    impact.impactOccurred()
-                                }
-
-                                // Display the current value
-                                Text(
-                                    "\(state.basalProfileRateValues.isEmpty || item.rateIndex >= state.basalProfileRateValues.count ? "--" : formatter.string(from: state.basalProfileRateValues[item.rateIndex] as NSNumber) ?? "--") U/h"
-                                )
-                                .frame(width: 80, alignment: .trailing)
-                                .lineLimit(1)
-                                .minimumScaleFactor(0.8)
-
-                                // Delete button (not for the first entry at 00:00)
-                                if index > 0 {
-                                    Button(action: {
-                                        state.basalProfileItems.remove(at: index)
-                                    }) {
-                                        Image(systemName: "trash")
-                                            .foregroundColor(.red)
-                                            .padding(.horizontal, 5)
-                                    }
-                                } else {
-                                    // Spacer to maintain alignment
-                                    Spacer()
-                                        .frame(width: 30)
-                                }
-                            }
-                            .padding(.vertical, 12)
-                            .background(index % 2 == 0 ? Color.purple.opacity(0.05) : Color.clear)
-                            .cornerRadius(8)
-                        }
-                    }
-                    .background(Color.purple.opacity(0.05))
-                    .cornerRadius(10)
-                    .padding(.horizontal)
-                    .onAppear {
-                        if state.basalProfileItems.isEmpty {
-                            addBasalRate()
-                        }
-                    }
-                }
+                TimeValueEditorView(
+                    items: $therapyItems,
+                    unit: String(localized: "U/hr"),
+                    valueOptions: state.basalProfileRateValues
+                ).scaledToFit()
 
 
                 // Total daily basal calculation
                 // Total daily basal calculation
                 if !state.basalProfileItems.isEmpty {
                 if !state.basalProfileItems.isEmpty {
@@ -199,63 +72,32 @@ struct BasalProfileStepView: View {
                     .padding(.top)
                     .padding(.top)
 
 
                     // Information about basal rates
                     // Information about basal rates
-                    VStack(alignment: .leading, spacing: 8) {
-                        Text("What This Means")
-                            .font(.headline)
-                            .padding(.horizontal)
-
-                        VStack(alignment: .leading, spacing: 4) {
-                            Text("• The basal profile provides background insulin throughout the day")
-                            Text("• Rates should be adjusted based on your body's varying insulin needs")
-                            Text("• Morning hours may require more insulin due to 'dawn phenomenon'")
-                            Text("• Lower rates are typically needed during sleep or periods of activity")
-                        }
-                        .font(.caption)
-                        .foregroundColor(.secondary)
-                        .padding(.horizontal)
-                    }
+//                    VStack(alignment: .leading, spacing: 8) {
+//                        Text("What This Means")
+//                            .font(.headline)
+//                            .padding(.horizontal)
+//
+//                        VStack(alignment: .leading, spacing: 4) {
+//                            Text("• The basal profile provides background insulin throughout the day")
+//                            Text("• Rates should be adjusted based on your body's varying insulin needs")
+//                            Text("• Morning hours may require more insulin due to 'dawn phenomenon'")
+//                            Text("• Lower rates are typically needed during sleep or periods of activity")
+//                        }
+//                        .font(.caption)
+//                        .foregroundColor(.secondary)
+//                        .padding(.horizontal)
+//                    }
                 }
                 }
             }
             }
-            .padding(.vertical)
         }
         }
-        .actionSheet(isPresented: $showTimeSelector) {
-            var buttons: [ActionSheet.Button] = []
-
-            // Find available time slots in 1-hour increments
-            for hour in 0 ..< 24 {
-                let hourInMinutes = hour * 60
-                // Calculate timeIndex for this hour
-                let timeIndex = state.basalProfileTimeValues
-                    .firstIndex { abs($0 - Double(hourInMinutes * 60)) < 10 } ?? 0
-
-                // Check if this hour is already in the profile
-                if !state.basalProfileItems.contains(where: { $0.timeIndex == timeIndex }) {
-                    buttons.append(.default(Text("\(String(format: "%02d:00", hour))")) {
-                        // Get the current rate from the last item
-                        let rateIndex = state.basalProfileItems.last?.rateIndex ?? 20 // 1.0 U/h as default
-                        // Create new item with the specified time
-                        let newItem = BasalProfileEditor.Item(rateIndex: rateIndex, timeIndex: timeIndex)
-                        // Add the new item and sort the list
-                        state.basalProfileItems.append(newItem)
-                        state.basalProfileItems.sort(by: { $0.timeIndex < $1.timeIndex })
-                    })
-                }
+        .onAppear {
+            if state.basalProfileItems.isEmpty {
+                state.addBasalRate()
             }
             }
-
-            buttons.append(.cancel())
-
-            return ActionSheet(
-                title: Text("Select Start Time"),
-                message: Text("Choose when this basal rate should start"),
-                buttons: buttons
-            )
-        }
-        .alert(isPresented: $showAlert) {
-            Alert(
-                title: Text("Unable to Save Basal Profile"),
-                message: Text(errorMessage),
-                dismissButton: .default(Text("OK"))
-            )
+            therapyItems = state.getBasalTherapyItems(from: state.basalProfileItems)
+        }.onChange(of: therapyItems) { _, newItems in
+            state.updateBasalRates(from: newItems)
+            refreshUI = UUID()
         }
         }
     }
     }
 
 

+ 16 - 148
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/CarbRatioStepView.swift

@@ -11,9 +11,8 @@ import UIKit
 /// Carb ratio step view for setting insulin-to-carb ratio.
 /// Carb ratio step view for setting insulin-to-carb ratio.
 struct CarbRatioStepView: View {
 struct CarbRatioStepView: View {
     @Bindable var state: Onboarding.StateModel
     @Bindable var state: Onboarding.StateModel
-    @State private var showTimeSelector = false
-    @State private var selectedRatioIndex: Int?
     @State private var refreshUI = UUID() // to update chart when slider value changes
     @State private var refreshUI = UUID() // to update chart when slider value changes
+    @State private var therapyItems: [TherapySettingItem] = []
 
 
     // For chart scaling
     // For chart scaling
     private let chartScale = Calendar.current
     private let chartScale = Calendar.current
@@ -35,132 +34,24 @@ struct CarbRatioStepView: View {
 
 
     var body: some View {
     var body: some View {
         ScrollView {
         ScrollView {
-            VStack(alignment: .leading, spacing: 20) {
-                Text("Your carb ratio tells how many grams of carbohydrates one unit of insulin will cover.")
-                    .font(.subheadline)
-                    .foregroundColor(.secondary)
-                    .padding(.horizontal)
-
+            VStack(alignment: .leading, spacing: 0) {
                 // Chart visualization
                 // Chart visualization
                 if !state.carbRatioItems.isEmpty {
                 if !state.carbRatioItems.isEmpty {
                     VStack(alignment: .leading) {
                     VStack(alignment: .leading) {
-                        Text("Carb Ratio Profile")
-                            .font(.headline)
-                            .padding(.horizontal)
-
                         carbRatioChart
                         carbRatioChart
                             .frame(height: 180)
                             .frame(height: 180)
                             .padding(.horizontal)
                             .padding(.horizontal)
                     }
                     }
-                    .padding(.vertical, 5)
-                    .background(Color.orange.opacity(0.05))
+                    .padding(.vertical)
+                    .background(Color.chart.opacity(0.45))
                     .cornerRadius(10)
                     .cornerRadius(10)
                 }
                 }
 
 
-                // Carb ratios list
-                VStack(alignment: .leading, spacing: 10) {
-                    HStack {
-                        Text("Carb Ratios")
-                            .font(.headline)
-
-                        Spacer()
-
-                        // Add new carb ratio button
-                        if state.carbRatioItems.count < 24 {
-                            Button(action: {
-                                showTimeSelector = true
-                            }) {
-                                HStack {
-                                    Image(systemName: "plus.circle.fill")
-                                    Text("Add Ratio")
-                                }
-                                .foregroundColor(.orange)
-                            }
-                            .disabled(!canAddRatio)
-                        }
-                    }
-                    .padding(.horizontal)
-
-                    // List of carb ratios
-                    VStack(spacing: 2) {
-                        ForEach(Array(state.carbRatioItems.enumerated()), id: \.element.id) { index, item in
-                            HStack {
-                                // Time display
-                                Text(
-                                    dateFormatter
-                                        .string(from: Date(
-                                            timeIntervalSince1970: state
-                                                .carbRatioTimeValues[item.timeIndex]
-                                        ))
-                                )
-                                .frame(width: 80, alignment: .leading)
-                                .padding(.leading)
-
-                                // Ratio slider
-                                Slider(
-                                    value: Binding(
-                                        get: {
-                                            Double(
-                                                truncating: state
-                                                    .carbRatioRateValues[item.rateIndex] as NSNumber
-                                            ) },
-                                        set: { newValue in
-                                            // Find closest match in rateValues array
-                                            let newIndex = state.carbRatioRateValues
-                                                .firstIndex { abs(Double($0) - newValue) < 0.05 } ?? item.rateIndex
-                                            state.carbRatioItems[index].rateIndex = newIndex
-                                            // Force refresh when slider changes
-                                            refreshUI = UUID()
-                                        }
-                                    ),
-                                    in: Double(truncating: state.carbRatioRateValues.first! as NSNumber) ...
-                                        Double(truncating: state.carbRatioRateValues.last! as NSNumber),
-                                    step: 0.5
-                                )
-                                .accentColor(.orange)
-                                .padding(.horizontal, 5)
-                                .onChange(of: state.carbRatioItems[index].rateIndex) { _, _ in
-                                    let impact = UIImpactFeedbackGenerator(style: .light)
-                                    impact.impactOccurred()
-                                }
-
-                                // Display the current value
-                                Text(
-                                    "\(formatter.string(from: state.carbRatioRateValues[item.rateIndex] as NSNumber) ?? "--") g/U"
-                                )
-                                .frame(width: 80, alignment: .trailing)
-                                .lineLimit(1)
-                                .minimumScaleFactor(0.8)
-
-                                // Delete button (not for the first entry at 00:00)
-                                if index > 0 {
-                                    Button(action: {
-                                        state.carbRatioItems.remove(at: index)
-                                    }) {
-                                        Image(systemName: "trash")
-                                            .foregroundColor(.red)
-                                            .padding(.horizontal, 5)
-                                    }
-                                } else {
-                                    // Spacer to maintain alignment
-                                    Spacer()
-                                        .frame(width: 30)
-                                }
-                            }
-                            .padding(.vertical, 12)
-                            .background(index % 2 == 0 ? Color.orange.opacity(0.05) : Color.clear)
-                            .cornerRadius(8)
-                        }
-                    }
-                    .background(Color.orange.opacity(0.05))
-                    .cornerRadius(10)
-                    .padding(.horizontal)
-                    .onAppear {
-                        if state.carbRatioItems.isEmpty {
-                            state.addCarbRatio()
-                        }
-                    }
-                }
+                TimeValueEditorView(
+                    items: $therapyItems,
+                    unit: String(localized: "g/U"),
+                    valueOptions: state.carbRatioRateValues
+                ).scaledToFit()
 
 
                 // Example calculation based on first carb ratio
                 // Example calculation based on first carb ratio
                 if !state.carbRatioItems.isEmpty {
                 if !state.carbRatioItems.isEmpty {
@@ -215,38 +106,15 @@ struct CarbRatioStepView: View {
                     }
                     }
                 }
                 }
             }
             }
-            .padding(.vertical)
         }
         }
-        .actionSheet(isPresented: $showTimeSelector) {
-            var buttons: [ActionSheet.Button] = []
-
-            // Find available time slots in 1-hour increments
-            for hour in 0 ..< 24 {
-                let hourInMinutes = hour * 60
-                // Calculate timeIndex for this hour
-                let timeIndex = state.carbRatioTimeValues.firstIndex { abs($0 - Double(hourInMinutes * 60)) < 10 } ?? 0
-
-                // Check if this hour is already in the profile
-                if !state.carbRatioItems.contains(where: { $0.timeIndex == timeIndex }) {
-                    buttons.append(.default(Text("\(String(format: "%02d:00", hour))")) {
-                        // Get the current ratio from the last item
-                        let rateIndex = state.carbRatioItems.last?.rateIndex ?? 0
-                        // Create new item with the specified time
-                        let newItem = CarbRatioEditor.Item(rateIndex: rateIndex, timeIndex: timeIndex)
-                        // Add the new item and sort the list
-                        state.carbRatioItems.append(newItem)
-                        state.carbRatioItems.sort(by: { $0.timeIndex < $1.timeIndex })
-                    })
-                }
+        .onAppear {
+            if state.carbRatioItems.isEmpty {
+                state.addCarbRatio()
             }
             }
-
-            buttons.append(.cancel())
-
-            return ActionSheet(
-                title: Text("Select Start Time"),
-                message: Text("Choose when this carb ratio should start"),
-                buttons: buttons
-            )
+            therapyItems = state.getCarbRatioTherapyItems(from: state.carbRatioItems)
+        }.onChange(of: therapyItems) { _, newItems in
+            state.updateCarbRatios(from: newItems)
+            refreshUI = UUID()
         }
         }
     }
     }
 
 

+ 2 - 2
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/GlucoseTargetStepView.swift

@@ -44,7 +44,7 @@ struct GlucoseTargetStepView: View {
                             .padding(.horizontal)
                             .padding(.horizontal)
                     }
                     }
                     .padding(.vertical)
                     .padding(.vertical)
-                    .background(Color.chart)
+                    .background(Color.chart.opacity(0.45))
                     .clipShape(
                     .clipShape(
                         .rect(
                         .rect(
                             topLeadingRadius: 10,
                             topLeadingRadius: 10,
@@ -67,7 +67,7 @@ struct GlucoseTargetStepView: View {
             if state.targetItems.isEmpty {
             if state.targetItems.isEmpty {
                 state.addTarget()
                 state.addTarget()
             }
             }
-            therapyItems = state.getTherapyItems(from: state.targetItems)
+            therapyItems = state.getTargetTherapyItems(from: state.targetItems)
         }.onChange(of: therapyItems) { _, newItems in
         }.onChange(of: therapyItems) { _, newItems in
             state.updateTargets(from: newItems)
             state.updateTargets(from: newItems)
             refreshUI = UUID()
             refreshUI = UUID()

+ 14 - 8
Trio/Sources/Modules/Onboarding/View/OnboardingView+Util.swift

@@ -70,13 +70,13 @@ struct TimeValueEditorView: View {
                     items.append(TherapySettingItem(time: newTime, value: newValue))
                     items.append(TherapySettingItem(time: newTime, value: newValue))
                 } label: {
                 } label: {
                     HStack {
                     HStack {
-                        Image(systemName: "plus")
+                        Image(systemName: "plus.circle.fill")
                         Text("Add")
                         Text("Add")
                     }.foregroundColor(.accentColor)
                     }.foregroundColor(.accentColor)
                 }
                 }
                 .disabled(items.count >= 48)
                 .disabled(items.count >= 48)
             }
             }
-            .listRowBackground(Color.chart)
+            .listRowBackground(Color.chart.opacity(0.45))
             .padding(.vertical, 5)
             .padding(.vertical, 5)
 
 
             ForEach($items) { $item in
             ForEach($items) { $item in
@@ -85,16 +85,22 @@ struct TimeValueEditorView: View {
                         selectedItemID = selectedItemID == item.id ? nil : item.id
                         selectedItemID = selectedItemID == item.id ? nil : item.id
                     } label: {
                     } label: {
                         HStack {
                         HStack {
-                            let startDate = Date(timeIntervalSinceReferenceDate: item.time)
-                            Text(timeFormatter.string(from: startDate))
-                                .foregroundStyle(selectedItemID == item.id ? Color.accentColor : Color.primary)
-                            Spacer()
                             HStack {
                             HStack {
                                 Text("\(item.value, specifier: "%.1f")")
                                 Text("\(item.value, specifier: "%.1f")")
                                     .foregroundStyle(selectedItemID == item.id ? Color.accentColor : Color.primary)
                                     .foregroundStyle(selectedItemID == item.id ? Color.accentColor : Color.primary)
                                 Text(unit.description)
                                 Text(unit.description)
                                     .foregroundStyle(Color.secondary)
                                     .foregroundStyle(Color.secondary)
                             }
                             }
+
+                            Spacer()
+
+                            HStack {
+                                Text("starts at").foregroundStyle(Color.secondary)
+
+                                let startDate = Date(timeIntervalSinceReferenceDate: item.time)
+                                Text(timeFormatter.string(from: startDate))
+                                    .foregroundStyle(selectedItemID == item.id ? Color.accentColor : Color.primary)
+                            }
                         }.contentShape(Rectangle())
                         }.contentShape(Rectangle())
                     }
                     }
                     .buttonStyle(.plain)
                     .buttonStyle(.plain)
@@ -119,9 +125,9 @@ struct TimeValueEditorView: View {
                     }
                     }
                 }
                 }
             }
             }
-            .listRowBackground(Color.chart)
+            .listRowBackground(Color.chart.opacity(0.45))
 
 
-            Rectangle().fill(Color.chart).frame(height: 10)
+            Rectangle().fill(Color.chart.opacity(0.45)).frame(height: 10)
                 .clipShape(
                 .clipShape(
                     .rect(
                     .rect(
                         topLeadingRadius: 0,
                         topLeadingRadius: 0,

+ 2 - 1
Trio/Sources/Modules/Onboarding/View/OnboardingView.swift

@@ -146,7 +146,8 @@ extension Onboarding {
                                 .foregroundColor(.white)
                                 .foregroundColor(.white)
                                 .background(
                                 .background(
                                     Capsule()
                                     Capsule()
-                                        .fill(currentStep.accentColor)
+//                                        .fill(currentStep.accentColor)
+                                        .fill(Color.blue)
                                 )
                                 )
                             }
                             }
                         }
                         }