Skip to content

Commit 945bf05

Browse files
Merge branch 'development' into fix-closure
2 parents 03ec0a1 + 354f734 commit 945bf05

File tree

30 files changed

+289
-156
lines changed

30 files changed

+289
-156
lines changed

.github/workflows/swiftui-auth.yml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ permissions:
2424
contents: read
2525

2626
jobs:
27+
format-check:
28+
name: Swift Format Check
29+
runs-on: macos-26
30+
timeout-minutes: 10
31+
steps:
32+
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
33+
34+
- name: Install swiftformat
35+
run: brew install swiftformat
36+
37+
- name: Check Swift formatting
38+
run: bash lint-swift.sh
39+
2740
# Package Unit Tests (standalone, no emulator needed)
2841
unit-tests:
2942
name: Package Unit Tests
@@ -176,8 +189,7 @@ jobs:
176189
xcodebuild test-without-building \
177190
-scheme FirebaseSwiftUIExampleUITests \
178191
-destination 'platform=iOS Simulator,name=iPhone 17' \
179-
-parallel-testing-enabled YES \
180-
-maximum-concurrent-test-simulator-destinations 2 \
192+
-parallel-testing-enabled NO \
181193
-enableCodeCoverage YES \
182194
-resultBundlePath FirebaseSwiftUIExampleUITests.xcresult | tee FirebaseSwiftUIExampleUITests.log | xcpretty --test --color --simple
183195
@@ -193,4 +205,4 @@ jobs:
193205
uses: actions/upload-artifact@v4
194206
with:
195207
name: FirebaseSwiftUIExampleUITests.xcresult
196-
path: e2eTest/FirebaseSwiftUIExample/FirebaseSwiftUIExampleUITests.xcresult
208+
path: e2eTest/FirebaseSwiftUIExample/FirebaseSwiftUIExampleUITests.xcresult

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/AuthPickerView.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public struct AuthPickerView<Content: View> {
3333
extension AuthPickerView: View {
3434
public var body: some View {
3535
@Bindable var authService = authService
36+
@Bindable var passwordPrompt = authService.passwordPrompt
3637
content()
3738
.sheet(isPresented: $authService.isPresented) {
3839
@Bindable var navigator = authService.navigator
@@ -79,6 +80,10 @@ extension AuthPickerView: View {
7980
// Apply MFA handling at NavigationStack level
8081
.mfaHandler()
8182
}
83+
// Centralized password prompt sheet to prevent conflicts
84+
.sheet(isPresented: $passwordPrompt.isPromptingPassword) {
85+
PasswordPromptSheet(coordinator: authService.passwordPrompt)
86+
}
8287
}
8388

8489
/// Closure for reporting errors from child views
@@ -156,7 +161,7 @@ extension AuthPickerView: View {
156161
VStack {
157162
authService.renderButtons()
158163
}
159-
.padding(.horizontal, proxy.size.width * 0.18)
164+
.padding(.horizontal, proxy.size.width * 0.14)
160165
}
161166
}
162167

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EmailAuthView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ extension EmailAuthView: View {
111111
keyboardType: .emailAddress,
112112
contentType: .emailAddress,
113113
validations: [
114-
FormValidators.email
114+
FormValidators.email,
115115
],
116116
maintainsValidationMessage: authService.authenticationFlow == .signUp,
117117
onSubmit: { _ in
@@ -161,7 +161,7 @@ extension EmailAuthView: View {
161161
contentType: .password,
162162
isSecureTextField: true,
163163
validations: [
164-
FormValidators.confirmPassword(password: password)
164+
FormValidators.confirmPassword(password: password),
165165
],
166166
maintainsValidationMessage: true,
167167
onSubmit: { _ in

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EmailLinkView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ extension EmailLinkView: View {
5050
keyboardType: .emailAddress,
5151
contentType: .emailAddress,
5252
validations: [
53-
FormValidators.email
53+
FormValidators.email,
5454
],
5555
leading: {
5656
Image(systemName: "at")

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EnterPhoneNumberView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ struct EnterPhoneNumberView: View {
3939
keyboardType: .phonePad,
4040
contentType: .telephoneNumber,
4141
validations: [
42-
FormValidators.phoneNumber
42+
FormValidators.phoneNumber,
4343
],
4444
onChange: { _ in }
4545
) {

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EnterVerificationCodeView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ struct EnterVerificationCodeView: View {
5252
VerificationCodeInputField(
5353
code: $verificationCode,
5454
validations: [
55-
FormValidators.verificationCode
55+
FormValidators.verificationCode,
5656
],
5757
maintainsValidationMessage: true
5858
)
@@ -106,7 +106,7 @@ struct EnterVerificationCodeView: View {
106106
return NavigationStack {
107107
EnterVerificationCodeView(
108108
verificationID: "mock-id",
109-
fullPhoneNumber: "+1 5551234567",
109+
fullPhoneNumber: "+1 5551234567"
110110
)
111111
.environment(AuthService())
112112
}

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/MFAEnrolmentView.swift

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ private enum FocusableField: Hashable {
2626
@MainActor
2727
public struct MFAEnrolmentView {
2828
@Environment(AuthService.self) private var authService
29+
@Environment(\.reportError) private var reportError
2930

3031
@State private var selectedFactorType: SecondFactorType = .sms
3132
@State private var phoneNumber = ""
@@ -81,12 +82,16 @@ public struct MFAEnrolmentView {
8182
isLoading = true
8283
defer { isLoading = false }
8384

84-
let session = try await authService.startMfaEnrollment(
85-
type: selectedFactorType,
86-
accountName: authService.currentUser?.email,
87-
issuer: authService.configuration.mfaIssuer
88-
)
89-
currentSession = session
85+
do {
86+
let session = try await authService.startMfaEnrollment(
87+
type: selectedFactorType,
88+
accountName: authService.currentUser?.email,
89+
issuer: authService.configuration.mfaIssuer
90+
)
91+
currentSession = session
92+
} catch {
93+
reportError?(error)
94+
}
9095
}
9196
}
9297

@@ -97,23 +102,27 @@ public struct MFAEnrolmentView {
97102
isLoading = true
98103
defer { isLoading = false }
99104

100-
let fullPhoneNumber = selectedCountry.dialCode + phoneNumber
101-
let verificationId = try await authService.sendSmsVerificationForEnrollment(
102-
session: session,
103-
phoneNumber: fullPhoneNumber
104-
)
105-
// Update session status
106-
currentSession = EnrollmentSession(
107-
id: session.id,
108-
type: session.type,
109-
session: session.session,
110-
totpInfo: session.totpInfo,
111-
phoneNumber: fullPhoneNumber,
112-
verificationId: verificationId,
113-
status: .verificationSent,
114-
createdAt: session.createdAt,
115-
expiresAt: session.expiresAt
116-
)
105+
do {
106+
let fullPhoneNumber = selectedCountry.dialCode + phoneNumber
107+
let verificationId = try await authService.sendSmsVerificationForEnrollment(
108+
session: session,
109+
phoneNumber: fullPhoneNumber
110+
)
111+
// Update session status
112+
currentSession = EnrollmentSession(
113+
id: session.id,
114+
type: session.type,
115+
session: session.session,
116+
totpInfo: session.totpInfo,
117+
phoneNumber: fullPhoneNumber,
118+
verificationId: verificationId,
119+
status: .verificationSent,
120+
createdAt: session.createdAt,
121+
expiresAt: session.expiresAt
122+
)
123+
} catch {
124+
reportError?(error)
125+
}
117126
}
118127
}
119128

@@ -124,18 +133,22 @@ public struct MFAEnrolmentView {
124133
isLoading = true
125134
defer { isLoading = false }
126135

127-
let code = session.type == .sms ? verificationCode : totpCode
128-
try await authService.completeEnrollment(
129-
session: session,
130-
verificationId: session.verificationId,
131-
verificationCode: code,
132-
displayName: displayName
133-
)
134-
135-
// Reset form state on success
136-
resetForm()
137-
138-
authService.navigator.clear()
136+
do {
137+
let code = session.type == .sms ? verificationCode : totpCode
138+
try await authService.completeEnrollment(
139+
session: session,
140+
verificationId: session.verificationId,
141+
verificationCode: code,
142+
displayName: displayName
143+
)
144+
145+
// Reset form state on success
146+
resetForm()
147+
148+
authService.navigator.clear()
149+
} catch {
150+
reportError?(error)
151+
}
139152
}
140153
}
141154

@@ -375,7 +388,7 @@ extension MFAEnrolmentView: View {
375388
keyboardType: .phonePad,
376389
contentType: .telephoneNumber,
377390
validations: [
378-
FormValidators.phoneNumber
391+
FormValidators.phoneNumber,
379392
],
380393
maintainsValidationMessage: true,
381394
onChange: { _ in }
@@ -393,7 +406,7 @@ extension MFAEnrolmentView: View {
393406
label: authService.string.displayNameFieldLabel,
394407
prompt: authService.string.enterDisplayNameForDevicePrompt,
395408
validations: [
396-
FormValidators.notEmpty(label: "Display name")
409+
FormValidators.notEmpty(label: "Display name"),
397410
],
398411
maintainsValidationMessage: true,
399412
leading: {
@@ -441,7 +454,7 @@ extension MFAEnrolmentView: View {
441454
VerificationCodeInputField(
442455
code: $verificationCode,
443456
validations: [
444-
FormValidators.verificationCode
457+
FormValidators.verificationCode,
445458
],
446459
maintainsValidationMessage: true
447460
)
@@ -584,7 +597,7 @@ extension MFAEnrolmentView: View {
584597
label: authService.string.displayNameFieldLabel,
585598
prompt: authService.string.enterDisplayNameForAuthenticatorPrompt,
586599
validations: [
587-
FormValidators.notEmpty(label: "Display name")
600+
FormValidators.notEmpty(label: "Display name"),
588601
],
589602
maintainsValidationMessage: true,
590603
leading: {
@@ -596,7 +609,7 @@ extension MFAEnrolmentView: View {
596609
VerificationCodeInputField(
597610
code: $totpCode,
598611
validations: [
599-
FormValidators.verificationCode
612+
FormValidators.verificationCode,
600613
],
601614
maintainsValidationMessage: true
602615
)

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/MFAManagementView.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ extension MultiFactorInfo: Identifiable {
2323
@MainActor
2424
public struct MFAManagementView {
2525
@Environment(AuthService.self) private var authService
26+
@Environment(\.reportError) private var reportError
2627

2728
@State private var enrolledFactors: [MultiFactorInfo] = []
2829
@State private var isLoading = false
@@ -43,6 +44,7 @@ public struct MFAManagementView {
4344
enrolledFactors = freshFactors
4445
isLoading = false
4546
} catch {
47+
reportError?(error)
4648
isLoading = false
4749
}
4850
}
@@ -55,7 +57,6 @@ public struct MFAManagementView {
5557

5658
extension MFAManagementView: View {
5759
public var body: some View {
58-
@Bindable var passwordPrompt = authService.passwordPrompt
5960
VStack(spacing: 20) {
6061
// Title section
6162
VStack {
@@ -133,10 +134,7 @@ extension MFAManagementView: View {
133134
.onAppear {
134135
loadEnrolledFactors()
135136
}
136-
// Present password prompt when required for reauthentication
137-
.sheet(isPresented: $passwordPrompt.isPromptingPassword) {
138-
PasswordPromptSheet(coordinator: authService.passwordPrompt)
139-
}
137+
// Password prompt sheet now centralized in AuthPickerView
140138
}
141139

142140
@ViewBuilder

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/MFAResolutionView.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ private enum FocusableField: Hashable {
2424
@MainActor
2525
public struct MFAResolutionView {
2626
@Environment(AuthService.self) private var authService
27+
@Environment(\.reportError) private var reportError
2728

2829
@State private var verificationCode = ""
2930
@State private var totpCode = ""
@@ -72,6 +73,7 @@ public struct MFAResolutionView {
7273
self.verificationId = verificationId
7374
isLoading = false
7475
} catch {
76+
reportError?(error)
7577
isLoading = false
7678
}
7779
}
@@ -93,6 +95,7 @@ public struct MFAResolutionView {
9395
authService.navigator.clear()
9496
isLoading = false
9597
} catch {
98+
reportError?(error)
9699
isLoading = false
97100
}
98101
}

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/PasswordRecoveryView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extension PasswordRecoveryView: View {
4545
keyboardType: .emailAddress,
4646
contentType: .emailAddress,
4747
validations: [
48-
FormValidators.email
48+
FormValidators.email,
4949
],
5050
leading: {
5151
Image(systemName: "at")

0 commit comments

Comments
 (0)