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

Refactor.
Use CoreData.
Clean up (needs nore)

Jon Mårtensson 2 лет назад
Родитель
Сommit
eb7c23b38f

+ 8 - 0
Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents

@@ -54,6 +54,14 @@
         <attribute name="loopStatus" optional="YES" attributeType="String"/>
         <attribute name="start" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
     </entity>
+    <entity name="Meals" representedClassName="Meals" syncable="YES" codeGenerationType="class">
+        <attribute name="carbs" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
+        <attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
+        <attribute name="fat" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
+        <attribute name="id" optional="YES" attributeType="String"/>
+        <attribute name="note" optional="YES" attributeType="String"/>
+        <attribute name="protein" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
+    </entity>
     <entity name="Oref0Suggestion" representedClassName="Oref0Suggestion" syncable="YES" codeGenerationType="class">
         <relationship name="computedInsulinDistribution" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="InsulinDistribution" inverseName="insulin" inverseEntity="InsulinDistribution"/>
         <relationship name="computedTDD" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="TDD" inverseName="computed" inverseEntity="TDD"/>

+ 12 - 10
FreeAPS/Sources/APS/Storage/CarbsStorage.swift

@@ -12,7 +12,7 @@ protocol CarbsStorage {
     func syncDate() -> Date
     func recent() -> [CarbsEntry]
     func nightscoutTretmentsNotUploaded() -> [NigtscoutTreatment]
-    func deleteCarbs(at date: String, complex: Bool?)
+    func deleteCarbs(at uniqueID: String, complex: Bool?)
 }
 
 final class BaseCarbsStorage: CarbsStorage, Injectable {
@@ -101,7 +101,7 @@ final class BaseCarbsStorage: CarbsStorage, Injectable {
             } // ------------------------- END OF TPU ----------------------------------------
             // Store the actual (normal) carbs
             if entries.last?.carbs ?? 0 > 0 {
-                uniqEvents = []
+                // uniqEvents = []
                 self.storage.transaction { storage in
                     storage.append(entries, to: file, uniqBy: \.createdAt)
                     uniqEvents = storage.retrieve(file, as: [CarbsEntry].self)?
@@ -143,12 +143,12 @@ final class BaseCarbsStorage: CarbsStorage, Injectable {
         storage.retrieve(OpenAPS.Monitor.carbHistory, as: [CarbsEntry].self)?.reversed() ?? []
     }
 
-    func deleteCarbs(at id: String, complex: Bool?) {
+    func deleteCarbs(at uniqueID: String, complex: Bool?) {
         processQueue.sync {
             var allValues = storage.retrieve(OpenAPS.Monitor.carbHistory, as: [CarbsEntry].self) ?? []
 
-            guard let entryIndex = allValues.firstIndex(where: { $0.id == id }) else {
-                debug(.default, "Didn't find anything to delete. Date to search for: " + id.description)
+            guard let entryIndex = allValues.firstIndex(where: { $0.id == uniqueID }) else {
+                debug(.default, "Didn't find anything to delete. Date to search for: " + uniqueID.description)
                 return
             }
 
@@ -167,15 +167,16 @@ final class BaseCarbsStorage: CarbsStorage, Injectable {
                     $0.carbsDidUpdate(allValues)
                 }
             }
-            if let deleteComplexEntriesAlso = complex {
-                guard let fpuIndex = allValues.firstIndex(where: { $0.id == (id + ".fpu") }) else {
+            // When deleting both carbs and fat and protein (complex meal entry)
+            if let deleteComplexEntriesAlso = complex, deleteComplexEntriesAlso {
+                guard let fpuIndex = allValues.firstIndex(where: { $0.id == (uniqueID + ".fpu") }) else {
                     debug(
                         .default,
-                        "Didn't find any complex fat and protein entries to delete. Date to search for: " + id.description
+                        "Didn't find any complex fat and protein entries to delete. Date to search for: " + uniqueID.description
                     )
                     return
                 }
-                allValues.removeAll(where: { $0.id == (id + ".fpu") })
+                allValues.removeAll(where: { $0.id == (uniqueID + ".fpu") })
                 storage.save(allValues, as: OpenAPS.Monitor.carbHistory)
             }
         }
@@ -202,7 +203,8 @@ final class BaseCarbsStorage: CarbsStorage, Injectable {
                 protein: nil,
                 foodType: $0.note,
                 targetTop: nil,
-                targetBottom: nil
+                targetBottom: nil,
+                id: $0.id
             )
         }
         return Array(Set(treatments).subtracting(Set(uploaded)))

+ 2 - 0
FreeAPS/Sources/Models/NightscoutTreatment.swift

@@ -21,6 +21,7 @@ struct NigtscoutTreatment: JSON, Hashable, Equatable {
     var glucoseType: String?
     var glucose: String?
     var units: String?
+    var id: String?
 
     static let local = "iAPS"
 
@@ -57,5 +58,6 @@ extension NigtscoutTreatment {
         case glucoseType
         case glucose
         case units
+        case id
     }
 }

+ 33 - 22
FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift

@@ -35,7 +35,6 @@ extension AddCarbs {
                 return
             }
             carbs = min(carbs, maxCarbs)
-
             id_ = UUID().uuidString
 
             let carbsToStore = [CarbsEntry(
@@ -48,24 +47,15 @@ extension AddCarbs {
                 enteredBy: CarbsEntry.manual,
                 isFPU: false, fpuID: nil
             )]
-
-            carbsStorage.storeCarbs(
-                carbsToStore
-            )
-
-            /*
-             let entries = Meals(
-                 carbs: carbs, protein: protein, fat: fat, note: note, summary: waitersNotepad(), id: id_, date: date,
-                 enteredBy: CarbsEntry.manual, isFPU: false, fpuID: nil
-             )
-              */
+            carbsStorage.storeCarbs(carbsToStore)
 
             if settingsManager.settings.skipBolusScreenAfterCarbs {
                 apsManager.determineBasalSync()
                 showModal(for: nil)
-            } else {
-                showModal(for: .bolus(waitForSuggestion: true, meal: carbsToStore))
-            }
+            } else if carbs > 0 {
+                saveToCoreData(carbsToStore)
+                showModal(for: .bolus(waitForSuggestion: true, fetch: true))
+            } else { hideModal() }
         }
 
         func deletePreset() {
@@ -174,16 +164,37 @@ extension AddCarbs {
             return waitersNotepadString
         }
 
-        func loadEntries(_ editMode: Bool, _ meal: [CarbsEntry]?) {
+        func loadEntries(_ editMode: Bool) {
             if editMode {
-                if let entries = meal {
-                    carbs = entries.first?.carbs ?? 0
-                    fat = entries.first?.fat ?? 0
-                    protein = entries.first?.protein ?? 0
-                    note = entries.first?.note ?? ""
-                    id_ = entries.first?.id ?? ""
+                coredataContext.perform {
+                    var mealToEdit = [Meals]()
+                    let requestMeal = Meals.fetchRequest() as NSFetchRequest<Meals>
+                    let sortMeal = NSSortDescriptor(key: "createdAt", ascending: false)
+                    requestMeal.sortDescriptors = [sortMeal]
+                    requestMeal.fetchLimit = 1
+                    try? mealToEdit = self.coredataContext.fetch(requestMeal)
+
+                    self.carbs = Decimal(mealToEdit.first?.carbs ?? 0)
+                    self.fat = Decimal(mealToEdit.first?.fat ?? 0)
+                    self.protein = Decimal(mealToEdit.first?.protein ?? 0)
+                    self.note = mealToEdit.first?.note ?? ""
+                    self.id_ = mealToEdit.first?.id ?? ""
                 }
             }
         }
+
+        func saveToCoreData(_ stored: [CarbsEntry]) {
+            let save = Meals(context: coredataContext)
+            save.id = stored.first?.id ?? ""
+            save.createdAt = stored.first?.createdAt ?? .distantPast
+            save.id = stored.first?.id ?? ""
+            save.carbs = Double(stored.first?.carbs ?? 0)
+            save.fat = Double(stored.first?.fat ?? 0)
+            save.protein = Double(stored.first?.protein ?? 0)
+            save.note = stored.first?.note ?? ""
+            if coredataContext.hasChanges {
+                try? coredataContext.save()
+            }
+        }
     }
 }

+ 2 - 3
FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift

@@ -6,7 +6,6 @@ extension AddCarbs {
     struct RootView: BaseView {
         let resolver: Resolver
         let editMode: Bool
-        let meal: [CarbsEntry]?
         @StateObject var state = StateModel()
         @State var dish: String = ""
         @State var isPromptPresented = false
@@ -120,7 +119,7 @@ extension AddCarbs {
 
                 Section {
                     Button { state.add() }
-                    label: { Text("Save and continue") }
+                    label: { Text(state.carbs > 0 ? "Save and continue" : "Save") }
                         .disabled(state.carbs <= 0 && state.fat <= 0 && state.protein <= 0)
                         .frame(maxWidth: .infinity, alignment: .center)
                 } footer: { Text(state.waitersNotepad().description) }
@@ -133,7 +132,7 @@ extension AddCarbs {
             }
             .onAppear {
                 configureView {
-                    state.loadEntries(editMode, meal)
+                    state.loadEntries(editMode)
                 }
             }
             .navigationTitle("Add Meals")

+ 12 - 11
FreeAPS/Sources/Modules/Bolus/BolusStateModel.swift

@@ -37,7 +37,6 @@ extension Bolus {
         var waitForSuggestionInitial: Bool = false
 
         // added for bolus calculator
-        @Published var glucose: [BloodGlucose] = []
         @Published var recentGlucose: BloodGlucose?
         @Published var target: Decimal = 0
         @Published var cob: Decimal = 0
@@ -59,7 +58,13 @@ extension Bolus {
         @Published var fattyMeals: Bool = false
         @Published var fattyMealFactor: Decimal = 0
         @Published var useFattyMealCorrectionFactor: Bool = false
-        @Published var currentTime: String = ""
+        @Published var eventualBG: Int = 0
+
+        @Published var meal: [CarbsEntry]?
+        @Published var carbs: Decimal = 0
+        @Published var fat: Decimal = 0
+        @Published var protein: Decimal = 0
+        @Published var note: String = ""
 
         override func subscribe() {
             setupInsulinRequired()
@@ -91,17 +96,14 @@ extension Bolus {
         func getDeltaBG() {
             let glucose = glucoseStorage.recent()
             guard glucose.count >= 3 else { return }
-
             let lastGlucose = glucose.last!
-
             let thirdLastGlucose = glucose[glucose.count - 3]
             let delta = Decimal(lastGlucose.glucose!) - Decimal(thirdLastGlucose.glucose!)
-
             deltaBG = delta
         }
 
         // CALCULATIONS FOR THE BOLUS CALCULATOR
-        func calculateInsulin() -> Decimal {
+        func calculateInsulin() {
             // for mmol conversion
             var conversion: Decimal = 1.0
             if units == .mmolL {
@@ -152,7 +154,7 @@ extension Bolus {
             let insulinCalculatedAsDouble = Double(insulinCalculated)
             roundedInsulinCalculated = Decimal(round(100 * insulinCalculatedAsDouble) / 100)
 
-            return insulinCalculated
+            insulinRecommended = min(insulinCalculated, maxBolus)
         }
 
         func add() {
@@ -206,18 +208,17 @@ extension Bolus {
 
                 self.insulinRecommended = self.apsManager
                     .roundBolus(amount: max(self.insulinRecommended, 0))
-
                 self.getDeltaBG()
             }
         }
 
-        func backToCarbsView(_ meal: [CarbsEntry], _ complexEntry: Bool) {
+        func backToCarbsView(complexEntry: Bool, _ id: String) {
             debug(.apsManager, "Start deleting carbs")
             nsManager.deleteCarbs(
-                at: meal.first?.id ?? "", isFPU: nil, fpuID: nil, syncID: meal.first?.id ?? "",
+                at: id, isFPU: nil, fpuID: nil, syncID: id,
                 complex: complexEntry
             )
-            showModal(for: .addCarbs(editMode: true, meal: meal))
+            showModal(for: .addCarbs(editMode: true))
         }
     }
 }

+ 154 - 205
FreeAPS/Sources/Modules/Bolus/View/AlternativeBolusCalcRootView.swift

@@ -1,20 +1,23 @@
+import Charts
+import CoreData
 import SwiftUI
 import Swinject
 
 extension Bolus {
-    // alternative bolus calc
     struct AlternativeBolusCalcRootView: BaseView {
         let resolver: Resolver
         let waitForSuggestion: Bool
-        let meal: [CarbsEntry]?
-        @ObservedObject var state: StateModel
-
+        let fetch: Bool
+        @StateObject var state: StateModel
         @State private var showInfo = false
         @State private var exceededMaxBolus = false
-        @State var insulinCalculated: Decimal = 0
-
         @Environment(\.colorScheme) var colorScheme
 
+        @FetchRequest(
+            entity: Meals.entity(),
+            sortDescriptors: [NSSortDescriptor(key: "createdAt", ascending: false)]
+        ) var meal: FetchedResults<Meals>
+
         private var formatter: NumberFormatter {
             let formatter = NumberFormatter()
             formatter.numberStyle = .decimal
@@ -39,45 +42,66 @@ extension Bolus {
 
         var body: some View {
             Form {
-                Section {
+                if state.waitForSuggestion {
                     HStack {
-                        Text("Glucose")
-                        DecimalTextField(
-                            "0",
-                            value: Binding(
-                                get: {
-                                    if state.units == .mmolL {
-                                        return state.currentBG.asMmolL
-                                    } else {
-                                        return state.currentBG
-                                    }
-                                },
-                                set: { newValue in
-                                    if state.units == .mmolL {
-                                        state.currentBG = newValue.asMmolL
-                                    } else {
-                                        state.currentBG = newValue
-                                    }
-                                }
-                            ),
-                            formatter: gluoseFormatter,
-                            autofocus: false,
-                            cleanInput: true
-                        )
-                        .onChange(of: state.currentBG) { newValue in
-                            if newValue > 500 {
-                                state.currentBG = 500 // ensure that user can not input more than 500 mg/dL
+                        Text("Wait please").foregroundColor(.secondary)
+                        Spacer()
+                        ActivityIndicator(isAnimating: .constant(true), style: .medium) // fix iOS 15 bug
+                    }
+                }
+                Section {
+                    if fetch {
+                        VStack {
+                            if let carbs = meal.first?.carbs, carbs > 0 {
+                                HStack {
+                                    Text("Carbs")
+                                    Spacer()
+                                    Text(carbs.formatted())
+                                    Text("g")
+                                }.foregroundColor(.secondary)
+                            }
+                            if let fat = meal.first?.fat, fat > 0 {
+                                HStack {
+                                    Text("Fat")
+                                    Spacer()
+                                    Text(fat.formatted())
+                                    Text("g")
+                                }.foregroundColor(.secondary)
+                            }
+                            if let protein = meal.first?.protein, protein > 0 {
+                                HStack {
+                                    Text("Protein")
+                                    Spacer()
+                                    Text(protein.formatted())
+                                    Text("g")
+                                }.foregroundColor(.secondary)
+                            }
+                            if let note = meal.first?.note, note != "" {
+                                HStack {
+                                    Text("Note")
+                                    Spacer()
+                                    Text(note)
+                                }.foregroundColor(.secondary)
                             }
-                            insulinCalculated = state.calculateInsulin()
                         }
-                        Text(state.units.rawValue)
-                            .foregroundColor(.secondary)
+                    } else {
+                        Text("No Meal")
+                    }
+                } header: { Text("Meal Summary") }
+
+                Section {
+                    Button {
+                        let id_ = meal.first?.id ?? ""
+                        state.backToCarbsView(complexEntry: fetch, id_)
                     }
-                    .contentShape(Rectangle())
+                    label: { Text("Edit Meal / Add Meal") }.frame(maxWidth: .infinity, alignment: .center)
+                }
+
+                Section {
                     HStack {
                         Button(action: {
                             showInfo.toggle()
-                            insulinCalculated = state.calculateInsulin()
+                            state.calculateInsulin()
                         }, label: {
                             Image(systemName: "info.circle")
                             Text("Calculations")
@@ -94,172 +118,94 @@ extension Bolus {
                             .toggleStyle(CheckboxToggleStyle())
                             .font(.footnote)
                             .onChange(of: state.useFattyMealCorrectionFactor) { _ in
-                                insulinCalculated = state.calculateInsulin()
+                                state.calculateInsulin()
                             }
                         }
                     }
-                } header: { Text("Values") }
 
-                if changed {
-                    Section {
-                        VStack {
-                            if let mealEntry = meal {
-                                if (mealEntry.first?.carbs ?? 0) > 0 {
-                                    HStack {
-                                        Text("Carbs")
-                                        Spacer()
-                                        Text((mealEntry.first?.carbs ?? 0).formatted())
-                                        Text("g")
-                                    }.foregroundColor(.secondary)
-                                }
-                                if (mealEntry.first?.fat ?? 0) > 0 {
-                                    HStack {
-                                        Text("Fat")
-                                        Spacer()
-                                        Text((mealEntry.first?.fat ?? 0).formatted())
-                                        Text("g")
-                                    }.foregroundColor(.secondary)
-                                }
-                                if (mealEntry.first?.protein ?? 0) > 0 {
-                                    HStack {
-                                        Text("Protein")
-                                        Spacer()
-                                        Text((mealEntry.first?.protein ?? 0).formatted())
-                                        Text("g")
-                                    }.foregroundColor(.secondary)
-                                }
-                                if (mealEntry.first?.note ?? "") != "" {
-                                    HStack {
-                                        Text("Note")
-                                        Spacer()
-                                        Text(mealEntry.first?.note ?? "")
-                                    }.foregroundColor(.secondary)
-                                }
-                            }
-                        }
-                    } header: { Text("Meal Summary") }
-                }
-
-                if changed {
-                    Section {
-                        Button {
-                            if let exists = meal {
-                                state.backToCarbsView(exists, hasFatOrProtein)
-                            }
-                        }
-                        label: { Text("Edit Meal") }.frame(maxWidth: .infinity, alignment: .center)
-                    }
-                }
+                    HStack {
+                        Text("Recommended Bolus")
+                        Spacer()
+                        Text(
+                            formatter
+                                .string(from: Double(state.insulinRecommended) as NSNumber)!
+                        )
+                        Text(
+                            NSLocalizedString(" U", comment: "Unit in number of units delivered (keep the space character!)")
+                        ).foregroundColor(.secondary)
+                    }.contentShape(Rectangle())
+                        .onTapGesture { state.amount = state.insulinRecommended }
 
-                Section {
-                    if state.waitForSuggestion {
+                    if !state.waitForSuggestion {
                         HStack {
-                            Text("Wait please").foregroundColor(.secondary)
+                            Text("Bolus")
                             Spacer()
-                            ActivityIndicator(isAnimating: .constant(true), style: .medium)
-                        }
-                    } else {
-                        HStack {
-                            Text("Recommended Bolus")
-                            Spacer()
-
-                            Text(
-                                formatter
-                                    .string(from: Double(insulinCalculated) as NSNumber)!
-                            )
-                            let unit = NSLocalizedString(
-                                " U",
-                                comment: "Unit in number of units delivered (keep the space character!)"
+                            DecimalTextField(
+                                "0",
+                                value: $state.amount,
+                                formatter: formatter,
+                                autofocus: false,
+                                cleanInput: true
                             )
-                            Text(unit).foregroundColor(.secondary)
-                        }.contentShape(Rectangle())
-                            .onTapGesture {
-                                state.amount = insulinCalculated
-                            }
-
-                        if !state.waitForSuggestion {
-                            HStack {
-                                Text("Bolus")
-                                Spacer()
-                                DecimalTextField(
-                                    "0",
-                                    value: $state.amount,
-                                    formatter: formatter,
-                                    autofocus: false,
-                                    cleanInput: true
-                                )
-                                Text(exceededMaxBolus ? "😵" : " U").foregroundColor(.secondary)
-                            }
-                            .onChange(of: state.amount) { newValue in
-                                if newValue > state.maxBolus {
-                                    exceededMaxBolus = true
-                                } else {
-                                    exceededMaxBolus = false
-                                }
+                            Text(exceededMaxBolus ? "😵" : " U").foregroundColor(.secondary)
+                        }
+                        .onChange(of: state.amount) { newValue in
+                            if newValue > state.maxBolus {
+                                exceededMaxBolus = true
+                            } else {
+                                exceededMaxBolus = false
                             }
                         }
                     }
-                }
-                header: { Text("Bolus") }
+                } header: { Text("Bolus Summary") }
 
                 Section {
-                    if state.amount == 0 {
+                    if state.amount == 0, waitForSuggestion {
                         Button { state.showModal(for: nil) }
                         label: { Text("Continue without bolus") }.frame(maxWidth: .infinity, alignment: .center)
                     } else {
-                        Button(action: {
-                            state.add()
-                        }) {
-                            Text(exceededMaxBolus ? "Max Bolus exceeded!" : "Enact bolus")
-                                .frame(maxWidth: .infinity, alignment: .center)
-                        }
-                        .foregroundColor(exceededMaxBolus ? .loopRed : .accentColor)
-                        .disabled(
-                            state.amount <= 0 || state.amount > state.maxBolus
-                        )
-                    }
-                }
-                .onAppear {
-                    configureView {
-                        state.waitForSuggestionInitial = waitForSuggestion
-                        state.waitForSuggestion = waitForSuggestion
-                        insulinCalculated = state.calculateInsulin()
+                        Button { state.add() }
+                        label: { Text(exceededMaxBolus ? "Max Bolus exceeded!" : "Enact bolus") }
+                            .frame(maxWidth: .infinity, alignment: .center)
+                            .foregroundColor(exceededMaxBolus ? .loopRed : .accentColor)
+                            .disabled(
+                                state.amount <= 0 || state.amount > state.maxBolus
+                            )
                     }
                 }
-                .navigationTitle("Enact Bolus")
-                .navigationBarTitleDisplayMode(.inline)
-                .navigationBarItems(leading: Button("Close", action: state.hideModal))
             }
             .blur(radius: showInfo ? 3 : 0)
+            .navigationTitle("Enact Bolus")
+            .navigationBarTitleDisplayMode(.inline)
+            .navigationBarItems(leading: Button("Close", action: state.hideModal))
+
+            .onAppear {
+                configureView {
+                    state.waitForSuggestionInitial = waitForSuggestion
+                    state.waitForSuggestion = waitForSuggestion
+                    state.calculateInsulin()
+                }
+            }
+
             .popup(isPresented: showInfo) {
                 bolusInfoAlternativeCalculator
             }
         }
 
         var changed: Bool {
-            if let exists = meal {
-                return ((exists.first?.carbs ?? 0) > 0 || (exists.first?.fat ?? 0) > 0 || (exists.first?.protein ?? 0) > 0)
-            }
-            return false
+            ((meal.first?.carbs ?? 0) > 0) || ((meal.first?.fat ?? 0) > 0) || ((meal.first?.protein ?? 0) > 0)
         }
 
         var hasFatOrProtein: Bool {
-            if let exists = meal {
-                return ((exists.first?.fat ?? 0) > 0 || (exists.first?.protein ?? 0) > 0)
-            }
-            return false
+            ((meal.first?.fat ?? 0) > 0) || ((meal.first?.protein ?? 0) > 0)
         }
 
         // calculation showed in popup
         var bolusInfoAlternativeCalculator: some View {
-            let unit = NSLocalizedString(
-                " U",
-                comment: "Unit in number of units delivered (keep the space character!)"
-            )
-
-            return VStack {
+            VStack {
+                let unit = NSLocalizedString(" U", comment: "Unit in number of units delivered (keep the space character!)")
                 VStack {
-                    VStack(spacing: 5) {
+                    VStack(spacing: 2) {
                         HStack {
                             Text("Calculations")
                                 .font(.title3)
@@ -268,43 +214,45 @@ extension Bolus {
                         }
                         .padding(.vertical, 10)
 
-                        if changed {
-                            VStack(spacing: 3) {
-                                if let mealEntry = meal {
-                                    if (mealEntry.first?.note ?? "") != "" {
-                                        HStack {
-                                            Text("Note")
-                                                .foregroundColor(.secondary)
-                                            Spacer()
-                                            Text(mealEntry.first?.note ?? "").foregroundColor(.secondary)
-                                        }
+                        if fetch {
+                            VStack {
+                                if let note = meal.first?.note, note != "" {
+                                    HStack {
+                                        Text("Note")
+                                            .foregroundColor(.secondary)
+                                        Spacer()
+                                        Text(note)
                                     }
-                                    if (mealEntry.first?.carbs ?? 0) > 0 {
-                                        HStack {
-                                            Text("Carbs")
-                                                .foregroundColor(.secondary)
-                                            Spacer()
-                                            Text((mealEntry.first?.carbs ?? 0).formatted())
-                                        }
+                                }
+                                if let carbs = meal.first?.carbs, carbs > 0 {
+                                    HStack {
+                                        Text("Carbs")
+                                            .foregroundColor(.secondary)
+                                        Spacer()
+                                        Text(carbs.formatted())
+                                        Text("g").foregroundColor(.secondary)
                                     }
-                                    if (mealEntry.first?.protein ?? 0) > 0 {
-                                        HStack {
-                                            Text("Protein")
-                                                .foregroundColor(.secondary)
-                                            Spacer()
-                                            Text((mealEntry.first?.protein ?? 0).formatted())
-                                        }
+                                }
+                                if let protein = meal.first?.protein, protein > 0 {
+                                    HStack {
+                                        Text("Protein")
+                                            .foregroundColor(.secondary)
+                                        Spacer()
+                                        Text(protein.formatted())
+                                        Text("g").foregroundColor(.secondary)
                                     }
-                                    if (mealEntry.first?.fat ?? 0) > 0 {
-                                        HStack {
-                                            Text("Fat")
-                                                .foregroundColor(.secondary)
-                                            Spacer()
-                                            Text((mealEntry.first?.fat ?? 0).formatted())
-                                        }
+                                }
+                                if let fat = meal.first?.fat, fat > 0 {
+                                    HStack {
+                                        Text("Fat")
+                                            .foregroundColor(.secondary)
+                                        Spacer()
+                                        Text(fat.formatted()).foregroundColor(.orange)
+                                        Text("g").foregroundColor(.secondary)
                                     }
                                 }
-                            }.padding(.bottom, 20)
+                            }
+                            Divider().fontWeight(.bold).padding(10)
                         }
 
                         HStack {
@@ -360,10 +308,11 @@ extension Bolus {
                                     .foregroundColor(.orange)
                             }
                         }
+                        Divider().fontWeight(.bold).foregroundColor(.white)
                     }
                     .padding()
 
-                    VStack {
+                    VStack(spacing: 2) {
                         HStack {
                             Text("Glucose")
                                 .foregroundColor(.secondary)
@@ -454,7 +403,7 @@ extension Bolus {
                     .padding()
 
                     Divider()
-                        .fontWeight(.bold)
+                        .fontWeight(.bold).foregroundColor(.white)
 
                     HStack {
                         Text("Full Bolus")
@@ -522,7 +471,7 @@ extension Bolus {
                 .padding(.top, 10)
                 .padding(.bottom, 15)
 
-                // Hide button
+                // Hide pop-up
                 VStack {
                     Button {
                         showInfo = false

+ 3 - 3
FreeAPS/Sources/Modules/Bolus/View/BolusRootView.swift

@@ -5,16 +5,16 @@ extension Bolus {
     struct RootView: BaseView {
         let resolver: Resolver
         let waitForSuggestion: Bool
-        let meal: [CarbsEntry]?
+        let fetch: Bool
         @StateObject var state = StateModel()
 
         var body: some View {
             if state.useCalc {
                 // show alternative bolus calc based on toggle in bolus calc settings
-                AlternativeBolusCalcRootView(resolver: resolver, waitForSuggestion: waitForSuggestion, meal: meal, state: state)
+                AlternativeBolusCalcRootView(resolver: resolver, waitForSuggestion: waitForSuggestion, fetch: fetch, state: state)
             } else {
                 // show iAPS standard bolus calc
-                DefaultBolusCalcRootView(resolver: resolver, waitForSuggestion: waitForSuggestion, meal: meal, state: state)
+                DefaultBolusCalcRootView(resolver: resolver, waitForSuggestion: waitForSuggestion, fetch: fetch, state: state)
             }
         }
     }

+ 1 - 2
FreeAPS/Sources/Modules/Bolus/View/DefaultBolusCalcRootView.swift

@@ -5,7 +5,7 @@ extension Bolus {
     struct DefaultBolusCalcRootView: BaseView {
         let resolver: Resolver
         let waitForSuggestion: Bool
-        let meal: [CarbsEntry]?
+        let fetch: Bool
         @StateObject var state = StateModel()
 
         @State private var isAddInsulinAlertPresented = false
@@ -212,7 +212,6 @@ extension Bolus {
             .background(
                 RoundedRectangle(cornerRadius: 8, style: .continuous)
                     .fill(Color(colorScheme == .dark ? UIColor.systemGray4 : UIColor.systemGray4))
-                // .fill(Color(.systemGray).gradient)  // A more prominent pop-up, but harder to read
             )
         }
 

+ 1 - 1
FreeAPS/Sources/Modules/Home/HomeStateModel.swift

@@ -196,7 +196,7 @@ extension Home {
         }
 
         func addCarbs() {
-            showModal(for: .addCarbs(editMode: false, meal: nil))
+            showModal(for: .addCarbs(editMode: false))
         }
 
         func runLoop() {

+ 2 - 2
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -481,7 +481,7 @@ extension Home {
                 Rectangle().fill(Color.gray.opacity(0.3)).frame(height: 50 + geo.safeAreaInsets.bottom)
 
                 HStack {
-                    Button { state.showModal(for: .addCarbs(editMode: false, meal: nil)) }
+                    Button { state.showModal(for: .addCarbs(editMode: false)) }
                     label: {
                         ZStack(alignment: Alignment(horizontal: .trailing, vertical: .bottom)) {
                             Image("carbs")
@@ -514,7 +514,7 @@ extension Home {
                     Button {
                         state.showModal(for: .bolus(
                             waitForSuggestion: true,
-                            meal: nil
+                            fetch: false
                         ))
                     }
                     label: {

+ 6 - 6
FreeAPS/Sources/Router/Screen.swift

@@ -14,9 +14,9 @@ enum Screen: Identifiable, Hashable {
     case crEditor
     case targetsEditor
     case preferencesEditor
-    case addCarbs(editMode: Bool, meal: [CarbsEntry]?)
+    case addCarbs(editMode: Bool)
     case addTempTarget
-    case bolus(waitForSuggestion: Bool, meal: [CarbsEntry]?)
+    case bolus(waitForSuggestion: Bool, fetch: Bool)
     case manualTempBasal
     case autotuneConfig
     case dataTable
@@ -64,12 +64,12 @@ extension Screen {
             TargetsEditor.RootView(resolver: resolver)
         case .preferencesEditor:
             PreferencesEditor.RootView(resolver: resolver)
-        case let .addCarbs(editMode, meal):
-            AddCarbs.RootView(resolver: resolver, editMode: editMode, meal: meal)
+        case let .addCarbs(editMode):
+            AddCarbs.RootView(resolver: resolver, editMode: editMode)
         case .addTempTarget:
             AddTempTarget.RootView(resolver: resolver)
-        case let .bolus(waitForSuggestion, meal):
-            Bolus.RootView(resolver: resolver, waitForSuggestion: waitForSuggestion, meal: meal)
+        case let .bolus(waitForSuggestion, fetch):
+            Bolus.RootView(resolver: resolver, waitForSuggestion: waitForSuggestion, fetch: fetch)
         case .manualTempBasal:
             ManualTempBasal.RootView(resolver: resolver)
         case .autotuneConfig:

+ 2 - 2
FreeAPS/Sources/Services/Network/NightscoutAPI.swift

@@ -141,7 +141,7 @@ extension NightscoutAPI {
             .eraseToAnyPublisher()
     }
 
-    func deleteCarbs(at date: String) -> AnyPublisher<Void, Swift.Error> {
+    func deleteCarbs(at uniqueID: String) -> AnyPublisher<Void, Swift.Error> {
         var components = URLComponents()
         components.scheme = url.scheme
         components.host = url.host
@@ -151,7 +151,7 @@ extension NightscoutAPI {
             URLQueryItem(name: "find[carbs][$exists]", value: "true"),
             URLQueryItem(
                 name: "find[id][$eq]",
-                value: date
+                value: uniqueID
             )
         ]
 

+ 8 - 8
FreeAPS/Sources/Services/Network/NightscoutManager.swift

@@ -9,7 +9,7 @@ protocol NightscoutManager: GlucoseSource {
     func fetchCarbs() -> AnyPublisher<[CarbsEntry], Never>
     func fetchTempTargets() -> AnyPublisher<[TempTarget], Never>
     func fetchAnnouncements() -> AnyPublisher<[Announcement], Never>
-    func deleteCarbs(at date: String, isFPU: Bool?, fpuID: String?, syncID: String, complex: Bool?)
+    func deleteCarbs(at uniqueID: String, isFPU: Bool?, fpuID: String?, syncID: String, complex: Bool?)
     func deleteInsulin(at date: Date)
     func deleteManualGlucose(at: Date)
     func uploadStatus()
@@ -177,31 +177,31 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
             .eraseToAnyPublisher()
     }
 
-    func deleteCarbs(at date: String, isFPU: Bool?, fpuID: String?, syncID: String, complex: Bool?) {
+    func deleteCarbs(at uniqueID: String, isFPU: Bool?, fpuID: String?, syncID: String, complex: Bool?) {
         // remove in AH
         healthkitManager.deleteCarbs(syncID: syncID, isFPU: isFPU, fpuID: fpuID)
 
         guard let nightscout = nightscoutAPI, isUploadEnabled else {
-            carbsStorage.deleteCarbs(at: date, complex: complex)
+            carbsStorage.deleteCarbs(at: uniqueID, complex: complex)
             return
         }
 
         if let isFPU = isFPU, isFPU {
             guard let fpuID = fpuID else { return }
             let allValues = storage.retrieve(OpenAPS.Monitor.carbHistory, as: [CarbsEntry].self) ?? []
-            let dates = allValues.filter { $0.fpuID == fpuID }.map(\.createdAt).removeDublicates()
+            let dates = allValues.filter { $0.fpuID == fpuID }.map(\.id).removeDublicates()
 
             let publishers = dates
                 .map { _ -> AnyPublisher<Void, Swift.Error> in
                     nightscout.deleteCarbs(
-                        at: date
+                        at: uniqueID
                     )
                 }
 
             Publishers.MergeMany(publishers)
                 .collect()
                 .sink { completion in
-                    self.carbsStorage.deleteCarbs(at: date, complex: complex)
+                    self.carbsStorage.deleteCarbs(at: uniqueID, complex: complex)
                     switch completion {
                     case .finished:
                         debug(.nightscout, "Carbs deleted")
@@ -217,9 +217,9 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
                 .store(in: &lifetime)
 
         } else {
-            nightscout.deleteCarbs(at: date)
+            nightscout.deleteCarbs(at: uniqueID)
                 .sink { completion in
-                    self.carbsStorage.deleteCarbs(at: date, complex: complex)
+                    self.carbsStorage.deleteCarbs(at: uniqueID, complex: complex)
                     switch completion {
                     case .finished:
                         debug(.nightscout, "Carbs deleted")