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

Improve Loop Status View error messaging WIP

Deniz Cengiz пре 1 година
родитељ
комит
0b71dc2f25

+ 12 - 15
Trio/Sources/APS/APSManager.swift

@@ -33,23 +33,20 @@ enum APSError: LocalizedError {
     case invalidPumpState(message: String)
     case glucoseError(message: String)
     case apsError(message: String)
-    case deviceSyncError(message: String)
     case manualBasalTemp(message: String)
 
     var errorDescription: String? {
         switch self {
         case let .pumpError(error):
-            return "Pump error: \(error.localizedDescription)"
+            return String(localized: "Pump Error (\(error.localizedDescription)).")
         case let .invalidPumpState(message):
-            return "Error: Invalid Pump State: \(message)"
+            return String(localized: "Invalid Pump State (\(message)).")
         case let .glucoseError(message):
-            return "Error: Invalid glucose: \(message)"
+            return String(localized: "Invalid Glucose (\(message)).")
         case let .apsError(message):
-            return "APS error: \(message)"
-        case let .deviceSyncError(message):
-            return "Sync error: \(message)"
+            return String(localized: "Invalid Algorithm Response (\(message)).")
         case let .manualBasalTemp(message):
-            return "Manual Basal Temp : \(message)"
+            return String(localized: "Manual Temporary Basal Rate (\(message)). Looping suspended.")
         }
     }
 }
@@ -351,21 +348,21 @@ final class BaseAPSManager: APSManager, Injectable {
 
     private func verifyStatus() -> Error? {
         guard let pump = pumpManager else {
-            return APSError.invalidPumpState(message: "Pump not set")
+            return APSError.invalidPumpState(message: String(localized: "Pump not set"))
         }
         let status = pump.status.pumpStatus
 
         guard !status.bolusing else {
-            return APSError.invalidPumpState(message: "Pump is bolusing")
+            return APSError.invalidPumpState(message: String(localized: "Pump is bolusing"))
         }
 
         guard !status.suspended else {
-            return APSError.invalidPumpState(message: "Pump suspended")
+            return APSError.invalidPumpState(message: String(localized: "Pump suspended"))
         }
 
         let reservoir = storage.retrieve(OpenAPS.Monitor.reservoir, as: Decimal.self) ?? 100
         guard reservoir >= 0 else {
-            return APSError.invalidPumpState(message: "Reservoir is empty")
+            return APSError.invalidPumpState(message: String(localized: "Reservoir is empty"))
         }
 
         return nil
@@ -417,20 +414,20 @@ final class BaseAPSManager: APSManager, Injectable {
 
             guard glucose.count > 2 else {
                 debug(.apsManager, "Not enough glucose data")
-                self.processError(APSError.glucoseError(message: "Not enough glucose data"))
+                self.processError(APSError.glucoseError(message: String(localized: "Not enough glucose data")))
                 return false
             }
 
             let dateOfLastGlucose = glucose.first?.date
             guard dateOfLastGlucose ?? Date() >= Date().addingTimeInterval(-12.minutes.timeInterval) else {
                 debug(.apsManager, "Glucose data is stale")
-                self.processError(APSError.glucoseError(message: "Glucose data is stale"))
+                self.processError(APSError.glucoseError(message: String(localized: "Glucose data is stale")))
                 return false
             }
 
             guard !GlucoseStored.glucoseIsFlat(glucose) else {
                 debug(.apsManager, "Glucose data is too flat")
-                self.processError(APSError.glucoseError(message: "Glucose data is too flat"))
+                self.processError(APSError.glucoseError(message: String(localized: "Glucose data is too flat")))
                 return false
             }
 

+ 1 - 1
Trio/Sources/APS/OpenAPS/OpenAPS.swift

@@ -373,7 +373,7 @@ final class OpenAPS {
 
             return determination
         } else {
-            throw APSError.apsError(message: "Determination is nil")
+            throw APSError.apsError(message: "No determination data.")
         }
     }
 

+ 2 - 3
Trio/Sources/APS/Storage/TDDStorage.swift

@@ -27,14 +27,13 @@ struct TDDResult {
 /// Implementation of the TDD Calculator
 final class BaseTDDStorage: TDDStorage, Injectable {
     @Injected() private var storage: FileStorage!
-    
+
     private let privateContext = CoreDataStack.shared.newTaskContext()
 
     init(resolver: Resolver) {
         injectServices(resolver)
     }
 
-
     /// Main function to calculate TDD from pump history and basal profile
     /// - Parameters:
     ///   - pumpManager: Representation of paired pump's PumpManagerUI
@@ -398,7 +397,7 @@ final class BaseTDDStorage: TDDStorage, Injectable {
 
         return gaps
     }
-    
+
     //    /// Finds gaps between tempBasal events where scheduled basal ran, excluding suspend-resume periods
     //    /// - Parameters:
     //    ///   - tempBasalEvents: Array of pump history events of type tempBasal

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

@@ -77421,6 +77421,9 @@
         }
       }
     },
+    "Enacted at %@" : {
+
+    },
     "Enacting bolus..." : {
       "comment" : "Successful message sent to watch when enacting bolus",
       "localizations" : {
@@ -78746,6 +78749,7 @@
       }
     },
     "Error During Algorithm Run at %@" : {
+      "extractionState" : "stale",
       "localizations" : {
         "bg" : {
           "stringUnit" : {
@@ -89241,6 +89245,12 @@
     "Glucose Count" : {
 
     },
+    "Glucose data is stale" : {
+
+    },
+    "Glucose data is too flat" : {
+
+    },
     "Glucose Data used for statistics" : {
       "comment" : "Debug option view Glucose Data used for statistics",
       "extractionState" : "manual",
@@ -102102,6 +102112,9 @@
         }
       }
     },
+    "Invalid Algorithm Response (%@)." : {
+
+    },
     "Invalid CGM reading (HIGH)." : {
       "localizations" : {
         "bg" : {
@@ -102202,6 +102215,9 @@
         }
       }
     },
+    "Invalid Glucose (%@)." : {
+
+    },
     "Invalid Glucose sample detected, try again later" : {
       "comment" : "Invalid Glucose sample detected, try again later",
       "extractionState" : "manual",
@@ -102418,6 +102434,9 @@
         }
       }
     },
+    "Invalid Pump State (%@)." : {
+
+    },
     "Invalid sensor" : {
       "extractionState" : "manual",
       "localizations" : {
@@ -109051,6 +109070,9 @@
         }
       }
     },
+    "Loop at %@ failed." : {
+
+    },
     "Loop Cycles" : {
       "comment" : "Debug option view",
       "extractionState" : "manual",
@@ -112068,6 +112090,9 @@
         }
       }
     },
+    "Manual Temporary Basal Rate (%@). Looping suspended." : {
+
+    },
     "Manual:" : {
 
     },
@@ -124643,6 +124668,12 @@
     "Not allowed" : {
 
     },
+    "Not enough glucose data" : {
+
+    },
+    "Not looping." : {
+
+    },
     "Not paired yet" : {
       "extractionState" : "manual",
       "localizations" : {
@@ -137503,6 +137534,9 @@
         }
       }
     },
+    "Pump Error (%@)." : {
+
+    },
     "Pump History" : {
       "comment" : "Debug option view Pump History",
       "extractionState" : "manual",
@@ -137711,6 +137745,9 @@
         }
       }
     },
+    "Pump is bolusing" : {
+
+    },
     "Pump Model" : {
       "localizations" : {
         "bg" : {
@@ -137811,6 +137848,9 @@
         }
       }
     },
+    "Pump not set" : {
+
+    },
     "Pump profile" : {
       "comment" : "Debug option view Pump profile",
       "extractionState" : "manual",
@@ -142172,6 +142212,9 @@
         }
       }
     },
+    "Reservoir is empty" : {
+
+    },
     "Reset to Defaults" : {
       "localizations" : {
         "bg" : {
@@ -177046,7 +177089,6 @@
 
     },
     "Time in Range Chart Style" : {
-      "extractionState" : "stale",
       "localizations" : {
         "bg" : {
           "stringUnit" : {
@@ -182241,6 +182283,9 @@
         }
       }
     },
+    "Trio has not looped in %lld minutes." : {
+
+    },
     "Trio has only been actively used and looping for less than seven days. Cannot enable dynamic ISF." : {
 
     },
@@ -188184,6 +188229,7 @@
       }
     },
     "Use Sigmoid Formula" : {
+      "extractionState" : "stale",
       "localizations" : {
         "bg" : {
           "stringUnit" : {

+ 33 - 5
Trio/Sources/Modules/Home/View/Header/LoopStatusView.swift

@@ -12,6 +12,7 @@ struct LoopStatusView: View {
     @State var helpSheetDetent = PresentationDetent.fraction(0.9)
 
     @State private var statusTitle: String = ""
+    @State private var lastDetermination: OrefDetermination?
 
     var body: some View {
         ScrollView {
@@ -44,7 +45,8 @@ struct LoopStatusView: View {
 
                 if let errorMessage = state.errorMessage, let date = state.errorDate {
                     Group {
-                        Text("Error During Algorithm Run at \(Formatter.dateFormatter.string(from: date))").font(.headline)
+                        Text("Loop at \(Formatter.dateFormatter.string(from: date)) failed.").font(.headline)
+                            .font(.headline)
                             .fixedSize(horizontal: false, vertical: true)
                         Text(errorMessage).font(.caption).fixedSize(horizontal: false, vertical: true)
                     }.foregroundColor(.loopRed)
@@ -124,6 +126,9 @@ struct LoopStatusView: View {
                 LoopStatusHelpView(state: state, helpSheetDetent: $helpSheetDetent, isHelpSheetPresented: $isHelpSheetPresented)
             }
         }
+        .onAppear {
+            lastDetermination = state.determinationsFromPersistence.first
+        }
         .presentationDetents([.height(sheetContentHeight)])
         .presentationDragIndicator(.visible)
         .onPreferenceChange(ContentSizeKey.self) { newSize in
@@ -163,11 +168,34 @@ struct LoopStatusView: View {
     }
 
     private func setStatusTitle() {
-        if let determination = state.determinationsFromPersistence.first {
-            statusTitle =
-                "Enacted at \(Formatter.dateFormatter.string(from: determination.deliverAt ?? Date()))"
+        if let determination = state.determinationsFromPersistence.first, let deliverAt = determination.deliverAt {
+            let minutesAgo = abs(deliverAt.timeIntervalSinceNow) / 60
+
+            if deliverAt < Date().addingTimeInterval(-5 * 60) {
+                let roundedMinutes = Int(minutesAgo.rounded())
+                statusTitle = String(
+                    localized: "Trio has not looped in \(roundedMinutes) minutes."
+                )
+            } else {
+                statusTitle = String(
+                    localized: "Enacted at \(Formatter.dateFormatter.string(from: deliverAt))"
+                )
+            }
+        } else if let determination = lastDetermination, let deliverAt = determination.deliverAt {
+            let minutesAgo = abs(deliverAt.timeIntervalSinceNow) / 60
+
+            if deliverAt < Date().addingTimeInterval(-5 * 60) {
+                let roundedMinutes = Int(minutesAgo.rounded())
+                statusTitle = String(
+                    localized: "Trio has not looped in \(roundedMinutes) minutes."
+                )
+            } else {
+                statusTitle = String(
+                    localized: "Enacted at \(Formatter.dateFormatter.string(from: deliverAt))"
+                )
+            }
         } else {
-            statusTitle = "Not enacted."
+            statusTitle = String(localized: "Not looping.")
         }
     }