|
// -------------------------------------------------------------------- |
|
// *** Shared *** |
|
// -------------------------------------------------------------------- |
|
|
|
|
|
// -------------------------------------------------------------------- |
|
// View.kt |
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
Shared interactors can reference properties and methods |
|
defined in their RIB's View interface. RIBs can specialize |
|
their own View interfaces to enable specific interaction |
|
on the view layer. |
|
*/ |
|
|
|
interface View: Presenter { |
|
val isUserInteractionEnabled: Bool |
|
val isHidden: Bool |
|
val alpha: Double |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
// Result.kt |
|
// -------------------------------------------------------------------- |
|
|
|
enum class Result { |
|
SUCCESS, |
|
ERROR |
|
} |
|
|
|
interface Resultable { |
|
fun get(): Result |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
// ChangePasswordView.kt |
|
// -------------------------------------------------------------------- |
|
|
|
/** |
|
Both Android and iOS views must implement the protocol defined below |
|
in order to attach the shared ChangePassword router (possible to have |
|
compile-time guardrails around this?). |
|
*/ |
|
|
|
interface ChangePasswordPresenter: View { |
|
val passwordFieldObservable: Observable<String> |
|
val didSubmitPasswordObservable: Observable<String> |
|
val isSubmitEnabled: Bool |
|
} |
|
|
|
// -------------------------------------------------------------------- |
|
// ChangePasswordInteractor.kt |
|
// -------------------------------------------------------------------- |
|
|
|
interface ChangePasswordResult: Resultable {} |
|
|
|
@RibInteractor |
|
class ChangePasswordInteractor : Interactor<ChangePasswordPresenter, ChangePasswordRouter>() { |
|
lateinit val presenter: ChangePasswordPresenter |
|
lateinit val listener: Listener |
|
val result: ChangePasswordResult |
|
|
|
override fun didBecomeActive(savedInstanceState: Bundle?) { |
|
super.didBecomeActive(savedInstanceState) |
|
|
|
presenter.passwordFieldObservable |
|
.observeOn(mainThreadScheduler) |
|
.autoDisposable(this) |
|
.subscribe { password -> |
|
presenter.isSubmitEnabled = !password.isEmpty |
|
} |
|
|
|
presenter.didSubmitPasswordObservable |
|
.observeOn(mainThreadScheduler) |
|
.autoDisposable(this) |
|
.subscribe { password -> |
|
presenter.isUserInteractionEnabled = false |
|
// This `get:` is like an `expect`, |
|
// with the `actual` constructed by |
|
// each platform to perform the pw |
|
// change request, and return the |
|
// corresponding `Result` value. |
|
this.result.get() { result -> |
|
presenter.isUserInteractionEnabled = true |
|
listener.changePasswordDidResult(result) |
|
} |
|
} |
|
} |
|
|
|
interface Listener { |
|
fun changePasswordDidResult(result: Result) |
|
} |
|
} |
|
|
|
|
|
|
|
// -------------------------------------------------------------------- |
|
// *** iOS *** |
|
// -------------------------------------------------------------------- |
|
|
|
|
|
|
|
// -------------------------------------------------------------------- |
|
// ChangePasswordViewController.swift |
|
// -------------------------------------------------------------------- |
|
|
|
import ChangePasswordShared |
|
import RxCocoa |
|
import RxSwift |
|
import UIKit |
|
|
|
final class ChangePasswordViewController: UIViewController, View { |
|
lazy var passwordFieldObservable: Observable<String> = passwordField.rx.text.asObservable() |
|
lazy var didSubmitObservable: Observable<Void> = submitButton.rx.tap |
|
|
|
var isSubmitEnabled: Bool { |
|
get { return submitButton.isEnabled } |
|
set { submitButton.isEnabled = newValue } |
|
} |
|
|
|
private let submitButton = UIButton() |
|
private let passwordField = UITextField() |
|
|
|
// etc. |
|
} |