Merge pull request #7292 from thunderbird/one_time_initialization
Add support for one-time (initialization) events
This commit is contained in:
commit
0b23c20b7e
7 changed files with 76 additions and 5 deletions
|
@ -35,6 +35,8 @@ abstract class BaseViewModel<STATE, EVENT, EFFECT>(
|
|||
private val _effect = MutableSharedFlow<EFFECT>()
|
||||
override val effect: SharedFlow<EFFECT> = _effect.asSharedFlow()
|
||||
|
||||
private val handledOneTimeEvents = mutableSetOf<EVENT>()
|
||||
|
||||
/**
|
||||
* Updates the [STATE] of the ViewModel.
|
||||
*
|
||||
|
@ -54,4 +56,20 @@ abstract class BaseViewModel<STATE, EVENT, EFFECT>(
|
|||
_effect.emit(effect)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that one-time events are only handled once.
|
||||
*
|
||||
* When you can't ensure that an event is only sent once, but you want the event to only be handled once, call this
|
||||
* method. It will ensure [block] is only executed the first time this function is called. Subsequent calls with an
|
||||
* [event] argument equal to that of a previous invocation will not execute [block].
|
||||
*
|
||||
* Multiple one-time events are supported.
|
||||
*/
|
||||
protected fun handleOneTimeEvent(event: EVENT, block: () -> Unit) {
|
||||
if (event !in handledOneTimeEvents) {
|
||||
handledOneTimeEvents.add(event)
|
||||
block()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import app.cash.turbine.test
|
|||
import app.k9mail.core.ui.compose.testing.MainDispatcherRule
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import assertk.assertions.isFalse
|
||||
import assertk.assertions.isTrue
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
@ -47,10 +49,61 @@ class BaseViewModelTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `handleOneTimeEvent() should execute block`() = runTest {
|
||||
val viewModel = TestBaseViewModel()
|
||||
var eventHandled = false
|
||||
|
||||
viewModel.callHandleOneTimeEvent(event = "event") {
|
||||
eventHandled = true
|
||||
}
|
||||
|
||||
assertThat(eventHandled).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `handleOneTimeEvent() should execute block only once`() = runTest {
|
||||
val viewModel = TestBaseViewModel()
|
||||
var eventHandledCount = 0
|
||||
|
||||
repeat(2) {
|
||||
viewModel.callHandleOneTimeEvent(event = "event") {
|
||||
eventHandledCount++
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(eventHandledCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `handleOneTimeEvent() should support multiple one-time events`() = runTest {
|
||||
val viewModel = TestBaseViewModel()
|
||||
var eventOneHandled = false
|
||||
var eventTwoHandled = false
|
||||
|
||||
viewModel.callHandleOneTimeEvent(event = "eventOne") {
|
||||
eventOneHandled = true
|
||||
}
|
||||
|
||||
assertThat(eventOneHandled).isTrue()
|
||||
assertThat(eventTwoHandled).isFalse()
|
||||
|
||||
viewModel.callHandleOneTimeEvent(event = "eventTwo") {
|
||||
eventTwoHandled = true
|
||||
}
|
||||
|
||||
assertThat(eventOneHandled).isTrue()
|
||||
assertThat(eventTwoHandled).isTrue()
|
||||
}
|
||||
|
||||
private class TestBaseViewModel : BaseViewModel<String, String, String>("Initial state") {
|
||||
override fun event(event: String) {
|
||||
updateState { event }
|
||||
emitEffect(event)
|
||||
}
|
||||
|
||||
fun callHandleOneTimeEvent(event: String, block: () -> Unit) {
|
||||
handleOneTimeEvent(event, block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ abstract class BaseSaveServerSettingsViewModel(
|
|||
|
||||
override fun event(event: Event) {
|
||||
when (event) {
|
||||
Event.SaveServerSettings -> onSaveServerSettings()
|
||||
Event.SaveServerSettings -> handleOneTimeEvent(event, ::onSaveServerSettings)
|
||||
Event.OnNextClicked -> navigateNext()
|
||||
Event.OnBackClicked -> navigateBack()
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ open class IncomingServerSettingsViewModel(
|
|||
@Suppress("CyclomaticComplexMethod")
|
||||
override fun event(event: Event) {
|
||||
when (event) {
|
||||
Event.LoadAccountState -> loadAccountState()
|
||||
Event.LoadAccountState -> handleOneTimeEvent(event, ::loadAccountState)
|
||||
|
||||
is Event.ProtocolTypeChanged -> updateProtocolType(event.protocolType)
|
||||
is Event.ServerChanged -> updateState { it.copy(server = it.server.updateValue(event.server)) }
|
||||
|
|
|
@ -21,7 +21,7 @@ open class OutgoingServerSettingsViewModel(
|
|||
|
||||
override fun event(event: Event) {
|
||||
when (event) {
|
||||
Event.LoadAccountState -> loadAccountState()
|
||||
Event.LoadAccountState -> handleOneTimeEvent(event, ::loadAccountState)
|
||||
|
||||
is Event.ServerChanged -> updateState { it.copy(server = it.server.updateValue(event.server)) }
|
||||
is Event.SecurityChanged -> updateSecurity(event.security)
|
||||
|
|
|
@ -37,7 +37,7 @@ abstract class BaseServerValidationViewModel(
|
|||
|
||||
override fun event(event: Event) {
|
||||
when (event) {
|
||||
Event.LoadAccountStateAndValidate -> loadAccountStateAndValidate()
|
||||
Event.LoadAccountStateAndValidate -> handleOneTimeEvent(event, ::loadAccountStateAndValidate)
|
||||
is Event.OnOAuthResult -> onOAuthResult(event.result)
|
||||
Event.ValidateServerSettings -> onValidateConfig()
|
||||
Event.OnNextClicked -> navigateNext()
|
||||
|
|
|
@ -20,7 +20,7 @@ internal class AccountOptionsViewModel(
|
|||
|
||||
override fun event(event: Event) {
|
||||
when (event) {
|
||||
Event.LoadAccountState -> loadAccountState()
|
||||
Event.LoadAccountState -> handleOneTimeEvent(event, ::loadAccountState)
|
||||
|
||||
is Event.OnAccountNameChanged -> updateState { state ->
|
||||
state.copy(
|
||||
|
|
Loading…
Reference in a new issue