Skip to content

Commit

Permalink
add ConfirmationEvent
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex committed Dec 8, 2021
1 parent e52981b commit 2653d21
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 5 deletions.
2 changes: 1 addition & 1 deletion reactiveviewmodel/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ afterEvaluate {
release(MavenPublication) {
from components.release
groupId = 'com.alexdeww.reactiveviewmodel'
version = '2.3.8'
version = '2.3.9'
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.alexdeww.reactiveviewmodel.core
import androidx.lifecycle.ViewModel
import com.alexdeww.reactiveviewmodel.core.common.RvmComponent
import com.alexdeww.reactiveviewmodel.core.property.Action
import com.alexdeww.reactiveviewmodel.core.property.ConfirmationEvent
import com.alexdeww.reactiveviewmodel.core.property.Event
import com.alexdeww.reactiveviewmodel.core.property.State
import io.reactivex.rxjava3.disposables.CompositeDisposable
Expand Down Expand Up @@ -36,6 +37,12 @@ abstract class ReactiveViewModel : ViewModel(), RvmComponent {
protected fun eventNone(debounceInterval: Long? = null): Event<Unit> =
Event(debounceInterval)

protected fun <T : Any> confirmationEvent(debounceInterval: Long? = null): ConfirmationEvent<T> =
ConfirmationEvent(debounceInterval)

protected fun confirmationEventNone(debounceInterval: Long? = null): ConfirmationEvent<Unit> =
ConfirmationEvent(debounceInterval)

protected fun <T : Any> action(debounceInterval: Long? = null): Action<T> =
Action(debounceInterval)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import com.alexdeww.reactiveviewmodel.core.property.Action
import com.alexdeww.reactiveviewmodel.core.property.ConfirmationEvent
import com.alexdeww.reactiveviewmodel.core.property.Event
import com.alexdeww.reactiveviewmodel.core.property.State
import io.reactivex.rxjava3.core.*
Expand All @@ -19,11 +20,20 @@ fun <T> LiveData<T>.observe(owner: LifecycleOwner, action: OnLiveDataAction<T>):
return observer
}

fun <T : Any> Event<T>.observe(owner: LifecycleOwner, action: OnLiveDataAction<T>): Observer<T> =
liveData.observe(owner = owner, action = action)
fun <T : Any> Event<T>.observe(
owner: LifecycleOwner,
action: OnLiveDataAction<T>
): Observer<T> = liveData.observe(owner = owner, action = action)

fun <T : Any> State<T>.observe(owner: LifecycleOwner, action: OnLiveDataAction<T>): Observer<T> =
liveData.observe(owner = owner, action = action)
fun <T : Any> ConfirmationEvent<T>.observe(
owner: LifecycleOwner,
action: OnLiveDataAction<T>
): Observer<T> = liveData.observe(owner = owner, action = action)

fun <T : Any> State<T>.observe(
owner: LifecycleOwner,
action: OnLiveDataAction<T>
): Observer<T> = liveData.observe(owner = owner, action = action)

fun Action<Unit>.call() = call(Unit)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.widget.RatingBar
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import com.alexdeww.reactiveviewmodel.core.property.ConfirmationEvent
import com.alexdeww.reactiveviewmodel.core.property.Event
import com.alexdeww.reactiveviewmodel.core.property.State
import com.alexdeww.reactiveviewmodel.widget.*
Expand All @@ -31,6 +32,9 @@ interface RvmViewComponent {
fun <T : Any> Event<T>.observe(action: OnLiveDataAction<T>): Observer<T> =
observe(componentLifecycleOwner, action)

fun <T : Any> ConfirmationEvent<T>.observe(action: OnLiveDataAction<T>): Observer<T> =
observe(componentLifecycleOwner, action)

fun <T : Any> DisplayableControl<T>.observe(
action: DisplayableAction<T>
): Observer<DisplayableControl.Action<T>> = this@observe.action.observe {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.alexdeww.reactiveviewmodel.core.common

import com.alexdeww.reactiveviewmodel.core.property.Action
import com.alexdeww.reactiveviewmodel.core.property.ConfirmationEvent
import com.alexdeww.reactiveviewmodel.core.property.Event
import com.alexdeww.reactiveviewmodel.core.property.State
import io.reactivex.rxjava3.core.Observable
Expand Down Expand Up @@ -30,4 +31,12 @@ interface RvmComponent {

val <T : Any> Event<T>.observable: Observable<T> get() = this.observable

fun <T : Any> ConfirmationEvent<T>.call(value: T) = this.consumer.accept(value)

fun ConfirmationEvent<Unit>.call() = this.consumer.accept(Unit)

val <T : Any> ConfirmationEvent<T>.consumer: Consumer<T> get() = this.consumer

val <T : Any> ConfirmationEvent<T>.observable: Observable<T> get() = this.observable

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.alexdeww.reactiveviewmodel.core.property

import androidx.annotation.MainThread
import androidx.collection.ArraySet
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Observer
import com.alexdeww.reactiveviewmodel.core.property.ConfirmationEvent.ObserverWrapper
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.functions.Consumer

class ConfirmationEvent<T : Any> internal constructor(debounceInterval: Long? = null) {

private sealed class EventType {
data class Pending(val data: Any) : EventType()
object Confirmed : EventType()
}

private val eventState = State<EventType>(EventType.Confirmed, debounceInterval)

internal val consumer: Consumer<T> = Consumer {
eventState.consumer.accept(EventType.Pending(it))
}

@Suppress("UNCHECKED_CAST")
internal val observable: Observable<T> = eventState.observable
.ofType(EventType.Pending::class.java)
.map { it.data as T }

val liveData: LiveData<T> by lazy { ConfirmationEventLiveData() }
val viewFlowable: Flowable<T> by lazy { observable.toViewFlowable() }
val isConfirmed: Boolean get() = eventState.value === EventType.Confirmed

fun confirm() {
eventState.consumer.accept(EventType.Confirmed)
}

private inner class ConfirmationEventLiveData : MediatorLiveData<T>() {

private val observers = ArraySet<ConfirmationEvent.ObserverWrapper<T>>()

@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
val wrapper = ObserverWrapper(observer)
observers.add(wrapper)
super.observe(owner, wrapper)
}

@MainThread
override fun removeObserver(observer: Observer<in T>) {
if (observers.remove(observer as Observer<*>)) {
super.removeObserver(observer)
return
}

val iterator = observers.iterator()
while (iterator.hasNext()) {
val wrapper = iterator.next()
if (wrapper.observer == observer) {
iterator.remove()
super.removeObserver(observer)
break
}
}
}

@Suppress("UNCHECKED_CAST")
override fun onActive() {
super.onActive()
addSource(eventState.liveData) { value = (it as? EventType.Pending)?.data as T }
}

override fun onInactive() {
removeSource(eventState.liveData)
super.onInactive()
}
}

private class ObserverWrapper<T>(val observer: Observer<in T>) : Observer<T> {
override fun onChanged(t: T?) {
if (t != null) observer.onChanged(t)
}
}

}

0 comments on commit 2653d21

Please sign in to comment.