Permalink
e0e3445 Nov 4, 2017
@kzaher @volodg
119 lines (98 sloc) 3.95 KB
//
// GithubSignupViewModel1.swift
// RxExample
//
// Created by Krunoslav Zaher on 12/6/15.
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
//
import RxSwift
import RxCocoa
/**
This is example where view model is mutable. Some consider this to be MVVM, some consider this to be Presenter,
or some other name.
In the end, it doesn't matter.
If you want to take a look at example using "immutable VMs", take a look at `TableViewWithEditingCommands` example.
This uses vanilla rx observable sequences.
Please note that there is no explicit state, outputs are defined using inputs and dependencies.
Please note that there is no dispose bag, because no subscription is being made.
*/
class GithubSignupViewModel1 {
// outputs {
let validatedUsername: Observable<ValidationResult>
let validatedPassword: Observable<ValidationResult>
let validatedPasswordRepeated: Observable<ValidationResult>
// Is signup button enabled
let signupEnabled: Observable<Bool>
// Has user signed in
let signedIn: Observable<Bool>
// Is signing process in progress
let signingIn: Observable<Bool>
// }
init(input: (
username: Observable<String>,
password: Observable<String>,
repeatedPassword: Observable<String>,
loginTaps: Observable<Void>
),
dependency: (
API: GitHubAPI,
validationService: GitHubValidationService,
wireframe: Wireframe
)
) {
let API = dependency.API
let validationService = dependency.validationService
let wireframe = dependency.wireframe
/**
Notice how no subscribe call is being made.
Everything is just a definition.
Pure transformation of input sequences to output sequences.
*/
validatedUsername = input.username
.flatMapLatest { username in
return validationService.validateUsername(username)
.observeOn(MainScheduler.instance)
.catchErrorJustReturn(.failed(message: "Error contacting server"))
}
.share(replay: 1)
validatedPassword = input.password
.map { password in
return validationService.validatePassword(password)
}
.share(replay: 1)
validatedPasswordRepeated = Observable.combineLatest(input.password, input.repeatedPassword, resultSelector: validationService.validateRepeatedPassword)
.share(replay: 1)
let signingIn = ActivityIndicator()
self.signingIn = signingIn.asObservable()
let usernameAndPassword = Observable.combineLatest(input.username, input.password) { (username: $0, password: $1) }
signedIn = input.loginTaps.withLatestFrom(usernameAndPassword)
.flatMapLatest { pair in
return API.signup(pair.username, password: pair.password)
.observeOn(MainScheduler.instance)
.catchErrorJustReturn(false)
.trackActivity(signingIn)
}
.flatMapLatest { loggedIn -> Observable<Bool> in
let message = loggedIn ? "Mock: Signed in to GitHub." : "Mock: Sign in to GitHub failed"
return wireframe.promptFor(message, cancelAction: "OK", actions: [])
// propagate original value
.map { _ in
loggedIn
}
}
.share(replay: 1)
signupEnabled = Observable.combineLatest(
validatedUsername,
validatedPassword,
validatedPasswordRepeated,
signingIn.asObservable()
) { username, password, repeatPassword, signingIn in
username.isValid &&
password.isValid &&
repeatPassword.isValid &&
!signingIn
}
.distinctUntilChanged()
.share(replay: 1)
}
}