Преглед изворни кода

Add Manual Glucose. Test Co

(cherry picked from commit 113018be2c1d3274f2a1ed4b910a98296d17b006)
Jon Mårtensson пре 2 година
родитељ
комит
561cf1c8bf

+ 2 - 1
Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21754" systemVersion="22E261" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
+<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22158.8" systemVersion="22F66" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
     <entity name="BGaverages" representedClassName="BGaverages" syncable="YES" codeGenerationType="class">
         <attribute name="average" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
         <attribute name="average_1" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
@@ -92,6 +92,7 @@
     <entity name="Readings" representedClassName="Readings" syncable="YES" codeGenerationType="class">
         <attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="glucose" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
+        <attribute name="id" optional="YES" attributeType="String"/>
     </entity>
     <entity name="StatsData" representedClassName="StatsData" syncable="YES" codeGenerationType="class">
         <attribute name="lastrun" attributeType="Date" defaultDateTimeInterval="704497620" usesScalarValueType="NO"/>

+ 4 - 1
FreeAPS/Sources/APS/Storage/GlucoseStorage.swift

@@ -56,14 +56,16 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
                     }
                 }
 
-                // MARK: Save to CoreData. TEST
+                // MARK: Save to CoreData.
 
                 var bg_ = 0
                 var bgDate = Date()
+                var id = ""
 
                 if glucose.isNotEmpty {
                     bg_ = glucose[0].glucose ?? 0
                     bgDate = glucose[0].dateString
+                    id = glucose[0].id
                 }
 
                 if bg_ != 0 {
@@ -72,6 +74,7 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
 
                         dataForForStats.date = bgDate
                         dataForForStats.glucose = Int16(bg_)
+                        dataForForStats.id = id
 
                         try? self.coredataContext.save()
                     }

+ 56 - 0
FreeAPS/Sources/Modules/DataTable/DataTableStateModel.swift

@@ -1,13 +1,19 @@
+import CoreData
 import SwiftUI
 
 extension DataTable {
     final class StateModel: BaseStateModel<Provider> {
         @Injected() var broadcaster: Broadcaster!
         @Injected() var unlockmanager: UnlockManager!
+        @Injected() private var storage: FileStorage!
+
+        let coredataContext = CoreDataStack.shared.persistentContainer.viewContext
 
         @Published var mode: Mode = .treatments
         @Published var treatments: [Treatment] = []
         @Published var glucose: [Glucose] = []
+        @Published var manualGlcuose: Decimal = 0
+
         var units: GlucoseUnits = .mmolL
 
         override func subscribe() {
@@ -132,6 +138,56 @@ extension DataTable {
         func deleteGlucose(at index: Int) {
             let id = glucose[index].id
             provider.deleteGlucose(id: id)
+
+            let fetchRequest: NSFetchRequest<NSFetchRequestResult>
+            fetchRequest = NSFetchRequest(entityName: "Readings")
+            fetchRequest.predicate = NSPredicate(format: "id == %@", id)
+
+            let deleteRequest = NSBatchDeleteRequest(
+                fetchRequest: fetchRequest
+            )
+            deleteRequest.resultType = .resultTypeObjectIDs
+            do {
+                let deleteResult = try coredataContext.execute(deleteRequest) as? NSBatchDeleteResult
+                if let objectIDs = deleteResult?.result as? [NSManagedObjectID] {
+                    NSManagedObjectContext.mergeChanges(
+                        fromRemoteContextSave: [NSDeletedObjectsKey: objectIDs],
+                        into: [coredataContext]
+                    )
+                }
+            } catch {
+                // To do: handle any thrown errors.
+            }
+            try? coredataContext.save()
+        }
+
+        func addManualGlucose() {
+            let glucose = units == .mmolL ? manualGlcuose.asMgdL : manualGlcuose
+            let now = Date()
+            let id = UUID().uuidString
+
+            let saveToJSON = BloodGlucose(
+                _id: id,
+                direction: nil,
+                date: Decimal(now.timeIntervalSince1970) * 1000,
+                dateString: now,
+                unfiltered: nil,
+                filtered: nil,
+                noise: nil,
+                glucose: Int(glucose),
+                type: "Manual"
+            )
+            provider.glucoseStorage.storeGlucose([saveToJSON])
+            debug(.default, "Manual Glucose saved to glucose.json")
+
+            coredataContext.perform {
+                let saveToCoreData = Readings(context: self.coredataContext)
+                saveToCoreData.date = now
+                saveToCoreData.glucose = Int16(Int(glucose))
+                saveToCoreData.id = id
+                try? self.coredataContext.save()
+                debug(.default, "Manual Glucose saved to CoreData")
+            }
         }
     }
 }

+ 35 - 1
FreeAPS/Sources/Modules/DataTable/View/DataTableRootView.swift

@@ -1,3 +1,4 @@
+import CoreData
 import SwiftUI
 import Swinject
 
@@ -8,9 +9,11 @@ extension DataTable {
 
         @State private var isRemoveCarbsAlertPresented = false
         @State private var removeCarbsAlert: Alert?
-
         @State private var isRemoveInsulinAlertPresented = false
         @State private var removeInsulinAlert: Alert?
+        @State private var newGlucose = false
+
+        @Environment(\.colorScheme) var colorScheme
 
         private var glucoseFormatter: NumberFormatter {
             let formatter = NumberFormatter()
@@ -54,6 +57,33 @@ extension DataTable {
                 leading: Button("Close", action: state.hideModal),
                 trailing: state.mode == .glucose ? EditButton().asAny() : EmptyView().asAny()
             )
+            .popup(isPresented: newGlucose, alignment: .top, direction: .bottom) {
+                VStack(spacing: 20) {
+                    HStack {
+                        Text("New Glucose")
+                        DecimalTextField(" ... ", value: $state.manualGlcuose, formatter: glucoseFormatter)
+                        Text(state.units.rawValue)
+                    }.padding(.horizontal, 20)
+                    HStack {
+                        Button { newGlucose = false }
+                        label: { Text("Cancel") }.frame(maxWidth: .infinity, alignment: .leading)
+
+                        Button {
+                            state.addManualGlucose()
+                            newGlucose = false
+                        }
+                        label: { Text("Save") }
+                            .frame(maxWidth: .infinity, alignment: .trailing)
+                            .disabled(state.manualGlcuose < 2.2 || state.manualGlcuose > 22)
+
+                    }.padding(20)
+                }
+                .frame(maxHeight: 140)
+                .background(
+                    RoundedRectangle(cornerRadius: 8, style: .continuous)
+                        .fill(Color(colorScheme == .dark ? UIColor.systemGray2 : UIColor.systemGray6))
+                )
+            }
         }
 
         private var treatmentsList: some View {
@@ -66,6 +96,10 @@ extension DataTable {
 
         private var glucoseList: some View {
             List {
+                Button { newGlucose = true }
+                label: { Text("Add") }.frame(maxWidth: .infinity, alignment: .trailing)
+                    .padding(.trailing, 20)
+
                 ForEach(state.glucose) { item in
                     glucoseView(item)
                 }.onDelete(perform: deleteGlucose)