Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the reauthentication flow in FirebaseAuthSwiftUI by introducing reusable screens (EmailLinkReauthScreen, EmailReauthScreen, and PhoneReauthScreen) and default content views, alongside a new reauthContent modifier that allows developers to provide custom UI for reauthentication prompts. It also adds comprehensive unit tests for these components. The review feedback suggests replacing deprecated .foregroundColor modifiers with .foregroundStyle across the new views and refactoring EmailReauthScreen to extract error reporting into a helper method for consistency.
| Image(systemName: "envelope.open.fill") | ||
| .font(.system(size: 60)) | ||
| .foregroundColor(.accentColor) | ||
| .padding(.top, 32) |
There was a problem hiding this comment.
Use .foregroundStyle instead of the deprecated .foregroundColor modifier. In modern SwiftUI (iOS 15+), .foregroundStyle is preferred for setting the color or style of views, and .foregroundStyle(.tint) is the idiomatic way to apply the accent color.
| Image(systemName: "envelope.open.fill") | |
| .font(.system(size: 60)) | |
| .foregroundColor(.accentColor) | |
| .padding(.top, 32) | |
| Image(systemName: "envelope.open.fill") | |
| .font(.system(size: 60)) | |
| .foregroundStyle(.tint) | |
| .padding(.top, 32) |
| Image(systemName: "lock.circle.fill") | ||
| .font(.system(size: 60)) | ||
| .foregroundColor(.blue) |
There was a problem hiding this comment.
| Text(authService.string.forSecurityEnterPasswordMessage) | ||
| .font(.body) | ||
| .foregroundColor(.secondary) |
There was a problem hiding this comment.
| Image(systemName: "phone.circle.fill") | ||
| .font(.system(size: 60)) | ||
| .foregroundColor(.blue) |
There was a problem hiding this comment.
| Text(authService.string.forSecurityVerifyPhoneMessage) | ||
| .font(.body) | ||
| .foregroundColor(.secondary) |
There was a problem hiding this comment.
| private func verify() { | ||
| guard isValid, !isLoading else { return } | ||
| isLoading = true | ||
| errorMessage = nil | ||
| Task { | ||
| defer { isLoading = false } | ||
| do { | ||
| let credential = EmailAuthProvider.credential(withEmail: email, password: password) | ||
| try await authService.reauthenticate(with: credential) | ||
| coordinator.reauthCompleted() | ||
| } catch let AuthServiceError.multiFactorReauthenticationRequired(mfaRequired) { | ||
| self.mfaRequired = mfaRequired | ||
| } catch { | ||
| errorMessage = authService.string.localizedErrorMessage(for: error) | ||
| if let reportError { | ||
| reportError(error) | ||
| } else { | ||
| self.error = AlertError( | ||
| title: "Error", | ||
| message: error.localizedDescription, | ||
| underlyingError: error | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
To reduce code duplication and maintain consistency with PhoneReauthScreen and EmailLinkReauthScreen, extract the error reporting logic into a private report(_:) helper method.
private func verify() {
guard isValid, !isLoading else { return }
isLoading = true
errorMessage = nil
Task {
defer { isLoading = false }
do {
let credential = EmailAuthProvider.credential(withEmail: email, password: password)
try await authService.reauthenticate(with: credential)
coordinator.reauthCompleted()
} catch let AuthServiceError.multiFactorReauthenticationRequired(mfaRequired) {
self.mfaRequired = mfaRequired
} catch {
report(error)
}
}
}
private func report(_ error: Error) {
errorMessage = authService.string.localizedErrorMessage(for: error)
if let reportError {
reportError(error)
} else {
self.error = AlertError(
title: "Error",
message: error.localizedDescription,
underlyingError: error
)
}
}a95b367 to
c318494
Compare
Lets apps draw the password, phone and email link reauthentication prompts with their own content through one
.reauthContentmodifier. Existing views and the stock UI are unchanged.Changes
EmailReauthScreen,PhoneReauthScreenandEmailLinkReauthScreenown the reauth logic and pass a…ContentState(bindings, actions,isValid,isLoading, localizederrorMessage) to their content.DefaultEmailReauthContent,DefaultPhoneReauthContentandDefaultEmailLinkReauthContenthold the stock markup with the stack's theming (authFont,.authCTAButtonStyle()), andEmailReauthView,PhoneReauthViewandEmailLinkReauthViewnow render the screens with them..reauthContent { prompt in ... }carries the app's content through the environment, so it reaches every sheetwithReauthenticationpresents, fromSignedInViewto the MFA screens.API Usage
Preview
Deleting the account with an expired session in the e2e example app (Auth emulator): custom password prompt from the snippet above, stock phone prompt through
DefaultReauthContent, and the stock password prompt picking up a GeorgiaauthTypographyand purple tint.Maintainer note: Fixes internal CPRN-608