From ad1839bdb5c19233b5cbd5b5fb75100998d1c18d Mon Sep 17 00:00:00 2001 From: alexandr Date: Mon, 4 Mar 2024 16:28:57 +0200 Subject: [PATCH] [MS-224] MatchViewModel now stores the initialization flag. Delay of the navigation (in order to have time to see the results on screen) is now handled in the view model --- .../simprints/matcher/screen/MatchFragment.kt | 12 ++---- .../matcher/screen/MatchViewModel.kt | 9 ++++- .../matcher/screen/MatchViewModelTest.kt | 37 ++++++++++++++++++- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchFragment.kt b/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchFragment.kt index 293d9437e9..f6fc47c9ac 100644 --- a/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchFragment.kt +++ b/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchFragment.kt @@ -2,8 +2,6 @@ package com.simprints.matcher.screen import android.animation.ObjectAnimator import android.os.Bundle -import android.os.Handler -import android.os.Looper import android.view.View import androidx.core.view.isGone import androidx.core.view.isVisible @@ -34,7 +32,9 @@ internal class MatchFragment : Fragment(R.layout.fragment_matcher) { super.onViewCreated(view, savedInstanceState) observeViewModel() - viewModel.setupMatch(args.params) + if(!viewModel.isInitialized) { + viewModel.setupMatch(args.params) + } } private fun setIdentificationProgress(progress: Int) = requireActivity().runOnUiThread { @@ -46,11 +46,7 @@ internal class MatchFragment : Fragment(R.layout.fragment_matcher) { private fun observeViewModel() { viewModel.matchResponse.observe(viewLifecycleOwner, LiveDataEventWithContentObserver { - // wait a bit for the user to see the results - Handler(Looper.getMainLooper()).postDelayed( - { findNavController().finishWithResult(this, it) }, - MatchViewModel.matchingEndWaitTimeInMillis - ) + findNavController().finishWithResult(this, it) }) viewModel.matchState.observe(viewLifecycleOwner) { matchState -> when (matchState) { diff --git a/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchViewModel.kt b/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchViewModel.kt index 35a8105aca..dbd0cb46e3 100644 --- a/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchViewModel.kt +++ b/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope import com.simprints.core.livedata.LiveDataEventWithContent import com.simprints.core.livedata.send import com.simprints.core.tools.time.TimeHelper +import com.simprints.infra.logging.Simber import com.simprints.matcher.FaceMatchResult import com.simprints.matcher.FingerprintMatchResult import com.simprints.matcher.MatchParams @@ -14,8 +15,8 @@ import com.simprints.matcher.MatchResultItem import com.simprints.matcher.usecases.FaceMatcherUseCase import com.simprints.matcher.usecases.FingerprintMatcherUseCase import com.simprints.matcher.usecases.SaveMatchEventUseCase -import com.simprints.infra.logging.Simber import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.io.Serializable import javax.inject.Inject @@ -29,6 +30,8 @@ internal class MatchViewModel @Inject constructor( private val timeHelper: TimeHelper, ) : ViewModel() { + var isInitialized = false + private set val matchState: LiveData get() = _matchState private val _matchState = MutableLiveData(MatchState.NotStarted) @@ -38,6 +41,7 @@ internal class MatchViewModel @Inject constructor( private val _matchResponse = MutableLiveData>() fun setupMatch(params: MatchParams) = viewModelScope.launch { + isInitialized = true val startTime = timeHelper.now() val isFaceMatch = params.isFaceMatch() @@ -67,6 +71,9 @@ internal class MatchViewModel @Inject constructor( setMatchState(totalCandidates, sortedResults) + // wait a bit for the user to see the results + delay(matchingEndWaitTimeInMillis) + _matchResponse.send(when { isFaceMatch -> FaceMatchResult(sortedResults) else -> FingerprintMatchResult(sortedResults) diff --git a/feature/matcher/src/test/java/com/simprints/matcher/screen/MatchViewModelTest.kt b/feature/matcher/src/test/java/com/simprints/matcher/screen/MatchViewModelTest.kt index a0bd014115..09fd8fc393 100644 --- a/feature/matcher/src/test/java/com/simprints/matcher/screen/MatchViewModelTest.kt +++ b/feature/matcher/src/test/java/com/simprints/matcher/screen/MatchViewModelTest.kt @@ -15,8 +15,16 @@ import com.simprints.matcher.usecases.FingerprintMatcherUseCase import com.simprints.matcher.usecases.SaveMatchEventUseCase import com.simprints.testtools.common.coroutines.TestCoroutineRule import com.simprints.testtools.common.livedata.getOrAwaitValue -import io.mockk.* +import io.mockk.CapturingSlot +import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.coJustRun +import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import io.mockk.slot +import io.mockk.verify +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule @@ -65,6 +73,29 @@ internal class MatchViewModelTest { timeHelper ) } + @Test + fun `when setup is called, then view model becomes initialized`() = runTest { + val responseItems = listOf( + FaceMatchResult.Item("1", 90f), + ) + + coEvery { faceMatcherUseCase.invoke(any(), capture(cb1)) } answers { + cb1.captured.invoke("tag1") + responseItems to responseItems.size + } + coJustRun { saveMatchEvent.invoke(any(), any(), any(), any(), any(), any()) } + + assertThat(viewModel.isInitialized).isFalse() + + viewModel.matchState.test() + viewModel.setupMatch(MatchParams( + probeFaceSamples = listOf(getFaceSample()), + flowType = FlowType.ENROL, + queryForCandidates = mockk {} + )) + + assertThat(viewModel.isInitialized).isTrue() + } @Test fun `Handle face match request correctly`() = runTest { @@ -90,6 +121,8 @@ internal class MatchViewModelTest { flowType = FlowType.ENROL, queryForCandidates = mockk {} )) + // Waiting for the ::delay in viewModel::setupMatch + advanceUntilIdle() assertThat(states.valueHistory()).isEqualTo( listOf( @@ -130,6 +163,8 @@ internal class MatchViewModelTest { flowType = FlowType.ENROL, queryForCandidates = mockk {} )) + // Waiting for the ::delay in viewModel::setupMatch + advanceUntilIdle() assertThat(states.valueHistory()).isEqualTo( listOf(