artem-zinnatullin / RxUi

Implementation of pure functional concept of talking to Android View layer in a Reactive way
https://artemzin.com/blog/rxui-talking-to-android-view-layer-in-a-reactive-way/
MIT License
261 stars 22 forks source link

Execute more then one command in view #35

Open crazyk2 opened 7 years ago

crazyk2 commented 7 years ago

I have chain, for example

 disposable = requestByClick
                .filter { !isLoading() }
                .doOnNext { showProgress() }
                .delay(3, TimeUnit.SECONDS)
                .flatMap { interactor.findWords(it).toObservable() }
                .observeOn(AndroidSchedulers.mainThread())
                .doOnEach { hideProgress() }
                .subscribe(foundWords)

How can I rewrite it with your library? I understood that you bind only one action/command between View and Presenter and showProgress() which returns return Rx.ui(avoid -> progressBar.visible()) need to Bind separatly

artem-zinnatullin commented 7 years ago

For now I would split stream into two and bind showProgress(), hideProgress() and foundWords separately:

val request = requestByClick.filter { isLoading() == false }.share()

val result = requests
  .delay(3, SECONDS)
  .flatMap { interactor.findWords(it).toObservable() }
  .share()

disposable += request.bind(showProgress)
disposable += result.bind(hideProgress)
disposable += result.bind(foundWords)

But I see the point and feel the pain, I'll try to play around with one concept I have that might solve this.

artem-zinnatullin commented 7 years ago

Ok, so here is the concept of such a function that you can apply in the middle of the stream:

disposable += Observable
  .just("a", "b", "c")
  .bind2(showProgress)
  .map { process(it) }
  .bind2(hideProgress)
  .bind(foundWords)
fun <T> Observable<T>.bind2(uiFunc: Function<Observable<T>, Disposable>): Observable<T> {
    var disposable: Disposable? = null
    val emitter = PublishSubject.create<T>()

    return this
            .doOnEach { notification ->
                when {
                    notification.isOnNext -> {
                        if (disposable == null) {
                            disposable = RxUi.bind(emitter, uiFunc)
                        }

                        emitter.onNext(notification.value!!)
                    }

                    notification.isOnComplete || notification.isOnError -> disposable?.dispose()
                }
            }
            .doOnDispose { disposable?.dispose() }
}