Skip to content

Commit

Permalink
Merge pull request #12218 from woocommerce/issue/12203-handle-multipl…
Browse files Browse the repository at this point in the history
…e-clicks-on-connect-reader-button

[WOO POS]M2: Prevent Multiple Instances of Card Reader Connect Dialog
  • Loading branch information
AnirudhBhat authored Aug 9, 2024
2 parents 886e0cd + 86983c8 commit 2f9c9d4
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.MenuI
import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.OnOutsideOfToolbarMenuClicked
import com.woocommerce.android.ui.woopos.home.toolbar.WooPosToolbarUIEvent.OnToolbarMenuClicked
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
Expand All @@ -33,6 +35,8 @@ class WooPosToolbarViewModel @Inject constructor(
)
val state: StateFlow<WooPosToolbarState> = _state

private var debounceJob: Job? = null

init {
viewModelScope.launch {
cardReaderFacade.readerStatus.collect {
Expand Down Expand Up @@ -85,7 +89,9 @@ class WooPosToolbarViewModel @Inject constructor(

private fun handleConnectToReaderButtonClicked() {
if (_state.value.cardReaderStatus != WooPosToolbarState.WooPosCardReaderStatus.Connected) {
cardReaderFacade.connectToReader()
debounce {
cardReaderFacade.connectToReader()
}
}
}

Expand All @@ -96,6 +102,16 @@ class WooPosToolbarViewModel @Inject constructor(
}
}

private fun debounce(block: () -> Unit) {
if (debounceJob?.isActive == true) {
return
}
debounceJob = viewModelScope.launch {
block()
delay(DEBOUNCE_TIME_MS)
}
}

private companion object {
val toolbarMenuItems = listOf(
WooPosToolbarState.Menu.MenuItem(
Expand All @@ -107,5 +123,11 @@ class WooPosToolbarViewModel @Inject constructor(
icon = R.drawable.woopos_ic_exit_pos,
),
)

private const val DEBOUNCE_TIME_MS = 800L
}

override fun onCleared() {
debounceJob?.cancel()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import com.woocommerce.android.ui.woopos.home.WooPosChildrenToParentEventSender
import com.woocommerce.android.ui.woopos.util.WooPosCoroutineTestRule
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever

Expand Down Expand Up @@ -129,6 +131,40 @@ class WooPosToolbarViewModelTest {
assertThat(viewModel.state.value.menu).isEqualTo(WooPosToolbarState.Menu.Hidden)
}

@Test
fun `when connect to card reader clicked multiple times, then debounce prevents multiple clicks`() = runTest {
// GIVEN
whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(CardReaderStatus.NotConnected()))
val viewModel = createViewModel()

// WHEN
viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked)
viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked)
viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked)
advanceUntilIdle()

// THEN
verify(cardReaderFacade, times(1)).connectToReader()
}

@Test
fun `when connect to card reader clicked multiple times after delay, then debounce handles all clicks`() = runTest {
// GIVEN
whenever(cardReaderFacade.readerStatus).thenReturn(flowOf(CardReaderStatus.NotConnected()))
val viewModel = createViewModel()

// WHEN
viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked)
advanceUntilIdle()
viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked)
advanceUntilIdle()
viewModel.onUiEvent(WooPosToolbarUIEvent.ConnectToAReaderClicked)
advanceUntilIdle()

// THEN
verify(cardReaderFacade, times(3)).connectToReader()
}

private fun createViewModel() = WooPosToolbarViewModel(
cardReaderFacade,
childrenToParentEventSender
Expand Down

0 comments on commit 2f9c9d4

Please sign in to comment.