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

Properly handel LAErrors; no longer mask UnlockError, but throw LAError

Deniz Cengiz 1 год назад
Родитель
Сommit
675aff48de

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

@@ -34783,6 +34783,12 @@
         }
       }
     },
+    "An unknown authentication error occurred. Please try again." : {
+
+    },
+    "An unknown biometric authentication error occurred. Please try again." : {
+
+    },
     "Animated Background" : {
       "extractionState" : "manual",
       "localizations" : {
@@ -37824,7 +37830,25 @@
         }
       }
     },
-    "Authentication failed. Please ensure you have configured a Passcode for your iPhone under iOS Settings > Face ID & Code." : {
+    "Authentication context is invalid. Please try again." : {
+
+    },
+    "Authentication failed. Please try again." : {
+
+    },
+    "Authentication requires a device passcode. Please set one in iOS Settings > Face ID & Passcode." : {
+
+    },
+    "Authentication UI cannot be displayed. Try restarting the app." : {
+
+    },
+    "Authentication was canceled by the app." : {
+
+    },
+    "Authentication was canceled by the system. Try again." : {
+
+    },
+    "Authentication was canceled by you." : {
 
     },
     "Authorize Trio to send notifications and use Bluetooth. You must allow both for Trio to work properly." : {
@@ -43528,6 +43552,15 @@
         }
       }
     },
+    "Biometric accessory is missing or not connected. Please reconnect it and try again." : {
+
+    },
+    "Biometric authentication is locked due to multiple failed attempts. Please unlock your device using your passcode." : {
+
+    },
+    "Biometric authentication is not available on this device." : {
+
+    },
     "Blood glucose (BG) readings" : {
       "extractionState" : "stale",
       "localizations" : {
@@ -138279,6 +138312,9 @@
         }
       }
     },
+    "No biometric identities are enrolled. Please set up Face ID or Touch ID." : {
+
+    },
     "No Bolus Data" : {
       "localizations" : {
         "bg" : {
@@ -227701,6 +227737,9 @@
         }
       }
     },
+    "You tapped the fallback option, but no fallback method is configured." : {
+
+    },
     "You will also be guided through re-configuring your algorithm settings, respecting Trio's new guardrails." : {
       "localizations" : {
         "bg" : {

+ 80 - 16
Trio/Sources/Modules/Treatments/TreatmentsStateModel.swift

@@ -458,6 +458,83 @@ extension Treatments {
             }
         }
 
+        private func parseAuthenticationError(from error: Error) -> String {
+            guard let laError = error as? LAError else {
+                return String(
+                    localized: "An unknown authentication error occurred. Please try again."
+                )
+            }
+
+            switch laError.code {
+            case .authenticationFailed:
+                return String(
+                    localized: "Authentication failed. Please try again."
+                )
+
+            case .userCancel:
+                return String(
+                    localized: "Authentication was canceled by you."
+                )
+
+            case .userFallback:
+                return String(
+                    localized: "You tapped the fallback option, but no fallback method is configured."
+                )
+
+            case .systemCancel:
+                return String(
+                    localized: "Authentication was canceled by the system. Try again."
+                )
+
+            case .appCancel:
+                return String(
+                    localized: "Authentication was canceled by the app."
+                )
+
+            case .invalidContext:
+                return String(
+                    localized: "Authentication context is invalid. Please try again."
+                )
+
+            case .notInteractive:
+                return String(
+                    localized: "Authentication UI cannot be displayed. Try restarting the app."
+                )
+
+            case .passcodeNotSet:
+                return String(
+                    localized: "Authentication requires a device passcode. Please set one in iOS Settings > Face ID & Passcode."
+                )
+
+            case .biometryNotAvailable:
+                return String(
+                    localized: "Biometric authentication is not available on this device."
+                )
+
+            case .biometryNotEnrolled:
+                return String(
+                    localized: "No biometric identities are enrolled. Please set up Face ID or Touch ID."
+                )
+
+            case .biometryLockout,
+                 .touchIDLockout:
+                return String(
+                    localized: "Biometric authentication is locked due to multiple failed attempts. Please unlock your device using your passcode."
+                )
+
+            case .biometryDisconnected,
+                 .biometryNotPaired:
+                return String(
+                    localized: "Biometric accessory is missing or not connected. Please reconnect it and try again."
+                )
+
+            default:
+                return String(
+                    localized: "An unknown biometric authentication error occurred. Please try again."
+                )
+            }
+        }
+
         func addPumpInsulin() async {
             guard amount > 0 else {
                 showModal(for: nil)
@@ -474,20 +551,14 @@ extension Treatments {
                         self.isAwaitingDeterminationResult = true
                     }
                     await apsManager.enactBolus(amount: maxAmount, isSMB: false, callback: nil)
-                } else {
-                    debug(.bolusState, "Authentication failed")
-                    throw UnlockError(error: LAError(.authenticationFailed))
                 }
             } catch {
                 debug(.bolusState, "Authentication error for pump bolus: \(error)")
+
                 await MainActor.run {
                     self.isAwaitingDeterminationResult = false
                     self.showDeterminationFailureAlert = true
-                    self
-                        .determinationFailureMessage =
-                        String(
-                            localized: "Authentication failed. Please ensure you have configured a Passcode for your iPhone under iOS Settings > Face ID & Code."
-                        )
+                    self.determinationFailureMessage = parseAuthenticationError(from: error)
                 }
             }
         }
@@ -515,20 +586,13 @@ extension Treatments {
                     await pumpHistoryStorage.storeExternalInsulinEvent(amount: amount, timestamp: date)
                     // perform determine basal sync
                     try await apsManager.determineBasalSync()
-                } else {
-                    debug(.bolusState, "Authentication failed")
-                    throw UnlockError(error: LAError(.authenticationFailed))
                 }
             } catch {
                 debug(.bolusState, "authentication error for external insulin: \(error)")
                 await MainActor.run {
                     self.isAwaitingDeterminationResult = false
                     self.showDeterminationFailureAlert = true
-                    self
-                        .determinationFailureMessage =
-                        String(
-                            localized: "Authentication failed. Please ensure you have configured a Passcode for your iPhone under iOS Settings > Face ID & Code."
-                        )
+                    self.determinationFailureMessage = parseAuthenticationError(from: error)
                 }
             }
         }

+ 1 - 5
Trio/Sources/Services/UnlockManager/UnlockManager.swift

@@ -5,10 +5,6 @@ protocol UnlockManager {
     func unlock() async throws -> Bool
 }
 
-struct UnlockError: Error {
-    let error: Error?
-}
-
 final class BaseUnlockManager: UnlockManager {
     @MainActor func unlock() async throws -> Bool {
         let context = LAContext()
@@ -18,7 +14,7 @@ final class BaseUnlockManager: UnlockManager {
             _ = try await context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason)
             return true
         } catch {
-            throw UnlockError(error: error)
+            throw error
         }
     }
 }