Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,28 @@ RxSignInView(
)
```

**With callbacks:**

```swift
RxSignInView(
manager: authManager,
onAuthSuccess: {
// Navigate to home, fetch user data, etc.
},
onAuthFailed: { error in
// Log error, show custom alert, etc.
}
)
```

**Advanced (fully custom header with ViewBuilder):**

```swift
RxSignInView(manager: authManager) {
RxSignInView(
manager: authManager,
onAuthSuccess: { print("Signed in!") },
onAuthFailed: { error in print("Failed: \(error)") }
) {
VStack {
Image("Logo")
.resizable()
Expand Down
15 changes: 13 additions & 2 deletions Sources/RxAuthSwiftUI/RxSignInView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,38 @@ public struct RxSignInView<Header: View>: View {
@Bindable private var manager: OAuthManager
private let appearance: RxSignInAppearance
private let customHeader: Header?
private let onAuthSuccess: (() -> Void)?
private let onAuthFailed: ((Error) -> Void)?

// MARK: - Simple Init (appearance struct)

public init(
manager: OAuthManager,
appearance: RxSignInAppearance = RxSignInAppearance()
appearance: RxSignInAppearance = RxSignInAppearance(),
onAuthSuccess: (() -> Void)? = nil,
onAuthFailed: ((Error) -> Void)? = nil
) where Header == Never {
Comment on lines 13 to 18
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onAuthSuccess/onAuthFailed are stored on the view, so the corresponding initializer parameters need to be @escaping (otherwise this won’t compile under Swift’s non-escaping default). Given Swift 6 strict concurrency, also consider annotating these callback types as @MainActor/@Sendable so they can be safely captured from the Task used by the button action.

Copilot uses AI. Check for mistakes.
self.manager = manager
self.appearance = appearance
self.customHeader = nil
self.onAuthSuccess = onAuthSuccess
self.onAuthFailed = onAuthFailed
}

// MARK: - Advanced Init (ViewBuilder for custom header)

public init(
manager: OAuthManager,
appearance: RxSignInAppearance = RxSignInAppearance(),
onAuthSuccess: (() -> Void)? = nil,
onAuthFailed: ((Error) -> Void)? = nil,
@ViewBuilder header: () -> Header
Comment on lines 28 to 33
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as the simple init: onAuthSuccess/onAuthFailed are stored properties, so these parameters should be @escaping (and ideally @MainActor/@Sendable in Swift 6) to avoid compile-time escaping/sendability errors when captured by Task.

Copilot uses AI. Check for mistakes.
) {
self.manager = manager
self.appearance = appearance
self.customHeader = header()
self.onAuthSuccess = onAuthSuccess
self.onAuthFailed = onAuthFailed
}

public var body: some View {
Expand Down Expand Up @@ -65,8 +75,9 @@ public struct RxSignInView<Header: View>: View {
Task {
do {
try await manager.authenticate()
onAuthSuccess?()
} catch {
// Error is handled by the manager
onAuthFailed?(error)
}
Comment on lines 75 to 81
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Task { ... } created here is not guaranteed to run on MainActor. After await manager.authenticate() returns, execution can resume off-main, so onAuthSuccess/onAuthFailed may be invoked on a background executor (problematic for UI/navigation work). Make the task main-actor isolated (e.g., Task { @MainActor in ... }) or dispatch the callback invocations back to MainActor.

Copilot uses AI. Check for mistakes.
}
}
Expand Down