Last active
July 19, 2017 21:51
-
-
Save dmitriigriazin/b3b7d3ca94ad45a141e8e71ea3aee03a to your computer and use it in GitHub Desktop.
This file contains 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
package ru.avito.aviyo.play_market_info | |
import android.os.Bundle | |
import com.jakewharton.rxrelay2.BehaviorRelay | |
import com.jakewharton.rxrelay2.PublishRelay | |
import io.reactivex.disposables.CompositeDisposable | |
import ru.avito.aviyo.SchedulersFactory | |
import ru.avito.aviyo.distinctTypes | |
import ru.avito.aviyo.play_market_info.ScreenState.* | |
import ru.avito.aviyo.plusAssign | |
interface Presenter { | |
fun attachView(view: View) | |
fun detachView() | |
fun attachRouter(router: Router) | |
fun detachRouter() | |
fun dispose() | |
fun onSaveState(): Bundle | |
} | |
class PresenterImpl(private val stateMachine: StateMachine, | |
private val interactor: Interactor, | |
private val schedulers: SchedulersFactory, | |
savedState: Bundle?) : Presenter { | |
private val state: BehaviorRelay<ScreenState> = BehaviorRelay.createDefault(Empty()) | |
private var lastInput = savedState?.getString(KEY_LAST_INPUT) | |
private val toolbarUpClicks: PublishRelay<Unit> = PublishRelay.create() | |
private val inputEvents: PublishRelay<String> = PublishRelay.create() | |
private val retryClicks: PublishRelay<Unit> = PublishRelay.create() | |
private lateinit var routerDisposable: CompositeDisposable | |
private lateinit var viewDisposable: CompositeDisposable | |
private val lifecycleDisposable = CompositeDisposable() | |
init { | |
lifecycleDisposable += state | |
.distinctTypes() | |
.switchMap { currentState -> | |
when (currentState) { | |
is Empty -> listenToInputEvents(currentState) | |
is Content -> listenToInputEvents(currentState) | |
is FullScreenLoading -> requestData(currentState, currentState.input) | |
is FullScreenError -> reloadDataByRetryClicks(currentState) | |
} | |
} | |
.subscribe(state) | |
lifecycleDisposable += state | |
.subscribe { | |
if (it is Content) { | |
lastInput = it.input | |
} | |
} | |
} | |
private fun reloadDataByRetryClicks(currentState: ScreenState) = | |
retryClicks.map { stateMachine.restartLoading(currentState) } | |
private fun requestData(currentState: ScreenState, input: String) = | |
interactor.getPackageData(input).map { | |
stateMachine.dispatchData( | |
screenState = currentState, | |
loadingState = it) | |
} | |
private fun listenToInputEvents(currentState: ScreenState) = | |
inputEvents.map { stateMachine.submitQuery(currentState, it) } | |
override fun attachView(view: View) { | |
viewDisposable = CompositeDisposable() | |
viewDisposable += view.toolbarUpClicks.subscribe(toolbarUpClicks) | |
viewDisposable += view.retryClicks.subscribe(retryClicks) | |
viewDisposable += state | |
.observeOn(schedulers.mainThread()) | |
.subscribe(view.screenBinding) | |
viewDisposable += state | |
.observeOn(schedulers.mainThread()) | |
.subscribe { | |
if (it is Content) { | |
lastInput = it.input | |
} | |
} | |
} | |
override fun detachView() { | |
viewDisposable.dispose() | |
} | |
override fun attachRouter(router: Router) { | |
routerDisposable = CompositeDisposable() | |
routerDisposable += toolbarUpClicks | |
.subscribe { router.leave() } | |
} | |
override fun detachRouter() { | |
routerDisposable.dispose() | |
} | |
override fun dispose() { | |
lifecycleDisposable.dispose() | |
} | |
override fun onSaveState() = Bundle().apply { putString(KEY_LAST_INPUT, lastInput) } | |
} | |
private const val KEY_LAST_INPUT = "KEY_LAST_INPUT" |
This file contains 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
package ru.avito.aviyo.play_market_info | |
import ru.avito.api.PlayMarketInfo | |
sealed class ScreenState() { | |
class Empty() : ScreenState() | |
class Content(val input: String, val info: PlayMarketInfo) : ScreenState() | |
class FullScreenLoading(val input: String) : ScreenState() | |
class FullScreenError(val input: String, val errorMessage: String) : ScreenState() | |
//class ModalError(val input: String, val info: PlayMarketInfo, val errorMessage: String) : ScreenState() | |
//class ModalLoading(val input: String, val info: PlayMarketInfo) : ScreenState() | |
} |
This file contains 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
package ru.avito.aviyo.play_market_info | |
import ru.avito.api.PlayMarketInfo | |
import ru.avito.aviyo.LoadingState | |
import ru.avito.aviyo.LoadingState.Error | |
import ru.avito.aviyo.LoadingState.Loaded | |
import ru.avito.aviyo.LoadingState.Loading | |
import ru.avito.aviyo.play_market_info.ScreenState.* | |
interface StateMachine { | |
fun dispatchData(screenState: ScreenState, loadingState: LoadingState<PlayMarketInfo>): ScreenState | |
fun restartLoading(state: ScreenState): ScreenState | |
fun submitQuery(state: ScreenState, query: String): ScreenState | |
} | |
class StateMachineImpl : StateMachine { | |
override fun dispatchData(screenState: ScreenState, | |
loadingState: LoadingState<PlayMarketInfo>): ScreenState { | |
return when (screenState) { | |
is FullScreenLoading -> { | |
when (loadingState) { | |
is Loaded -> Content( | |
input = screenState.input, | |
info = loadingState.data) | |
is Error -> FullScreenError( | |
input = screenState.input, | |
errorMessage = loadingState.error.message) | |
is Loading -> FullScreenLoading( | |
input = screenState.input | |
) | |
} | |
} | |
else -> error("Data dispatching is unsupported for screenState $screenState") | |
} | |
} | |
override fun submitQuery(state: ScreenState, query: String) = when (state) { | |
is Content, is Empty, is FullScreenError -> FullScreenLoading(input = query) | |
else -> error("Query submiting is unsupported for state $state") | |
} | |
override fun restartLoading(state: ScreenState) = when (state) { | |
is FullScreenError -> FullScreenLoading(input = state.input) | |
else -> error("Loading restart is unsupported for state $state") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment