I'm pretty new in Combine, I'm trying to create a login flow where:
- When I click on the login button the app fires the GoogleSignIn
signfunction - Then, when the session data is received on GoogleDelegate it needs to start a request to my server-side login method.
To do that I have a GoogleSignInController that controls the sign-in process:
class GoogleSignInController: GIDSignInDelegate {
@Published var onSessionAcquired: GoogleSignInSessionData = ("", "")
func signIn() {
if (GIDSignIn.sharedInstance()?.presentingViewController == nil) {
GIDSignIn.sharedInstance()?.presentingViewController = UIApplication.shared.windows.last?.rootViewController
}
GIDSignIn.sharedInstance()?.signIn()
}
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let error = error {
if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
print("The user has not signed in")
} else {
print("\(error.localizedDescription)")
}
return
}
onSessionAcquired = GoogleSignInSessionData(idToken: user.authentication.idToken ?? "", serverAuthCode: user.serverAuthCode ?? "")
print("Successful sign-in!")
signedIn = true
}
}
Then in the ViewModel, I'm using some states to control the process:
static func whenStartedLogin() -> Feedback<State, Event> {
Feedback { (state: State) -> AnyPublisher<Event, Never> in
guard case .loadingGoogleSignIn = state else { return Empty().eraseToAnyPublisher() }
GoogleSignInController.shared.signIn()
return GoogleSignInController.shared.$onSessionAcquired
.receive(on: DispatchQueue.main)
.map { Event.onGoogleSessionAcquired($0) }
.eraseToAnyPublisher()
}
}
static func whenReceivedGoogleSession() -> Feedback<State, Event> {
Feedback { (state: State) -> AnyPublisher<Event, Never> in
guard case let .loadingServerSession(googleSession) = state else { return Empty().eraseToAnyPublisher() }
return self.signIn(idToken: googleSession.idToken, serverAuthCode: googleSession.serverAuthCode)
.map { (userInfo, error) in
if let error = error {
return Event.onFailedToAcquireSession(error)
} else if let userInfo = userInfo {
return Event.onUserInfoAcquired(userInfo)
} else {
return Event.onFailedToAcquireSession(AppError.unknown)
}
}
.eraseToAnyPublisher()
}
}
The problem is: when I click on the login button, the whenStatedLogin function is fired, and it maps my event to be Event.onGoogleSessionAcquired. This should be mapped only when onSessionAcquired is changed (after the sign delegate is called). How can I do that?