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
28 changes: 28 additions & 0 deletions rxpm/src/main/kotlin/me/dmdev/rxpm/PmExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,27 @@ inline fun Completable.bindProgress(progressConsumer: Consumer<Boolean>): Comple
.doFinally { progressConsumer.accept(false) }
}

/**
* Convenience to bind the [progress][state] to the [Single].
*/
fun <T> Single<T>.bindProgress(state: State<Boolean>): Single<T> {
return this.bindProgress(state.relay)
}

/**
* Convenience to bind the [progress][state] to the [Maybe].
*/
fun <T> Maybe<T>.bindProgress(state: State<Boolean>): Maybe<T> {
return this.bindProgress(state.relay)
}

/**
* Convenience to bind the [progress][state] to the [Completable].
*/
fun Completable.bindProgress(state: State<Boolean>): Completable {
return this.bindProgress(state.relay)
}

/**
* Convenience to filter out items emitted by the source [Observable] when in progress ([progressState] last value is `true`).
*/
Expand All @@ -67,6 +88,13 @@ inline fun <T> Observable<T>.skipWhileInProgress(progressState: Observable<Boole
.map { (item, _) -> item }
}

/**
* Convenience to filter out items emitted by the source [Observable] when in progress ([state] last value is `true`).
*/
fun <T> Observable<T>.skipWhileInProgress(state: State<Boolean>): Observable<T> {
return this.skipWhileInProgress(state.observable)
}

/**
* Returns the [Observable] that emits items when active, and buffers them when [idle][isIdle].
* Buffered items is emitted when idle state ends.
Expand Down
98 changes: 98 additions & 0 deletions rxpm/src/main/kotlin/me/dmdev/rxpm/PresentationModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ abstract class PresentationModel {
*/
protected val <T> State<T>.consumer: Consumer<T> get() = relay

/**
* Accept the given [value] by the [State].
*/
protected fun <T> State<T>.accept(value: T) = relay.accept(value)

/**
* Observable of the [Action].
* Accessible only from a [PresentationModel].
Expand All @@ -246,6 +251,11 @@ abstract class PresentationModel {
*/
protected val <T> Action<T>.observable: Observable<T> get() = relay

/**
* Accept the given [value] by the [Action].
*/
protected fun <T> Action<T>.accept(value: T) = relay.accept(value)

/**
* Consumer of the [Command].
* Accessible only from a [PresentationModel].
Expand All @@ -254,5 +264,93 @@ abstract class PresentationModel {
*/
protected val <T> Command<T>.consumer: Consumer<T> get() = relay

/**
* Accept the given [value] to the [Command].
*/
protected fun <T> Command<T>.accept(value: T) = relay.accept(value)

/**
* Convenience to subscribe [state] to the [Observable].
*/
protected fun <T> Observable<T>.subscribe(state: State<T>): Disposable {
return this.subscribe(state.relay)
}

/**
* Convenience to subscribe [state] to the [Single].
*/
protected fun <T> Single<T>.subscribe(state: State<T>): Disposable {
return this.subscribe(state.relay)
}

/**
* Convenience to subscribe [state] to the [Flowable].
*/
protected fun <T> Flowable<T>.subscribe(state: State<T>): Disposable {
return this.subscribe(state.relay)
}

/**
* Convenience to subscribe [state] to the [Maybe].
*/
protected fun <T> Maybe<T>.subscribe(state: State<T>): Disposable {
return this.subscribe(state.relay)
}

/**
* Convenience to subscribe [action] to the [Observable].
*/
protected fun <T> Observable<T>.subscribe(action: Action<T>): Disposable {
return this.subscribe(action.relay)
}

/**
* Convenience to subscribe [action] to the [Single].
*/
protected fun <T> Single<T>.subscribe(action: Action<T>): Disposable {
return this.subscribe(action.relay)
}

/**
* Convenience to subscribe [action] to the [Flowable].
*/
protected fun <T> Flowable<T>.subscribe(action: Action<T>): Disposable {
return this.subscribe(action.relay)
}

/**
* Convenience to subscribe [action] to the [Maybe].
*/
protected fun <T> Maybe<T>.subscribe(action: Action<T>): Disposable {
return this.subscribe(action.relay)
}

/**
* Convenience to subscribe [command] to the [Observable].
*/
protected fun <T> Observable<T>.subscribe(command: Command<T>): Disposable {
return this.subscribe(command.relay)
}

/**
* Convenience to subscribe [command] to the [Single].
*/
protected fun <T> Single<T>.subscribe(command: Command<T>): Disposable {
return this.subscribe(command.relay)
}

/**
* Convenience to subscribe [command] to the [Flowable].
*/
protected fun <T> Flowable<T>.subscribe(command: Command<T>): Disposable {
return this.subscribe(command.relay)
}

/**
* Convenience to subscribe [command] to the [Maybe].
*/
protected fun <T> Maybe<T>.subscribe(command: Command<T>): Disposable {
return this.subscribe(command.relay)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.view.*
import androidx.appcompat.app.*
import io.reactivex.functions.*
import me.dmdev.rxpm.base.*
import me.dmdev.rxpm.passTo
import me.dmdev.rxpm.sample.*
import me.dmdev.rxpm.sample.main.extensions.*
import me.dmdev.rxpm.widget.*
Expand Down Expand Up @@ -34,7 +35,7 @@ abstract class Screen<PM : ScreenPresentationModel> :
}

override fun handleBack(): Boolean {
presentationModel.backAction.consumer.accept(Unit)
Unit passTo presentationModel.backAction
return true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ abstract class ScreenPresentationModel : PresentationModel(),
}

protected fun sendMessage(message: NavigationMessage) {
navigationMessages.consumer.accept(message)
navigationMessages.accept(message)
}

protected fun showError(errorMessage: String?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ class CodeConfirmationPm(
.distinctUntilChanged()

Observable.merge(sendAction.observable, codeFilledAction)
.skipWhileInProgress(inProgress.observable)
.skipWhileInProgress(inProgress)
.map { code.text.value }
.filter { validateForm() }
.switchMapCompletable { code ->
authModel.sendConfirmationCode(phone, code)
.bindProgress(inProgress.consumer)
.bindProgress(inProgress)
.doOnComplete { sendMessage(PhoneConfirmedMessage()) }
.doOnError { showError(it.message) }
}
Expand All @@ -50,7 +50,7 @@ class CodeConfirmationPm(

code.text.observable
.map { it.length == CODE_LENGTH }
.subscribe(sendButtonEnabled.consumer)
.subscribe(sendButtonEnabled)
.untilDestroy()

}
Expand All @@ -59,11 +59,11 @@ class CodeConfirmationPm(

return when {
code.text.value.isEmpty() -> {
code.error.consumer.accept(resourceProvider.getString(R.string.enter_confirmation_code))
code.error.accept(resourceProvider.getString(R.string.enter_confirmation_code))
false
}
code.text.value.length < CODE_LENGTH -> {
code.error.consumer.accept(resourceProvider.getString(R.string.invalid_confirmation_code))
code.error.accept(resourceProvider.getString(R.string.invalid_confirmation_code))
false
}
else -> true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,25 @@ class ChooseCountryPm(private val phoneUtil: PhoneUtil) : ScreenPresentationMode

openSearchAction.observable
.map { SEARCH_OPENED }
.subscribe(mode.consumer)
.subscribe(mode)
.untilDestroy()

clearAction.observable
.subscribe {
if (searchQueryInput.text.value.isEmpty()) {
mode.consumer.accept(SEARCH_CLOSED)
mode.accept(SEARCH_CLOSED)
} else {
searchQueryInput.text.consumer.accept("")
searchQueryInput.text.accept("")
}
}
.untilDestroy()

backAction.observable
.subscribe {
if (mode.value == SEARCH_OPENED) {
mode.consumer.accept(SEARCH_CLOSED)
mode.accept(SEARCH_CLOSED)
} else {
super.backAction.consumer.accept(Unit)
super.backAction.accept(Unit)
}
}
.untilDestroy()
Expand All @@ -61,7 +61,7 @@ class ChooseCountryPm(private val phoneUtil: PhoneUtil) : ScreenPresentationMode
compareValues(c1.name.toLowerCase(), c2.name.toLowerCase())
})
}
.subscribe(countries.consumer)
.subscribe(countries)
.untilDestroy()

countryClicks.observable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import me.dmdev.rxpm.widget.*
class ChooseCountryScreen : Screen<ChooseCountryPm>() {

private val countriesAdapter = CountriesAdapter(null) { country ->
presentationModel.countryClicks.consumer.accept(country)
country passTo presentationModel.countryClicks
}

override val screenLayout = R.layout.screen_choose_country
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ class MainPm(private val authModel: AuthModel) : ScreenPresentationModel() {
super.onCreate()

logoutAction.observable
.skipWhileInProgress(inProgress.observable)
.skipWhileInProgress(inProgress)
.switchMapMaybe {
logoutDialog.showForResult(Unit)
.filter { it == DialogResult.Ok }
}
.switchMapCompletable {
authModel.logout()
.bindProgress(inProgress.consumer)
.bindProgress(inProgress)
.doOnError { showError(it.message) }
.doOnComplete { sendMessage(LogoutCompletedMessage()) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class AuthByPhonePm(
if (code.length > 5) {
try {
val number = phoneUtil.parsePhone(code)
phoneNumberFocus.consumer.accept(Unit)
phoneNumber.textChanges.consumer.accept(number.nationalNumber.toString())
phoneNumberFocus.accept(Unit)
phoneNumber.textChanges.accept(number.nationalNumber.toString())
"+${number.countryCode}"
} catch (e: NumberParseException) {
code
Expand Down Expand Up @@ -59,22 +59,22 @@ class AuthByPhonePm(
Country.UNKNOWN
}
}
.subscribe(chosenCountry.consumer)
.subscribe(chosenCountry)
.untilDestroy()

Observable.combineLatest(phoneNumber.textChanges.observable, chosenCountry.observable,
BiFunction { number: String, country: Country ->
phoneUtil.formatPhoneNumber(country, number)
})
.subscribe(phoneNumber.text.consumer)
.subscribe(phoneNumber.text)
.untilDestroy()


Observable.combineLatest(phoneNumber.textChanges.observable, chosenCountry.observable,
BiFunction { number: String, country: Country ->
phoneUtil.isValidPhone(country, number)
})
.subscribe(sendButtonEnabled.consumer)
.subscribe(sendButtonEnabled)
.untilDestroy()

countryClicks.observable
Expand All @@ -85,19 +85,19 @@ class AuthByPhonePm(

chooseCountryAction.observable
.subscribe {
countryCode.textChanges.consumer.accept("+${it.countryCallingCode}")
chosenCountry.consumer.accept(it)
phoneNumberFocus.consumer.accept(Unit)
countryCode.textChanges.accept("+${it.countryCallingCode}")
chosenCountry.accept(it)
phoneNumberFocus.accept(Unit)
}
.untilDestroy()

sendAction.observable
.skipWhileInProgress(inProgress.observable)
.skipWhileInProgress(inProgress)
.filter { validateForm() }
.map { "${countryCode.text.value} ${phoneNumber.text.value}" }
.switchMapCompletable { phone ->
authModel.sendPhone(phone)
.bindProgress(inProgress.consumer)
.bindProgress(inProgress)
.doOnComplete {
sendMessage(PhoneSentSuccessfullyMessage(phone))
}
Expand All @@ -111,10 +111,10 @@ class AuthByPhonePm(
private fun validateForm(): Boolean {

return if (phoneNumber.text.value.isEmpty()) {
phoneNumber.error.consumer.accept(resourceProvider.getString(R.string.enter_phone_number))
phoneNumber.error.accept(resourceProvider.getString(R.string.enter_phone_number))
false
} else if (!phoneUtil.isValidPhone(chosenCountry.value, phoneNumber.text.value)) {
phoneNumber.error.consumer.accept(resourceProvider.getString(R.string.invalid_phone_number))
phoneNumber.error.accept(resourceProvider.getString(R.string.invalid_phone_number))
false
} else {
true
Expand Down