From dbc537d9474660a7d6b9821327b0ec948424ac63 Mon Sep 17 00:00:00 2001 From: toluo-stripe Date: Fri, 27 Sep 2024 13:42:34 -0400 Subject: [PATCH] remove mvi-viewmodel --- .../com/stripe/android/link/LinkActivity.kt | 38 ++++------ .../android/link/LinkActivityViewModel.kt | 26 +++---- .../stripe/android/link/ui/signup/Model.kt | 18 ----- .../android/link/ui/signup/SignUpScreen.kt | 25 +------ .../android/link/ui/signup/SignUpViewModel.kt | 40 ---------- .../stripe/android/link/LinkActivityTest.kt | 75 ------------------- .../android/link/LinkActivityViewModelTest.kt | 23 +++--- .../link/ui/signup/SignUpViewModelTest.kt | 45 ----------- 8 files changed, 37 insertions(+), 253 deletions(-) delete mode 100644 link/src/main/java/com/stripe/android/link/ui/signup/Model.kt delete mode 100644 link/src/main/java/com/stripe/android/link/ui/signup/SignUpViewModel.kt delete mode 100644 link/src/test/java/com/stripe/android/link/LinkActivityTest.kt delete mode 100644 link/src/test/java/com/stripe/android/link/ui/signup/SignUpViewModelTest.kt diff --git a/link/src/main/java/com/stripe/android/link/LinkActivity.kt b/link/src/main/java/com/stripe/android/link/LinkActivity.kt index 61d0d57bb35..5ece38b0e04 100644 --- a/link/src/main/java/com/stripe/android/link/LinkActivity.kt +++ b/link/src/main/java/com/stripe/android/link/LinkActivity.kt @@ -10,7 +10,6 @@ import androidx.appcompat.app.AppCompatActivity import androidx.compose.runtime.LaunchedEffect import androidx.core.os.bundleOf import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -18,7 +17,6 @@ import androidx.navigation.compose.rememberNavController import com.stripe.android.link.ui.cardedit.CardEditScreen import com.stripe.android.link.ui.paymentmenthod.PaymentMethodScreen import com.stripe.android.link.ui.signup.SignUpScreen -import com.stripe.android.link.ui.signup.SignUpViewModel import com.stripe.android.link.ui.verification.VerificationScreen import com.stripe.android.link.ui.wallet.WalletScreen @@ -36,22 +34,9 @@ internal class LinkActivity : AppCompatActivity() { setContent { navController = rememberNavController() - LaunchedEffect("LinkEffects") { - viewModel.effect.collect { effect -> - when (effect) { - LinkEffect.GoBack -> navController.popBackStack() - is LinkEffect.SendResult -> { - val bundle = bundleOf( - LinkActivityContract.EXTRA_RESULT to LinkActivityContract.Result(effect.result) - ) - this@LinkActivity.setResult( - Activity.RESULT_OK, - Intent().putExtras(bundle) - ) - this@LinkActivity.finish() - } - } - } + LaunchedEffect(Unit) { + viewModel.navController = navController + viewModel.dismissWithResult = ::dismissWithResult } NavHost( @@ -59,11 +44,7 @@ internal class LinkActivity : AppCompatActivity() { startDestination = LinkScreen.SignUp.route ) { composable(LinkScreen.SignUp.route) { - val vm = viewModel() - SignUpScreen( - viewModel = vm, - navController = navController - ) + SignUpScreen() } composable(LinkScreen.Verification.route) { @@ -84,4 +65,15 @@ internal class LinkActivity : AppCompatActivity() { } } } + + private fun dismissWithResult(result: LinkActivityResult) { + val bundle = bundleOf( + LinkActivityContract.EXTRA_RESULT to LinkActivityContract.Result(result) + ) + this@LinkActivity.setResult( + Activity.RESULT_OK, + Intent().putExtras(bundle) + ) + this@LinkActivity.finish() + } } diff --git a/link/src/main/java/com/stripe/android/link/LinkActivityViewModel.kt b/link/src/main/java/com/stripe/android/link/LinkActivityViewModel.kt index 75bd2bfeb5b..a978c16ca2c 100644 --- a/link/src/main/java/com/stripe/android/link/LinkActivityViewModel.kt +++ b/link/src/main/java/com/stripe/android/link/LinkActivityViewModel.kt @@ -2,28 +2,20 @@ package com.stripe.android.link import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf +import androidx.navigation.NavHostController -internal class LinkActivityViewModel : StateAndEffectsVM( - initialState = LinkState, -) { - override fun actionToResult(action: LinkAction): Flow { - return when (action) { +internal class LinkActivityViewModel : ViewModel() { + lateinit var navController: NavHostController + lateinit var dismissWithResult: (LinkActivityResult) -> Unit + + fun handleViewAction(action: LinkAction) { + when (action) { LinkAction.BackPressed -> handleBackPressed() } } - private fun handleBackPressed(): Flow { - return flowOf(LinkResult.SendEffect(LinkEffect.GoBack)) - } - - override fun resultToState(currentState: LinkState, result: LinkResult) = currentState - - override fun resultToEffect(result: LinkResult): LinkEffect? { - return when (result) { - is LinkResult.SendEffect -> result.effect - } + private fun handleBackPressed() { + dismissWithResult(LinkActivityResult.Canceled()) } internal class Factory : ViewModelProvider.Factory { diff --git a/link/src/main/java/com/stripe/android/link/ui/signup/Model.kt b/link/src/main/java/com/stripe/android/link/ui/signup/Model.kt deleted file mode 100644 index 0a03cc95405..00000000000 --- a/link/src/main/java/com/stripe/android/link/ui/signup/Model.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.stripe.android.link.ui.signup - -data class SignUpViewState( - val loading: Boolean = false -) - -sealed interface SignUpAction { - data object SignUpClicked : SignUpAction -} - -sealed interface SignUpResult { - data object ShowLoader : SignUpResult - data class SendEffect(val effect: SignUpEffect) : SignUpResult -} - -sealed interface SignUpEffect { - data object NavigateToWallet : SignUpEffect -} diff --git a/link/src/main/java/com/stripe/android/link/ui/signup/SignUpScreen.kt b/link/src/main/java/com/stripe/android/link/ui/signup/SignUpScreen.kt index 6c38cb6cdf5..877500d116a 100644 --- a/link/src/main/java/com/stripe/android/link/ui/signup/SignUpScreen.kt +++ b/link/src/main/java/com/stripe/android/link/ui/signup/SignUpScreen.kt @@ -1,28 +1,9 @@ package com.stripe.android.link.ui.signup -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.navigation.NavHostController -import com.stripe.android.link.LinkScreen -import com.stripe.android.uicore.utils.collectAsState @Composable -internal fun SignUpScreen( - viewModel: SignUpViewModel, - navController: NavHostController -) { - LaunchedEffect("SignUpEffects") { - viewModel.effect.collect { effect -> - when (effect) { - SignUpEffect.NavigateToWallet -> navController.navigate(LinkScreen.Wallet.route) - } - } - } - val state by viewModel.state.collectAsState() - AnimatedVisibility(visible = state.loading) { - CircularProgressIndicator() - } +internal fun SignUpScreen() { + Text(text = "SignUpScreen") } diff --git a/link/src/main/java/com/stripe/android/link/ui/signup/SignUpViewModel.kt b/link/src/main/java/com/stripe/android/link/ui/signup/SignUpViewModel.kt deleted file mode 100644 index fa9472d1759..00000000000 --- a/link/src/main/java/com/stripe/android/link/ui/signup/SignUpViewModel.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.stripe.android.link.ui.signup - -import com.stripe.android.link.StateAndEffectsVM -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow - -internal class SignUpViewModel : StateAndEffectsVM( - initialState = SignUpViewState() -) { - override fun actionToResult(action: SignUpAction): Flow { - return when (action) { - SignUpAction.SignUpClicked -> handleSignUpClicked() - } - } - - private fun handleSignUpClicked() = flow { - emit(SignUpResult.ShowLoader) - emit( - value = SignUpResult.SendEffect( - effect = SignUpEffect.NavigateToWallet - ) - ) - } - - override fun resultToState(currentState: SignUpViewState, result: SignUpResult): SignUpViewState { - return when (result) { - is SignUpResult.SendEffect -> currentState - SignUpResult.ShowLoader -> { - currentState.copy(loading = true) - } - } - } - - override fun resultToEffect(result: SignUpResult): SignUpEffect? { - return when (result) { - is SignUpResult.SendEffect -> result.effect - SignUpResult.ShowLoader -> null - } - } -} diff --git a/link/src/test/java/com/stripe/android/link/LinkActivityTest.kt b/link/src/test/java/com/stripe/android/link/LinkActivityTest.kt deleted file mode 100644 index e8df2292585..00000000000 --- a/link/src/test/java/com/stripe/android/link/LinkActivityTest.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.stripe.android.link - -import android.content.Context -import android.content.Intent -import android.os.Build -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import androidx.compose.ui.test.junit4.createAndroidComposeRule -import androidx.navigation.NavHostController -import androidx.test.core.app.ApplicationProvider -import com.stripe.android.link.utils.InjectableActivityScenario -import com.stripe.android.link.utils.injectableActivityScenario -import com.stripe.android.link.utils.viewModelFactoryFor -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.test.resetMain -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.kotlin.mock -import org.mockito.kotlin.verify -import org.robolectric.RobolectricTestRunner -import org.robolectric.annotation.Config -import kotlin.test.AfterTest - -@RunWith(RobolectricTestRunner::class) -@Config(sdk = [Build.VERSION_CODES.Q]) -internal class LinkActivityTest { - - @get:Rule - val rule = InstantTaskExecutorRule() - - @get:Rule - val composeTestRule = createAndroidComposeRule() - - private val navHostController: NavHostController = mock() - - private val context = ApplicationProvider.getApplicationContext() - - @AfterTest - fun cleanup() { - Dispatchers.resetMain() - } - - @Test - fun `test that navigator pops back on back pressed`() { - val vm = LinkActivityViewModel() - val scenario = activityScenario(viewModel = vm) - scenario.launchTest { - vm.handleAction(LinkAction.BackPressed) - - composeTestRule.waitForIdle() - - verify(navHostController).popBackStack() - } - } - - private fun InjectableActivityScenario.launchTest( - startIntent: Intent = Intent(context, LinkActivity::class.java), - block: (LinkActivity) -> Unit - ) { - launch(startIntent).onActivity { activity -> - activity.navController = navHostController - block(activity) - } - } - - private fun activityScenario( - viewModel: LinkActivityViewModel = LinkActivityViewModel(), - ): InjectableActivityScenario { - return injectableActivityScenario { - injectActivity { - viewModelFactory = viewModelFactoryFor(viewModel) - } - } - } -} diff --git a/link/src/test/java/com/stripe/android/link/LinkActivityViewModelTest.kt b/link/src/test/java/com/stripe/android/link/LinkActivityViewModelTest.kt index d36a2deb708..057bc9c1b6b 100644 --- a/link/src/test/java/com/stripe/android/link/LinkActivityViewModelTest.kt +++ b/link/src/test/java/com/stripe/android/link/LinkActivityViewModelTest.kt @@ -1,7 +1,6 @@ package com.stripe.android.link -import app.cash.turbine.test -import com.google.common.truth.Truth +import androidx.navigation.NavHostController import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain @@ -11,16 +10,22 @@ import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) internal class LinkActivityViewModelTest { private val dispatcher = UnconfinedTestDispatcher() private val vm = LinkActivityViewModel() + private val navController: NavHostController = mock() + private val dismissWithResult: (LinkActivityResult) -> Unit = mock() @Before fun setUp() { Dispatchers.setMain(dispatcher) + vm.dismissWithResult = dismissWithResult + vm.navController = navController } @After @@ -29,17 +34,9 @@ internal class LinkActivityViewModelTest { } @Test - fun `test that viewmodel has correct initial state`() = runTest(dispatcher) { - vm.state.test { - Truth.assertThat(awaitItem()).isEqualTo(LinkState) - } - } + fun `test that cancel result is called on back pressed`() = runTest(dispatcher) { + vm.handleViewAction(LinkAction.BackPressed) - @Test - fun `test that correct effect is emitted on back pressed`() = runTest(dispatcher) { - vm.effect.test { - vm.handleAction(LinkAction.BackPressed) - Truth.assertThat(awaitItem()).isEqualTo(LinkEffect.GoBack) - } + verify(dismissWithResult).invoke(LinkActivityResult.Canceled()) } } diff --git a/link/src/test/java/com/stripe/android/link/ui/signup/SignUpViewModelTest.kt b/link/src/test/java/com/stripe/android/link/ui/signup/SignUpViewModelTest.kt deleted file mode 100644 index b55b7cb9df6..00000000000 --- a/link/src/test/java/com/stripe/android/link/ui/signup/SignUpViewModelTest.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.stripe.android.link.ui.signup - -import app.cash.turbine.test -import com.google.common.truth.Truth -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.test.UnconfinedTestDispatcher -import kotlinx.coroutines.test.resetMain -import kotlinx.coroutines.test.runTest -import kotlinx.coroutines.test.setMain -import org.junit.After -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner - -@RunWith(RobolectricTestRunner::class) -class SignUpViewModelTest { - private val dispatcher = UnconfinedTestDispatcher() - private val vm = SignUpViewModel() - - @Before - fun setUp() { - Dispatchers.setMain(dispatcher) - } - - @After - fun tearDown() { - Dispatchers.resetMain() - } - - @Test - fun `test that viewmodel has correct initial state`() = runTest(dispatcher) { - vm.state.test { - Truth.assertThat(awaitItem()).isEqualTo(SignUpViewState()) - } - } - - @Test - fun `test that correct effect is emitted on successful sign up`() = runTest(dispatcher) { - vm.effect.test { - vm.handleAction(SignUpAction.SignUpClicked) - Truth.assertThat(awaitItem()).isEqualTo(SignUpEffect.NavigateToWallet) - } - } -}