Prechádzať zdrojové kódy

Fix problem where a temp target does not get used by oref when another temp target was already running; Add ability to reorder presets; Fix Save button in Edit Temp Target Sheet enabling on preset name change; Fix problem where an editet Temp target does not get used by oref

polscm32 aka Marvout 1 rok pred
rodič
commit
d45a9b1709

+ 1 - 1
FreeAPS/Sources/APS/Storage/OverrideStorage.swift

@@ -14,7 +14,7 @@ protocol OverrideStorage {
     func getOverrideRunsNotYetUploadedToNightscout() async -> [NightscoutExercise]
 }
 
-final class BaseOverrideStorage: OverrideStorage, Injectable {
+final class BaseOverrideStorage: @preconcurrency OverrideStorage, Injectable {
     @Injected() private var settingsManager: SettingsManager!
 
     private let viewContext = CoreDataStack.shared.persistentContainer.viewContext

+ 14 - 20
FreeAPS/Sources/APS/Storage/TempTargetsStorage.swift

@@ -38,7 +38,7 @@ final class BaseTempTargetsStorage: TempTargetsStorage, Injectable {
             ofType: TempTargetStored.self,
             onContext: backgroundContext,
             predicate: NSPredicate.lastActiveTempTarget,
-            key: "date",
+            key: "orderPosition",
             ascending: true,
             fetchLimit: fetchLimit
         )
@@ -56,7 +56,7 @@ final class BaseTempTargetsStorage: TempTargetsStorage, Injectable {
             ofType: TempTargetStored.self,
             onContext: backgroundContext,
             predicate: NSPredicate.allTempTargetPresets,
-            key: "date",
+            key: "orderPosition",
             ascending: true
         )
 
@@ -68,6 +68,12 @@ final class BaseTempTargetsStorage: TempTargetsStorage, Injectable {
     }
 
     func storeTempTarget(tempTarget: TempTarget) async {
+        var presetCount = -1
+        if tempTarget.isPreset == true {
+            let presets = await fetchForTempTargetPresets()
+            presetCount = presets.count
+        }
+
         await backgroundContext.perform {
             let newTempTarget = TempTargetStored(context: self.backgroundContext)
             newTempTarget.date = tempTarget.createdAt
@@ -80,6 +86,11 @@ final class BaseTempTargetsStorage: TempTargetsStorage, Injectable {
             newTempTarget.isPreset = tempTarget.isPreset ?? false
             newTempTarget.halfBasalTarget = NSDecimalNumber(decimal: tempTarget.halfBasalTarget ?? 160)
 
+            // Set order position if we have a valid count and the temp target is a preset
+            if tempTarget.isPreset == true, presetCount > -1 {
+                newTempTarget.orderPosition = Int16(presetCount + 1)
+            }
+
             do {
                 guard self.backgroundContext.hasChanges else { return }
                 try self.backgroundContext.save()
@@ -88,32 +99,15 @@ final class BaseTempTargetsStorage: TempTargetsStorage, Injectable {
                     "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to save Temp Target to Core Data with error: \(error.userInfo)"
                 )
             }
-
-            /*
-             Saving the Preset to the Storage means that it gets used by Oref
-             We only want that when either creating a new non-Preset-Temp Target or when enacting a Temp Target Preset, NOT when we are only saving a new Preset, hence the check here!
-             */
-            if !(tempTarget.isPreset ?? false) {
-                self.saveTempTargetsToStorage([tempTarget])
-            }
         }
     }
 
     func saveTempTargetsToStorage(_ targets: [TempTarget]) {
         processQueue.async {
-            var updatedTargets = targets
-
-            if let newActive = updatedTargets.last(where: { $0.isActive }) {
-                // Cancel current target
-                // This logic to add a new cancel Temp target to cancel the current one is so fucking dumb...
-                updatedTargets.append(.cancel(at: newActive.createdAt.addingTimeInterval(-1)))
-            }
-
             let file = OpenAPS.Settings.tempTargets
-
             var uniqEvents: [TempTarget] = []
             self.storage.transaction { storage in
-                storage.append(updatedTargets, to: file, uniqBy: \.createdAt)
+                storage.append(targets, to: file, uniqBy: \.createdAt)
 
                 let retrievedTargets = storage.retrieve(file, as: [TempTarget].self) ?? []
                 uniqEvents = retrievedTargets

+ 41 - 18
FreeAPS/Sources/Modules/OverrideConfig/OverrideStateModel.swift

@@ -175,6 +175,26 @@ extension OverrideConfig.StateModel {
         }
     }
 
+    func reorderTempTargets(from source: IndexSet, to destination: Int) {
+        tempTargetPresets.move(fromOffsets: source, toOffset: destination)
+
+        for (index, tempTarget) in tempTargetPresets.enumerated() {
+            tempTarget.orderPosition = Int16(index + 1)
+        }
+
+        do {
+            guard viewContext.hasChanges else { return }
+            try viewContext.save()
+
+            // Update Presets View
+            setupTempTargetPresetsArray()
+        } catch {
+            debugPrint(
+                "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to save after reordering Temp Target Presets with error: \(error.localizedDescription)"
+            )
+        }
+    }
+
     /// here we only have to update the Boolean Flag 'enabled'
     @MainActor func enactOverridePreset(withID id: NSManagedObjectID) async {
         do {
@@ -288,11 +308,11 @@ extension OverrideConfig.StateModel {
         // First disable all Overrides
         await disableAllActiveOverrides(createOverrideRunEntry: true)
 
-        // Then save and activate a new custom Override and reset the State variables
-        async let storeOverride: () = overrideStorage.storeOverride(override: override)
-        async let resetState: () = resetStateVariables()
+        // Then save and activate a new custom Override
+        await overrideStorage.storeOverride(override: override)
 
-        _ = await (storeOverride, resetState)
+        // Reset State variables
+        await resetStateVariables()
 
         // Update View
         updateLatestOverrideConfiguration()
@@ -550,8 +570,15 @@ extension OverrideConfig.StateModel {
         }
     }
 
+    func saveTempTargetToStorage(tempTargets: [TempTarget]) {
+        tempTargetStorage.saveTempTargetsToStorage(tempTargets)
+    }
+
     // Creates and enacts a non Preset Temp Target
     func saveCustomTempTarget() async {
+        // First disable all active TempTargets
+        await disableAllActiveTempTargets(createTempTargetRunEntry: true)
+
         let tempTarget = TempTarget(
             name: tempTargetName,
             createdAt: Date(),
@@ -565,16 +592,14 @@ extension OverrideConfig.StateModel {
             halfBasalTarget: halfBasalTarget
         )
 
-        // First disable all active TempTargets
-        await disableAllActiveTempTargets(createTempTargetRunEntry: true)
+        // Save Temp Target to Core Data
+        await tempTargetStorage.storeTempTarget(tempTarget: tempTarget)
 
-        // Save Temp Target to Core Data and to the storage
-        async let storeTempTarget: () = tempTargetStorage.storeTempTarget(tempTarget: tempTarget)
+        // Enact Temp Target for oref
+        tempTargetStorage.saveTempTargetsToStorage([tempTarget])
 
         // Reset State variables
-        async let resetState: () = resetTempTargetState()
-
-        _ = await (storeTempTarget, resetState)
+        await resetTempTargetState()
 
         // Update View
         updateLatestTempTargetConfiguration()
@@ -595,6 +620,7 @@ extension OverrideConfig.StateModel {
             halfBasalTarget: halfBasalTarget
         )
 
+        // Save to Core Data
         await tempTargetStorage.storeTempTarget(tempTarget: tempTarget)
 
         // Reset State variables
@@ -626,8 +652,9 @@ extension OverrideConfig.StateModel {
 
             _ = await (disableTempTargets, resetState)
 
-            guard viewContext.hasChanges else { return }
-            try viewContext.save()
+            if viewContext.hasChanges {
+                try viewContext.save()
+            }
 
             // Update View
             updateLatestTempTargetConfiguration()
@@ -695,12 +722,8 @@ extension OverrideConfig.StateModel {
                 if self.viewContext.hasChanges {
                     try self.viewContext.save()
 
-                    // Update the View
-                    self.updateLatestTempTargetConfiguration()
-
                     // Update the storage
-//                   await self.tempTargetStorage.storeTempTarget(tempTarget: TempTarget.cancel(at: Date()))
-                    self.tempTargetStorage.saveTempTargetsToStorage([TempTarget.cancel(at: Date())])
+                    self.tempTargetStorage.saveTempTargetsToStorage([TempTarget.cancel(at: Date().addingTimeInterval(-1))])
                 }
             } catch {
                 debugPrint(

+ 30 - 2
FreeAPS/Sources/Modules/OverrideConfig/View/EditTempTargetForm.swift

@@ -17,6 +17,8 @@ struct EditTempTargetForm: View {
     @State private var hasChanges = false
     @State private var showAlert = false
     @State private var isUsingSlider = false
+    @State private var isPreset = false
+    @State private var isEnabled = false
 
     init(tempTargetToEdit: TempTargetStored, state: OverrideConfig.StateModel) {
         tempTarget = tempTargetToEdit
@@ -26,6 +28,8 @@ struct EditTempTargetForm: View {
         _duration = State(initialValue: tempTargetToEdit.duration?.decimalValue ?? 0)
         _date = State(initialValue: tempTargetToEdit.date ?? Date())
         _halfBasalTarget = State(initialValue: tempTargetToEdit.halfBasalTarget?.decimalValue ?? 160)
+        _isPreset = State(initialValue: tempTargetToEdit.isPreset)
+        _isEnabled = State(initialValue: tempTargetToEdit.enabled)
 
         let normalTarget: Decimal = 100
         if let hbt = tempTargetToEdit.halfBasalTarget?.decimalValue {
@@ -122,6 +126,9 @@ struct EditTempTargetForm: View {
                     Spacer()
                     TextField("Enter Name (optional)", text: $name)
                         .multilineTextAlignment(.trailing)
+                        .onChange(of: name) {
+                            hasChanges = true
+                        }
                 }
                 HStack {
                     Text("Target")
@@ -156,7 +163,7 @@ struct EditTempTargetForm: View {
                     Text("minutes").foregroundColor(.secondary)
                 }
                 DatePicker("Date", selection: $date)
-                    .onChange(of: date) { _ in hasChanges = true }
+                    .onChange(of: date) { hasChanges = true }
             }
         ).listRowBackground(Color.chart)
 
@@ -234,14 +241,35 @@ struct EditTempTargetForm: View {
                         guard moc.hasChanges else { return }
                         try moc.save()
 
-                        // Disable previous active Temp Target and update View
                         if let currentActiveTempTarget = state.currentActiveTempTarget {
                             Task {
+                                // TODO: - Creating a Run entry is probably needed for Overrides as well and the reason for "jumping" Overrides?
+                                // Disable previous active Temp Targets
                                 await state.disableAllActiveOverrides(
                                     except: currentActiveTempTarget.objectID,
                                     createOverrideRunEntry: false
                                 )
 
+                                // If the temp target which currently gets edited is enabled, then store it to the Temp Target JSON so that oref uses it
+                                if isEnabled {
+                                    let tempTarget = TempTarget(
+                                        name: name,
+                                        createdAt: Date(),
+                                        targetTop: target,
+                                        targetBottom: target,
+                                        duration: duration,
+                                        enteredBy: TempTarget.manual,
+                                        reason: TempTarget.custom,
+                                        isPreset: isPreset ? true : false,
+                                        enabled: isEnabled ? true : false,
+                                        halfBasalTarget: halfBasalTarget
+                                    )
+
+                                    // Store to TempTargetStorage so that oref uses the edited Temp target
+                                    state.saveTempTargetToStorage(tempTargets: [tempTarget])
+                                }
+
+                                // Update view
                                 state.updateLatestTempTargetConfiguration()
                             }
                         }

+ 8 - 1
FreeAPS/Sources/Modules/OverrideConfig/View/OverrideRootView.swift

@@ -288,7 +288,7 @@ extension OverrideConfig {
                             })
                         }
                 }
-//                .onMove(perform: state.reorderOverride)
+                .onMove(perform: state.reorderTempTargets)
                 .listRowBackground(Color.chart)
             } header: {
                 Text("Presets")
@@ -378,6 +378,9 @@ extension OverrideConfig {
                         // Save cancelled Temp Targets in TempTargetRunStored Entity
                         // Cancel ALL active Temp Targets
                         await state.disableAllActiveTempTargets(createTempTargetRunEntry: true)
+
+                        // Update View
+                        state.updateLatestTempTargetConfiguration()
                     }
                 }, label: {
                     Text("Cancel Temp Target")
@@ -447,6 +450,10 @@ extension OverrideConfig {
                         .imageScale(.large)
                         .fontWeight(.bold)
                         .foregroundStyle(Color.green)
+                } else {
+                    Image(systemName: "line.3.horizontal")
+                        .imageScale(.medium)
+                        .foregroundStyle(.secondary)
                 }
             })
         }

+ 2 - 1
Model/TrioCoreDataPersistentContainer.xcdatamodeld/TrioCoreDataPersistentContainer.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="23222.3" systemVersion="23G93" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithSwiftData="YES" userDefinedModelVersionIdentifier="">
+<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="23231" systemVersion="24A335" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithSwiftData="YES" userDefinedModelVersionIdentifier="">
     <entity name="BolusStored" representedClassName="BolusStored" syncable="YES">
         <attribute name="amount" optional="YES" attributeType="Decimal" defaultValueString="0"/>
         <attribute name="isExternal" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
@@ -215,6 +215,7 @@
         <attribute name="isPreset" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
         <attribute name="isUploadedToNS" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
         <attribute name="name" optional="YES" attributeType="String"/>
+        <attribute name="orderPosition" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
         <attribute name="target" optional="YES" attributeType="Decimal" defaultValueString="160"/>
         <relationship name="tempTargetRun" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TempTargetRunStored" inverseName="tempTarget" inverseEntity="TempTargetRunStored"/>
         <fetchIndex name="byDate">

+ 1 - 0
TempTargetStored+CoreDataProperties.swift

@@ -16,6 +16,7 @@ public extension TempTargetStored {
     @NSManaged var isPreset: Bool
     @NSManaged var halfBasalTarget: NSDecimalNumber?
     @NSManaged var tempTargetRun: TempTargetRunStored?
+    @NSManaged var orderPosition: Int16
 }
 
 extension TempTargetStored: Identifiable {}