This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| protocol ViewModelType { | |
| associatedtype Input: InputType | |
| associatedtype Output | |
| func transform(input: Input) -> Output | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| protocol InputType { | |
| associatedtype FromView | |
| associatedtype FromController | |
| var fromView: FromView { get } | |
| var fromController: FromController { get } | |
| init(fromView: FromView, fromController: FromController) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import RxSwift | |
| import RxCocoa | |
| class BaseViewModel<NavigationStep, FromView, Output>: ViewModelType { | |
| let bag = DisposeBag() | |
| // Small type wrapping a RxSwift PublishSubject, that we notify about navigation, passing | |
| // a contextual `NavigationStep` which typically is an enum, modelling all possible | |
| // outgoing navigation steps we can take from this scene. | |
| let navigator = Stepper<NavigationStep>() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // The cases should be named as if they were prefixed with the words | |
| // "user intends to" or "user did" | |
| enum AuthenticateNavigationStep { | |
| case signIn | |
| case signUp | |
| } | |
| final class AuthenticateViewModel: BaseViewModel< | |
| AuthenticateNavigationStep, | |
| AuthenticateViewModel.InputFromView, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| private extension AuthenticationCoordinator { | |
| func toAuthentication() { | |
| let viewModel = AuthenticateViewModel() | |
| push(scene: Authenticate.self, viewModel: viewModel) { [unowned self] userIntendsTo in | |
| switch userIntendsTo { | |
| case .signUp: self.toSignIn() | |
| case .signIn: self.toSignUp() | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import RxSwift | |
| class SceneController<View>: UIViewController where View: UIView & ViewModelled { | |
| typealias ViewModel = View.ViewModel | |
| private let bag = DisposeBag() | |
| private let viewModel: ViewModel | |
| // We omit some additional "AbstractTarget" wrappers taking these `PublishSubjects` as arguments |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* This ⬇ single line ⬇ constitutes a fully working ViewController. Clean code 👌🏽 */ | |
| typealias Authenticate = SceneController<AuthenticateView> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| final class SignInView: UIView { | |
| // Some loading view, it might contain a `UIActivityIndicatorView` | |
| // it has reactive binding for `isLoading`, but starts invisible | |
| private lazy var loadingView = LoadingView() | |
| // In fact these TextFields are some subclass capable of displaying validation errors | |
| private lazy var usernameField = UITextField() | |
| private lazy var passwordField = UITextField() | |
| private lazy var confirmPasswordField = UITextField() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| protocol AuthenticationUseCase: AnyObject { | |
| func signIn(request: SignInRequest) -> Observable<Void> | |
| } | |
| struct SignInRequest { | |
| let username: String | |
| let password: String | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| enum Validation<Validated> { | |
| case valid(Validated) | |
| case invalid(errorMessage: String) | |
| var asValidated: Validated? { | |
| switch self { | |
| case .valid(let validated): return validated | |
| default: return nil | |
| } | |
| } |