Bladeren bron

merge 'core-data-sync-trio', fix merge conflicts

polscm32 1 jaar geleden
bovenliggende
commit
46dc53e637

+ 25 - 6
FreeAPS/Sources/APS/CGM/PluginSource.swift

@@ -135,13 +135,24 @@ extension PluginSource: CGMManagerDelegate {
         return glucoseStorage.lastGlucoseDate()
     }
 
-    func cgmManagerDidUpdateState(_: CGMManager) {
+    func cgmManagerDidUpdateState(_ cgmManager: CGMManager) {
         dispatchPrecondition(condition: .onQueue(processQueue))
-//        guard let g6Manager = manager as? TransmitterManager else {
-//            return
-//        }
-//        glucoseManager?.settingsManager.settings.uploadGlucose = g6Manager.shouldSyncToRemoteService
-//        UserDefaults.standard.dexcomTransmitterID = g6Manager.rawState["transmitterID"] as? String
+
+        guard let fetchGlucoseManager = glucoseManager else {
+            debug(
+                .deviceManager,
+                "Could not gracefully unwrap FetchGlucoseManager upon observing LoopKit's cgmManagerDidUpdateState"
+            )
+            return
+        }
+        // Adjust app-specific NS Upload setting value when CGM setting is changed
+        fetchGlucoseManager.settingsManager.settings.uploadGlucose = cgmManager.shouldSyncToRemoteService
+
+        fetchGlucoseManager.updateGlucoseSource(
+            cgmGlucoseSourceType: fetchGlucoseManager.settingsManager.settings.cgm,
+            cgmGlucosePluginId: fetchGlucoseManager.settingsManager.settings.cgmPluginIdentifier,
+            newManager: cgmManager as? CGMManagerUI
+        )
     }
 
     func credentialStoragePrefix(for _: CGMManager) -> String {
@@ -160,6 +171,14 @@ extension PluginSource: CGMManagerDelegate {
 
     private func readCGMResult(readingResult: CGMReadingResult) -> Result<[BloodGlucose], Error> {
         debug(.deviceManager, "PLUGIN CGM - Process CGM Reading Result launched with \(readingResult)")
+
+        if glucoseManager?.glucoseSource == nil {
+            debug(
+                .deviceManager,
+                "No glucose source available."
+            )
+        }
+
         switch readingResult {
         case let .newData(values):
 

+ 0 - 1
FreeAPS/Sources/APS/DeviceDataManager.swift

@@ -475,7 +475,6 @@ extension BaseDeviceDataManager: PumpManagerDelegate {
         completion: @escaping (_ error: Error?) -> Void
     ) {
         dispatchPrecondition(condition: .onQueue(processQueue))
-        debug(.deviceManager, "New pump events:\n\(events.map(\.title).joined(separator: "\n"))")
 
         // filter buggy TBRs > maxBasal from MDT
         let events = events.filter {

+ 18 - 16
FreeAPS/Sources/APS/FetchGlucoseManager.swift

@@ -105,6 +105,7 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
         if self.cgmGlucoseSourceType != cgmGlucoseSourceType || self.cgmGlucosePluginId != cgmGlucosePluginId {
             removeCalibrations()
             cgmManager = nil
+            glucoseSource = nil
         }
 
         self.cgmGlucoseSourceType = cgmGlucoseSourceType
@@ -125,23 +126,24 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
             saveConfigManager()
         }
 
-        switch self.cgmGlucoseSourceType {
-        case .none:
-            glucoseSource = nil
-        case .xdrip:
-            glucoseSource = AppGroupSource(from: "xDrip", cgmType: .xdrip)
-        case .nightscout:
-            glucoseSource = nightscoutManager
-        case .simulator:
-            glucoseSource = simulatorSource
-        case .glucoseDirect:
-            glucoseSource = AppGroupSource(from: "GlucoseDirect", cgmType: .glucoseDirect)
-        case .enlite:
-            glucoseSource = deviceDataManager
-        case .plugin:
-            glucoseSource = PluginSource(glucoseStorage: glucoseStorage, glucoseManager: self)
+        if glucoseSource == nil {
+            switch self.cgmGlucoseSourceType {
+            case .none:
+                glucoseSource = nil
+            case .xdrip:
+                glucoseSource = AppGroupSource(from: "xDrip", cgmType: .xdrip)
+            case .nightscout:
+                glucoseSource = nightscoutManager
+            case .simulator:
+                glucoseSource = simulatorSource
+            case .glucoseDirect:
+                glucoseSource = AppGroupSource(from: "GlucoseDirect", cgmType: .glucoseDirect)
+            case .enlite:
+                glucoseSource = deviceDataManager
+            case .plugin:
+                glucoseSource = PluginSource(glucoseStorage: glucoseStorage, glucoseManager: self)
+            }
         }
-        // update the config
     }
 
     /// Upload cgmManager from raw value

+ 11 - 10
FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift

@@ -133,7 +133,7 @@ final class OpenAPS {
         let results = await CoreDataStack.shared.fetchEntitiesAsync(
             ofType: GlucoseStored.self,
             onContext: context,
-            predicate: NSPredicate.predicateForSixHoursAgo,
+            predicate: NSPredicate.predicateForOneDayAgoInMinutes,
             key: "date",
             ascending: false,
             fetchLimit: 72,
@@ -173,7 +173,7 @@ final class OpenAPS {
         let results = await CoreDataStack.shared.fetchEntitiesAsync(
             ofType: PumpEventStored.self,
             onContext: context,
-            predicate: NSPredicate.pumpHistoryLast24h,
+            predicate: NSPredicate.pumpHistoryLast1440Minutes,
             key: "timestamp",
             ascending: false,
             batchSize: 50
@@ -204,12 +204,15 @@ final class OpenAPS {
                 if let bolusDTO = event.toBolusDTOEnum() {
                     eventDTOs.append(bolusDTO)
                 }
-                if let tempBasalDTO = event.toTempBasalDTOEnum() {
-                    eventDTOs.append(tempBasalDTO)
-                }
+
                 if let tempBasalDurationDTO = event.toTempBasalDurationDTOEnum() {
                     eventDTOs.append(tempBasalDurationDTO)
                 }
+
+                if let tempBasalDTO = event.toTempBasalDTOEnum() {
+                    eventDTOs.append(tempBasalDTO)
+                }
+
                 return eventDTOs
             }
 
@@ -222,8 +225,7 @@ final class OpenAPS {
         debug(.openAPS, "Start determineBasal")
 
         // clock
-        let dateFormatted = OpenAPS.dateFormatter.string(from: clock)
-        let dateFormattedAsString = "\"\(dateFormatted)\""
+        self.storage.save(clock, as: Monitor.clock)
 
         // temp_basal
         let tempBasal = currentTemp.rawJSON
@@ -263,13 +265,12 @@ final class OpenAPS {
         )
 
         // TODO: - Save and fetch profile/basalProfile in/from UserDefaults!
-
         // Meal
         let meal = try await self.meal(
             pumphistory: pumpHistoryJSON,
             profile: profile,
             basalProfile: basalProfile,
-            clock: dateFormattedAsString,
+            clock: clock,
             carbs: carbsAsJSON,
             glucose: glucoseAsJSON
         )
@@ -278,7 +279,7 @@ final class OpenAPS {
         let iob = try await self.iob(
             pumphistory: pumpHistoryJSON,
             profile: profile,
-            clock: dateFormattedAsString,
+            clock: clock,
             autosens: autosens.isEmpty ? .null : autosens
         )
 

+ 2 - 14
FreeAPS/Sources/APS/Storage/DeterminationStorage.swift

@@ -103,13 +103,9 @@ final class BaseDeterminationStorage: DeterminationStorage, Injectable {
         var result: Determination?
 
         guard let determinationId = determinationIds.first else {
-            print("No determination ID found.")
             return nil
         }
 
-        print("Using context: \(backgroundContext)")
-        print("Determination ID: \(determinationId)")
-
         let predictions = Predictions(
             iob: await parseForecastValues(ofType: "iob", from: determinationId),
             zt: await parseForecastValues(ofType: "zt", from: determinationId),
@@ -121,15 +117,9 @@ final class BaseDeterminationStorage: DeterminationStorage, Injectable {
             do {
                 let orefDetermination = try self.backgroundContext.existingObject(with: determinationId) as? OrefDetermination
 
-                // Log the type of the fetched object
-                print("Fetched object type: \(type(of: orefDetermination))")
-                print("Fetched object description: \(orefDetermination)")
-
                 // Check if the fetched object is of the expected type
                 if let orefDetermination = orefDetermination {
-                    print("Successfully cast to OrefDetermination")
                     let forecastSet = orefDetermination.forecasts
-                    print("Fetched forecast set: \(forecastSet)")
 
                     result = Determination(
                         id: orefDetermination.id ?? UUID(),
@@ -163,12 +153,10 @@ final class BaseDeterminationStorage: DeterminationStorage, Injectable {
                         carbRatio: self.decimal(from: orefDetermination.carbRatio),
                         received: orefDetermination.enacted // this is actually part of NS...
                     )
-                } else {
-                    print("Fetched object is not of type OrefDetermination")
                 }
             } catch {
-                print("Failed to fetch managed object: \(error)")
-            }
+                debugPrint("\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to fetch managed object with error: \(error.localizedDescription)")
+             }
 
             return result
         }

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

@@ -46,8 +46,6 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
 
     func storeGlucose(_ glucose: [BloodGlucose]) {
         processQueue.sync {
-            debug(.deviceManager, "Start storage of glucose data")
-
             self.coredataContext.perform {
                 let datesToCheck: Set<Date?> = Set(glucose.compactMap { $0.dateString as Date? })
                 let fetchRequest: NSFetchRequest<NSFetchRequestResult> = GlucoseStored.fetchRequest()
@@ -81,8 +79,6 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
                         glucoseEntry.date = entry.dateString
                         glucoseEntry.direction = entry.direction?.rawValue
                         glucoseEntry.isUploadedToNS = false /// the value is not uploaded to NS (yet)
-                        debugPrint("\(DebuggingIdentifiers.failed)")
-                        debugPrint("\(String(describing: glucoseEntry.direction))")
                         return false // Continue processing
                     }
                 )
@@ -90,7 +86,7 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
                 // process batch insert
                 do {
                     try self.coredataContext.execute(batchInsert)
-                    debugPrint("Glucose Storage: \(#function) \(DebuggingIdentifiers.succeeded) saved glucose to Core Data")
+//                    debugPrint("Glucose Storage: \(#function) \(DebuggingIdentifiers.succeeded) saved glucose to Core Data")
 
                     // Send notification for triggering a fetch in Home State Model to update the Glucose Array
                     /// This is necessary because changes only get merged automatically into the viewContext because of the Persistent History Tracking

+ 7 - 0
FreeAPS/Sources/Modules/Bolus/BolusStateModel.swift

@@ -25,6 +25,7 @@ extension Bolus {
         @Published var percentage: Decimal = 0
         @Published var threshold: Decimal = 0
         @Published var maxBolus: Decimal = 0
+        var maxExternal: Decimal { maxBolus * 3 }
         @Published var errorString: Decimal = 0
         @Published var evBG: Decimal = 0
         @Published var insulin: Decimal = 0
@@ -84,6 +85,8 @@ extension Bolus {
         @Published var selection: MealPresetStored?
         @Published var summation: [String] = []
         @Published var maxCarbs: Decimal = 0
+        @Published var maxFat: Decimal = 0
+        @Published var maxProtein: Decimal = 0
 
         @Published var id_: String = ""
         @Published var summary: String = ""
@@ -126,6 +129,8 @@ extension Bolus {
             displayPresets = settings.settings.displayPresets
 
             maxCarbs = settings.settings.maxCarbs
+            maxFat = settings.settings.maxFat
+            maxProtein = settings.settings.maxProtein
             skipBolus = settingsManager.settings.skipBolusScreenAfterCarbs
             useFPUconversion = settingsManager.settings.useFPUconversion
 
@@ -385,6 +390,8 @@ extension Bolus {
 
             await MainActor.run {
                    self.carbs = min(self.carbs, self.maxCarbs)
+                    self.fat = min(self.fat, self.maxFat)
+                    self.protein = min(self.protein, self.maxProtein)
                    self.id_ = UUID().uuidString
                }
 

+ 43 - 38
FreeAPS/Sources/Modules/Bolus/View/BolusRootView.swift

@@ -507,10 +507,7 @@ extension Bolus {
                         .frame(minHeight: 50)
                 }
                 .disabled(disableTaskButton)
-                .background(
-                    (state.externalInsulin ? externalBolusLimit : pumpBolusLimit) ? Color(.systemRed) :
-                        Color(.systemBlue)
-                )
+                .background(limitExceeded ? Color(.systemRed) : Color(.systemBlue))
                 .shadow(radius: 3)
                 .clipShape(RoundedRectangle(cornerRadius: 8))
                 .padding()
@@ -519,61 +516,69 @@ extension Bolus {
         }
 
         private var taskButtonLabel: some View {
+            if pumpBolusLimitExceeded {
+                return Text("Max Bolus of \(state.maxBolus) U Exceeded")
+            } else if externalBolusLimitExceeded {
+                return Text("Max External Bolus of \(state.maxExternal) U Exceeded")
+            } else if carbLimitExceeded {
+                return Text("Max Carbs of \(state.maxCarbs) g Exceeded")
+            } else if fatLimitExceeded {
+                return Text("Max Fat of \(state.maxFat) g Exceeded")
+            } else if proteinLimitExceeded {
+                return Text("Max Protein of \(state.maxProtein) g Exceeded")
+            }
+
             let hasInsulin = state.amount > 0
             let hasCarbs = state.carbs > 0
             let hasFatOrProtein = state.fat > 0 || state.protein > 0
+            let bolusString = state.externalInsulin ? "External Insulin" : "Enact Bolus"
 
             switch (hasInsulin, hasCarbs, hasFatOrProtein) {
             case (true, true, true):
-                return Text(
-                    state
-                        .externalInsulin ? (
-                            externalBolusLimit ? "Manual bolus exceeds max bolus!" : "Log meal and external insulin"
-                        ) :
-                        (pumpBolusLimit ? "Pump bolus exceeds max bolus!" : "Log meal and enact bolus")
-                )
+                return Text("Log Meal and \(bolusString)")
             case (true, true, false):
-                return Text(
-                    state
-                        .externalInsulin ?
-                        (externalBolusLimit ? "Manual bolus exceeds max bolus!" : "Log carbs and external insulin") :
-                        (pumpBolusLimit ? "Pump bolus exceeds max bolus!" : "Log carbs and enact bolus")
-                )
+                return Text("Log Carbs and \(bolusString)")
             case (true, false, true):
-                return Text(
-                    state
-                        .externalInsulin ?
-                        (externalBolusLimit ? "Manual bolus exceeds max bolus!" : "Log FPUs and external insulin") :
-                        (pumpBolusLimit ? "Pump bolus exceeds max bolus!" : "Log FPUs and enact bolus")
-                )
+                return Text("Log FPU and \(bolusString)")
             case (true, false, false):
-                return Text(
-                    state
-                        .externalInsulin ? (externalBolusLimit ? "Manual bolus exceeds max bolus!" : "Log external insulin") :
-                        (pumpBolusLimit ? "Pump bolus exceeds max bolus!" : "Enact bolus")
-                )
+                return Text(state.externalInsulin ? "Log External Insulin" : "Enact Bolus")
             case (false, true, true):
-                return Text("Log meal")
+                return Text("Log Meal")
             case (false, true, false):
-                return Text("Log carbs")
+                return Text("Log Carbs")
             case (false, false, true):
-                return Text("Log FPUs")
+                return Text("Log FPU")
             default:
-                return Text("Continue without treatment")
+                return Text("Continue Without Treatment")
             }
         }
 
-        private var pumpBolusLimit: Bool {
-            state.amount > state.maxBolus
+        private var pumpBolusLimitExceeded: Bool {
+            !state.externalInsulin && state.amount > state.maxBolus
+        }
+
+        private var externalBolusLimitExceeded: Bool {
+            state.externalInsulin && state.amount > state.maxExternal
+        }
+
+        private var carbLimitExceeded: Bool {
+            state.carbs > state.maxCarbs
+        }
+
+        private var fatLimitExceeded: Bool {
+            state.fat > state.maxFat
+        }
+
+        private var proteinLimitExceeded: Bool {
+            state.protein > state.maxProtein
         }
 
-        private var externalBolusLimit: Bool {
-            state.amount > state.maxBolus * 3
+        private var limitExceeded: Bool {
+            pumpBolusLimitExceeded || externalBolusLimitExceeded || carbLimitExceeded || fatLimitExceeded || proteinLimitExceeded
         }
 
         private var disableTaskButton: Bool {
-            state.addButtonPressed ||
-                (state.amount > 0 ? (state.externalInsulin ? externalBolusLimit : pumpBolusLimit) : false)
+            state.addButtonPressed || limitExceeded
         }
     }
 

+ 8 - 0
FreeAPS/Sources/Modules/HealthKit/View/AppleHealthKitRootView.swift

@@ -27,6 +27,14 @@ extension AppleHealthKit {
         var body: some View {
             Form {
                 Section {
+                    HStack {
+                        Image(systemName: "exclamationmark.triangle")
+                        Text(
+                            "Connecting to Apple Health will use an excessive amount of storage and may cause Apple Health to lag. This will be improved in a future release."
+                        )
+                        .font(.caption)
+                    }
+                    .foregroundColor(Color.secondary)
                     Toggle("Connect to Apple Health", isOn: $state.useAppleHealth)
                     HStack {
                         Image(systemName: "pencil.circle.fill")

+ 2 - 5
FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift

@@ -1001,9 +1001,6 @@ extension MainChartView {
 
         minValue = minOverall * conversionFactor - 50 * conversionFactor
         maxValue = maxOverall * conversionFactor + 80 * conversionFactor
-
-        debug(.default, "min \(minValue)")
-        debug(.default, "max \(maxValue)")
     }
 
     private func yAxisChartDataCobChart() {
@@ -1064,7 +1061,7 @@ extension MainChartView {
     private var mainChartYAxis: some AxisContent {
         AxisMarks(position: .trailing) { value in
 
-            if displayXgridLines {
+            if displayYgridLines {
                 AxisGridLine(stroke: .init(lineWidth: 0.5, dash: [2, 3]))
             } else {
                 AxisGridLine(stroke: .init(lineWidth: 0, dash: [2, 3]))
@@ -1082,7 +1079,7 @@ extension MainChartView {
 
     private var cobChartYAxis: some AxisContent {
         AxisMarks(position: .trailing) { _ in
-            if displayXgridLines {
+            if displayYgridLines {
                 AxisGridLine(stroke: .init(lineWidth: 0.5, dash: [2, 3]))
             } else {
                 AxisGridLine(stroke: .init(lineWidth: 0, dash: [2, 3]))

+ 3 - 32
FreeAPS/Sources/Services/HealthKit/HealthKitManager.swift

@@ -168,14 +168,7 @@ final class BaseHealthKitManager: HealthKitManager, Injectable, CarbsObserver, P
                 }
 
             healthKitStore.save(samplesToSave) { (success: Bool, error: Error?) -> Void in
-                if success {
-                    for sample in samplesToSave {
-                        debug(
-                            .service,
-                            "Stored blood glucose \(sample.quantity) in HealthKit Store! Metadata: \(String(describing: sample.metadata?.values))"
-                        )
-                    }
-                } else {
+                if !success {
                     debug(.service, "Failed to store blood glucose in HealthKit Store!")
                     debug(.service, error?.localizedDescription ?? "Unknown error")
                 }
@@ -222,14 +215,7 @@ final class BaseHealthKitManager: HealthKitManager, Injectable, CarbsObserver, P
                 }
 
             healthKitStore.save(samplesToSave) { (success: Bool, error: Error?) -> Void in
-                if success {
-                    for sample in samplesToSave {
-                        debug(
-                            .service,
-                            "Stored carb entry \(sample.quantity) in HealthKit Store! Metadata: \(String(describing: sample.metadata?.values))"
-                        )
-                    }
-                } else {
+                if !success {
                     debug(.service, "Failed to store carb entry in HealthKit Store!")
                     debug(.service, error?.localizedDescription ?? "Unknown error")
                 }
@@ -298,14 +284,7 @@ final class BaseHealthKitManager: HealthKitManager, Injectable, CarbsObserver, P
                 }
 
             healthKitStore.save(bolusSamples + basalSamples) { (success: Bool, error: Error?) -> Void in
-                if success {
-                    for sample in bolusSamples + basalSamples {
-                        debug(
-                            .service,
-                            "Stored insulin entry in HealthKit Store! Metadata: \(String(describing: sample.metadata?.values))"
-                        )
-                    }
-                } else {
+                if !success {
                     debug(.service, "Failed to store insulin entry in HealthKit Store!")
                     debug(.service, error?.localizedDescription ?? "Unknown error")
                 }
@@ -493,7 +472,6 @@ final class BaseHealthKitManager: HealthKitManager, Injectable, CarbsObserver, P
 
     private func prepareBGSamplesToPublisherFetch(_ samples: [HKQuantitySample]) {
         dispatchPrecondition(condition: .onQueue(processQueue))
-        debug(.service, "Start preparing samples: \(String(describing: samples))")
 
         newGlucose += samples
             .compactMap { sample -> HealthKitSample? in
@@ -522,11 +500,6 @@ final class BaseHealthKitManager: HealthKitManager, Injectable, CarbsObserver, P
             .filter { $0.dateString >= Date().addingTimeInterval(-1.days.timeInterval) }
 
         newGlucose = newGlucose.removeDublicates()
-
-        debug(
-            .service,
-            "Current BloodGlucose.Type objects will be send from Publisher during fetch: \(String(describing: newGlucose))"
-        )
     }
 
     // MARK: - GlucoseSource
@@ -542,9 +515,7 @@ final class BaseHealthKitManager: HealthKitManager, Injectable, CarbsObserver, P
             }
 
             self.processQueue.async {
-                //   debug(.service, "Start fetching HealthKitManager")
                 guard self.settingsManager.settings.useAppleHealth else {
-                    debug(.service, "HealthKitManager cant return any data, because useAppleHealth option is disable")
                     promise(.success([]))
                     return
                 }

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

@@ -344,8 +344,8 @@ extension NightscoutAPI {
         do {
             let encodedBody = try JSONCoding.encoder.encode(treatments)
             request.httpBody = encodedBody
-            debugPrint("Payload treatments size: \(encodedBody.count) bytes")
-            debugPrint(String(data: encodedBody, encoding: .utf8) ?? "Invalid payload")
+//            debugPrint("Payload treatments size: \(encodedBody.count) bytes")
+//            debugPrint(String(data: encodedBody, encoding: .utf8) ?? "Invalid payload")
         } catch {
             debugPrint("Error encoding payload: \(error.localizedDescription)")
             throw error
@@ -359,7 +359,7 @@ extension NightscoutAPI {
             throw URLError(.badServerResponse)
         }
 
-        debugPrint("Upload successful, response data: \(String(data: data, encoding: .utf8) ?? "No data")")
+//        debugPrint("Upload successful, response data: \(String(data: data, encoding: .utf8) ?? "No data")")
     }
 
     func uploadGlucose(_ glucose: [BloodGlucose]) async throws {
@@ -380,8 +380,8 @@ extension NightscoutAPI {
         do {
             let encodedBody = try JSONCoding.encoder.encode(glucose)
             request.httpBody = encodedBody
-            debugPrint("Payload glucose size: \(encodedBody.count) bytes")
-            debugPrint(String(data: encodedBody, encoding: .utf8) ?? "Invalid payload")
+//            debugPrint("Payload glucose size: \(encodedBody.count) bytes")
+//            debugPrint(String(data: encodedBody, encoding: .utf8) ?? "Invalid payload")
         } catch {
             debugPrint("Error encoding payload: \(error.localizedDescription)")
             throw error
@@ -395,7 +395,7 @@ extension NightscoutAPI {
             throw URLError(.badServerResponse)
         }
 
-        debugPrint("Upload successful, response data: \(String(data: data, encoding: .utf8) ?? "No data")")
+//        debugPrint("Upload successful, response data: \(String(data: data, encoding: .utf8) ?? "No data")")
     }
 
     func uploadStats(_ stats: NightscoutStatistics) async throws {
@@ -442,8 +442,8 @@ extension NightscoutAPI {
         do {
             let encodedBody = try JSONCoding.encoder.encode(status)
             request.httpBody = encodedBody
-            debugPrint("Payload glucose size: \(encodedBody.count) bytes")
-            debugPrint(String(data: encodedBody, encoding: .utf8) ?? "Invalid payload")
+//            debugPrint("Payload glucose size: \(encodedBody.count) bytes")
+//            debugPrint(String(data: encodedBody, encoding: .utf8) ?? "Invalid payload")
         } catch {
             debugPrint("Error encoding payload: \(error.localizedDescription)")
             throw error
@@ -572,8 +572,8 @@ extension NightscoutAPI {
         do {
             let encodedBody = try JSONCoding.encoder.encode(overrides)
             request.httpBody = encodedBody
-            debugPrint("Payload glucose size: \(encodedBody.count) bytes")
-            debugPrint(String(data: encodedBody, encoding: .utf8) ?? "Invalid payload")
+//            debugPrint("Payload glucose size: \(encodedBody.count) bytes")
+//            debugPrint(String(data: encodedBody, encoding: .utf8) ?? "Invalid payload")
         } catch {
             debugPrint("Error encoding payload: \(error.localizedDescription)")
             throw error
@@ -587,7 +587,7 @@ extension NightscoutAPI {
             throw URLError(.badServerResponse)
         }
 
-        debugPrint("Upload successful, response data: \(String(data: data, encoding: .utf8) ?? "No data")")
+//        debugPrint("Upload successful, response data: \(String(data: data, encoding: .utf8) ?? "No data")")
     }
 }
 

+ 0 - 14
FreeAPS/Sources/Services/Network/NightscoutManager.swift

@@ -482,13 +482,11 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
     private func updateOrefDeterminationAsUploaded(_ determination: [Determination]) async {
         await backgroundContext.perform {
             let ids = determination.map(\.id) as NSArray
-            print("\(DebuggingIdentifiers.inProgress) ids: \(ids)")
             let fetchRequest: NSFetchRequest<OrefDetermination> = OrefDetermination.fetchRequest()
             fetchRequest.predicate = NSPredicate(format: "id IN %@", ids)
 
             do {
                 let results = try self.backgroundContext.fetch(fetchRequest)
-                print("\(DebuggingIdentifiers.inProgress) results: \(results)")
                 for result in results {
                     result.isUploadedToNS = true
                 }
@@ -737,13 +735,11 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
     private func updateGlucoseAsUploaded(_ glucose: [BloodGlucose]) async {
         await backgroundContext.perform {
             let ids = glucose.map(\.id) as NSArray
-            print("\(DebuggingIdentifiers.inProgress) ids: \(ids)")
             let fetchRequest: NSFetchRequest<GlucoseStored> = GlucoseStored.fetchRequest()
             fetchRequest.predicate = NSPredicate(format: "id IN %@", ids)
 
             do {
                 let results = try self.backgroundContext.fetch(fetchRequest)
-                print("\(DebuggingIdentifiers.inProgress) results: \(results)")
                 for result in results {
                     result.isUploadedToNS = true
                 }
@@ -780,13 +776,11 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
     private func updateTreatmentsAsUploaded(_ treatments: [NightscoutTreatment]) async {
         await backgroundContext.perform {
             let ids = treatments.map(\.id) as NSArray
-            print("\(DebuggingIdentifiers.inProgress) ids: \(ids)")
             let fetchRequest: NSFetchRequest<PumpEventStored> = PumpEventStored.fetchRequest()
             fetchRequest.predicate = NSPredicate(format: "id IN %@", ids)
 
             do {
                 let results = try self.backgroundContext.fetch(fetchRequest)
-                print("\(DebuggingIdentifiers.inProgress) results: \(results)")
                 for result in results {
                     result.isUploadedToNS = true
                 }
@@ -823,13 +817,11 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
     private func updateManualGlucoseAsUploaded(_ treatments: [NightscoutTreatment]) async {
         await backgroundContext.perform {
             let ids = treatments.map(\.id) as NSArray
-            print("\(DebuggingIdentifiers.inProgress) ids: \(ids)")
             let fetchRequest: NSFetchRequest<GlucoseStored> = GlucoseStored.fetchRequest()
             fetchRequest.predicate = NSPredicate(format: "id IN %@", ids)
 
             do {
                 let results = try self.backgroundContext.fetch(fetchRequest)
-                print("\(DebuggingIdentifiers.inProgress) results: \(results)")
                 for result in results {
                     result.isUploadedToNS = true
                 }
@@ -866,13 +858,11 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
     private func updateCarbsAsUploaded(_ treatments: [NightscoutTreatment]) async {
         await backgroundContext.perform {
             let ids = treatments.map(\.id) as NSArray
-            print("\(DebuggingIdentifiers.inProgress) ids: \(ids)")
             let fetchRequest: NSFetchRequest<CarbEntryStored> = CarbEntryStored.fetchRequest()
             fetchRequest.predicate = NSPredicate(format: "id IN %@", ids)
 
             do {
                 let results = try self.backgroundContext.fetch(fetchRequest)
-                print("\(DebuggingIdentifiers.inProgress) results: \(results)")
                 for result in results {
                     result.isUploadedToNS = true
                 }
@@ -909,13 +899,11 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
     private func updateOverridesAsUploaded(_ overrides: [NightscoutExercise]) async {
         await backgroundContext.perform {
             let ids = overrides.map(\.id) as NSArray
-            print("\(DebuggingIdentifiers.inProgress) ids: \(ids)")
             let fetchRequest: NSFetchRequest<OverrideStored> = OverrideStored.fetchRequest()
             fetchRequest.predicate = NSPredicate(format: "id IN %@", ids)
 
             do {
                 let results = try self.backgroundContext.fetch(fetchRequest)
-                print("\(DebuggingIdentifiers.inProgress) results: \(results)")
                 for result in results {
                     result.isUploadedToNS = true
                 }
@@ -952,13 +940,11 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
     private func updateOverrideRunsAsUploaded(_ overrideRuns: [NightscoutExercise]) async {
         await backgroundContext.perform {
             let ids = overrideRuns.map(\.id) as NSArray
-            print("\(DebuggingIdentifiers.inProgress) ids: \(ids)")
             let fetchRequest: NSFetchRequest<OverrideRunStored> = OverrideRunStored.fetchRequest()
             fetchRequest.predicate = NSPredicate(format: "id IN %@", ids)
 
             do {
                 let results = try self.backgroundContext.fetch(fetchRequest)
-                print("\(DebuggingIdentifiers.inProgress) results: \(results)")
                 for result in results {
                     result.isUploadedToNS = true
                 }

+ 1 - 1
FreeAPS/Sources/Services/UserNotifications/UserNotificationsManager.swift

@@ -243,7 +243,7 @@ final class BaseUserNotificationsManager: NSObject, UserNotificationsManager, In
 
             guard let lastReading = glucoseObjects.first?.glucose,
                   let secondLastReading = glucoseObjects.dropFirst().first?.glucose,
-                  let lastDirection = glucoseObjects.first?.direction else { return }
+                  let lastDirection = glucoseObjects.first?.directionEnum?.symbol else { return }
 
             addAppBadge(glucose: (glucoseObjects.first?.glucose).map { Int($0) })
 

+ 1 - 1
FreeAPS/Sources/Services/WatchManager/WatchManager.swift

@@ -207,7 +207,7 @@ final class BaseWatchManager: NSObject, WatchManager, Injectable {
                 let value = settingsManager.settings
                     .units == .mgdL ? Decimal(firstGlucoseValue.glucose) : Decimal(firstGlucoseValue.glucose).asMmolL
                 state.glucose = glucoseFormatter.string(from: value as NSNumber)
-                state.trend = firstGlucoseValue.direction
+                state.trend = firstGlucoseValue.directionEnum?.symbol
                 let delta = glucoseValues
                     .count >= 2 ? Decimal(firstGlucoseValue.glucose) - Decimal(glucoseValues.dropFirst().first?.glucose ?? 0) : 0
                 let deltaConverted = settingsManager.settings.units == .mgdL ? delta : delta.asMmolL

+ 14 - 14
Model/CoreDataStack.swift

@@ -106,7 +106,7 @@ class CoreDataStack: ObservableObject {
     private func fetchPersistentHistoryTransactionsAndChanges() async throws {
         let taskContext = newTaskContext()
         taskContext.name = "persistentHistoryContext"
-        debugPrint("Start fetching persistent history changes from the store ... \(DebuggingIdentifiers.inProgress)")
+//        debugPrint("Start fetching persistent history changes from the store ... \(DebuggingIdentifiers.inProgress)")
 
         try await taskContext.perform {
             // Execute the persistent history change since the last transaction
@@ -121,7 +121,7 @@ class CoreDataStack: ObservableObject {
     }
 
     private func mergePersistentHistoryChanges(from history: [NSPersistentHistoryTransaction]) {
-        debugPrint("Received \(history.count) persistent history transactions")
+//        debugPrint("Received \(history.count) persistent history transactions")
         // Update view context with objectIDs from history change request
         /// - Tag: mergeChanges
         let viewContext = persistentContainer.viewContext
@@ -210,7 +210,7 @@ extension CoreDataStack {
 
             // Guard check if there are NSManagedObjects older than the specified days
             guard !objectIDs.isEmpty else {
-                debugPrint("No objects found older than \(days) days.")
+//                debugPrint("No objects found older than \(days) days.")
                 return
             }
 
@@ -258,7 +258,7 @@ extension CoreDataStack {
             }
 
             guard !parentObjectIDs.isEmpty else {
-                debugPrint("No \(parentType) objects found older than \(days) days.")
+//                debugPrint("No \(parentType) objects found older than \(days) days.")
                 return
             }
 
@@ -272,7 +272,7 @@ extension CoreDataStack {
             }
 
             guard !childObjectIDs.isEmpty else {
-                debugPrint("No \(childType) objects found related to \(parentType) objects older than \(days) days.")
+//                debugPrint("No \(childType) objects found related to \(parentType) objects older than \(days) days.")
                 return
             }
 
@@ -339,9 +339,9 @@ extension CoreDataStack {
         /// we need to ensure that the fetch immediately returns a value as long as the whole app does not use the async await pattern, otherwise we could perform this asynchronously with backgroundContext.perform and not block the thread
         context.performAndWait {
             do {
-                debugPrint(
-                    "Fetching \(T.self) in \(callingFunction) from \(callingClass): \(DebuggingIdentifiers.succeeded) on Thread: \(Thread.current)"
-                )
+//                debugPrint(
+//                    "Fetching \(T.self) in \(callingFunction) from \(callingClass): \(DebuggingIdentifiers.succeeded) on Thread: \(Thread.current)"
+//                )
                 result = try context.fetch(request)
             } catch let error as NSError {
                 debugPrint(
@@ -387,9 +387,9 @@ extension CoreDataStack {
 
         return await context.perform {
             do {
-                debugPrint(
-                    "Fetching \(T.self) in \(callingFunction) from \(callingClass): \(DebuggingIdentifiers.succeeded) on Thread: \(Thread.current)"
-                )
+//                debugPrint(
+//                    "Fetching \(T.self) in \(callingFunction) from \(callingClass): \(DebuggingIdentifiers.succeeded) on Thread: \(Thread.current)"
+//                )
                 if propertiesToFetch != nil {
                     return try context.fetch(request) as? [[String: Any]] ?? []
                 } else {
@@ -433,9 +433,9 @@ extension NSManagedObjectContext {
         do {
             guard onContext.hasChanges else { return }
             try onContext.save()
-            debugPrint(
-                "Saving to Core Data successful in \(callingFunction) in \(callingClass): \(DebuggingIdentifiers.succeeded)"
-            )
+//            debugPrint(
+//                "Saving to Core Data successful in \(callingFunction) in \(callingClass): \(DebuggingIdentifiers.succeeded)"
+//            )
         } catch let error as NSError {
             debugPrint(
                 "Saving to Core Data failed in \(callingFunction) in \(callingClass): \(DebuggingIdentifiers.failed) with error \(error), \(error.userInfo)"

+ 9 - 0
Model/Helper/NSPredicates.swift

@@ -6,6 +6,10 @@ extension Date {
         Calendar.current.startOfDay(for: Date())
     }
 
+    static var oneDayAgoInMinutes: Date {
+        Calendar.current.date(byAdding: .minute, value: -1440, to: Date())!
+    }
+
     static var oneDayAgo: Date {
         Calendar.current.date(byAdding: .day, value: -1, to: Date())!
     }
@@ -48,6 +52,11 @@ extension NSPredicate {
 
     static let none = NSPredicate(format: "FALSEPREDICATE")
 
+    static var predicateForOneDayAgoInMinutes: NSPredicate {
+        let date = Date.oneDayAgoInMinutes
+        return NSPredicate(format: "date >= %@", date as NSDate)
+    }
+
     static var predicateForOneDayAgo: NSPredicate {
         let date = Date.oneDayAgo
         return NSPredicate(format: "date >= %@", date as NSDate)

+ 8 - 3
Model/Helper/PumpEvent+helper.swift

@@ -53,6 +53,11 @@ public extension PumpEventStored {
 }
 
 extension NSPredicate {
+    static var pumpHistoryLast1440Minutes: NSPredicate {
+        let date = Date.oneDayAgoInMinutes
+        return NSPredicate(format: "timestamp >= %@", date as NSDate)
+    }
+
     static var pumpHistoryLast24h: NSPredicate {
         let date = Date.oneDayAgo
         return NSPredicate(format: "timestamp >= %@", date as NSDate)
@@ -155,7 +160,7 @@ extension PumpEventStored {
     }
 
     func toTempBasalDTOEnum() -> PumpEventDTO? {
-        guard let timestamp = timestamp, let tempBasal = tempBasal, let rate = tempBasal.rate else {
+        guard let id = id, let timestamp = timestamp, let tempBasal = tempBasal, let rate = tempBasal.rate else {
             return nil
         }
 
@@ -169,12 +174,12 @@ extension PumpEventStored {
     }
 
     func toTempBasalDurationDTOEnum() -> PumpEventDTO? {
-        guard let timestamp = timestamp, let tempBasal = tempBasal else {
+        guard let id = id, let timestamp = timestamp, let tempBasal = tempBasal else {
             return nil
         }
 
         let tempBasalDurationDTO = TempBasalDurationDTO(
-            id: id ?? UUID().uuidString,
+            id: id,
             timestamp: PumpEventStored.dateFormatter.string(from: timestamp),
             duration: Int(tempBasal.duration)
         )

+ 3 - 2
Trio.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -1,4 +1,5 @@
 {
+  "originHash" : "59ac7eba66375d6eb406e758cb0b9964f4b3b0ae45c5665596f00384c32262b9",
   "pins" : [
     {
       "identity" : "cryptoswift",
@@ -48,7 +49,7 @@
     {
       "identity" : "swiftcharts",
       "kind" : "remoteSourceControl",
-      "location" : "https://github.com/ivanschuetz/SwiftCharts",
+      "location" : "https://github.com/ivanschuetz/SwiftCharts.git",
       "state" : {
         "branch" : "master",
         "revision" : "c354c1945bb35a1f01b665b22474f6db28cba4a2"
@@ -91,5 +92,5 @@
       }
     }
   ],
-  "version" : 2
+  "version" : 3
 }

+ 1 - 6
scripts/capture-build-details.sh

@@ -1,22 +1,17 @@
 #!/bin/sh -e
-
 #  capture-build-details.sh
 #  Trio
 #
 #  Created by Jonas Björkert on 2024-05-08.
-
 # Enable debugging if needed
 #set -x
-
 info_plist_path="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/BuildDetails.plist"
-
 # Ensure the path to BuildDetails.plist is valid.
 if [ "${info_plist_path}" == "/" -o ! -e "${info_plist_path}" ]; then
     echo "BuildDetails.plist file does not exist at path: ${info_plist_path}" >&2
     exit 1
 else
     echo "Gathering build details..."
-
     # Capture the current date and write it to BuildDetails.plist
     plutil -replace com-trio-build-date -string "$(date)" "${info_plist_path}"
 
@@ -40,4 +35,4 @@ else
 
     # Update BuildDetails.plist with the SHA information
     plutil -replace com-trio-commit-sha -string "${git_commit_sha}" "${info_plist_path}"
-fi
+fi