diff --git a/LoopFollow/Helpers/AuthService.swift b/LoopFollow/Helpers/AuthService.swift index c00b1db9b..d065054c8 100644 --- a/LoopFollow/Helpers/AuthService.swift +++ b/LoopFollow/Helpers/AuthService.swift @@ -7,7 +7,7 @@ import LocalAuthentication public enum AuthResult { case success case canceled - case unavailable + case unavailable(String) case failed } @@ -29,7 +29,20 @@ public enum AuthService { var error: NSError? guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else { - completion(.unavailable) + var message = "Device authentication is not available. " + + let biometryType = context.biometryType + if biometryType == .none { + message += "Please enable Face ID, Touch ID, or set up a device passcode in Settings." + } else if biometryType == .faceID { + message += "Face ID is not available. Please set up a device passcode in Settings." + } else if biometryType == .touchID { + message += "Touch ID is not available. Please set up a device passcode in Settings." + } + + DispatchQueue.main.async { + completion(.unavailable(message)) + } return } diff --git a/LoopFollow/Remote/LoopAPNS/LoopAPNSBolusView.swift b/LoopFollow/Remote/LoopAPNS/LoopAPNSBolusView.swift index d3ae79c9e..011fe0e10 100644 --- a/LoopFollow/Remote/LoopAPNS/LoopAPNSBolusView.swift +++ b/LoopFollow/Remote/LoopAPNS/LoopAPNSBolusView.swift @@ -326,20 +326,22 @@ struct LoopAPNSBolusView: View { private func authenticateAndSendInsulin() { AuthService.authenticate(reason: "Confirm your identity to send insulin.") { result in - switch result { - case .success: - sendInsulinConfirmed() - case .unavailable: - alertMessage = "Authentication not available" - alertType = .error - showAlert = true - case .failed: - alertMessage = "Authentication failed" - alertType = .error - showAlert = true - case .canceled: - // User canceled: no alert to avoid spammy UX - break + DispatchQueue.main.async { + switch result { + case .success: + self.sendInsulinConfirmed() + case let .unavailable(message): + self.alertMessage = message + self.alertType = .error + self.showAlert = true + case .failed: + self.alertMessage = "Authentication failed" + self.alertType = .error + self.showAlert = true + case .canceled: + // User canceled: no alert to avoid spammy UX + break + } } } } diff --git a/LoopFollow/Remote/TRC/BolusView.swift b/LoopFollow/Remote/TRC/BolusView.swift index 0a70f86b9..30bfab213 100644 --- a/LoopFollow/Remote/TRC/BolusView.swift +++ b/LoopFollow/Remote/TRC/BolusView.swift @@ -113,8 +113,22 @@ struct BolusView: View { message: Text("Are you sure you want to send \(InsulinFormatter.shared.string(bolusAmount)) U?"), primaryButton: .default(Text("Confirm"), action: { AuthService.authenticate(reason: "Confirm your identity to send bolus.") { result in - if case .success = result { - sendBolus() + DispatchQueue.main.async { + switch result { + case .success: + self.sendBolus() + case let .unavailable(message): + self.alertMessage = message + self.alertType = .validation + self.showAlert = true + case .failed: + self.alertMessage = "Authentication failed" + self.alertType = .validation + self.showAlert = true + case .canceled: + // User canceled, no alert + break + } } } }), diff --git a/LoopFollow/Remote/TRC/MealView.swift b/LoopFollow/Remote/TRC/MealView.swift index 517db1811..4c5e27df6 100644 --- a/LoopFollow/Remote/TRC/MealView.swift +++ b/LoopFollow/Remote/TRC/MealView.swift @@ -196,12 +196,26 @@ struct MealView: View { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { if bolusAmount > 0 { AuthService.authenticate(reason: "Confirm your identity to send bolus.") { result in - if case .success = result { - sendMealCommand() + DispatchQueue.main.async { + switch result { + case .success: + self.sendMealCommand() + case let .unavailable(message): + self.alertMessage = message + self.alertType = .validationError + self.showAlert = true + case .failed: + self.alertMessage = "Authentication failed" + self.alertType = .validationError + self.showAlert = true + case .canceled: + // User canceled, no alert + break + } } } } else { - sendMealCommand() + self.sendMealCommand() } } }),