Skip to content

Commit

Permalink
Link Verification VM (#9542)
Browse files Browse the repository at this point in the history
  • Loading branch information
toluo-stripe authored Nov 12, 2024
1 parent 4a49d68 commit 938f70e
Show file tree
Hide file tree
Showing 17 changed files with 617 additions and 15 deletions.
2 changes: 0 additions & 2 deletions link/api/link.api
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,12 @@ public final class com/stripe/android/link/ui/ComposableSingletons$LinkContentKt
public static field lambda-3 Lkotlin/jvm/functions/Function4;
public static field lambda-4 Lkotlin/jvm/functions/Function4;
public static field lambda-5 Lkotlin/jvm/functions/Function4;
public static field lambda-6 Lkotlin/jvm/functions/Function4;
public fun <init> ()V
public final fun getLambda-1$link_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-2$link_release ()Lkotlin/jvm/functions/Function4;
public final fun getLambda-3$link_release ()Lkotlin/jvm/functions/Function4;
public final fun getLambda-4$link_release ()Lkotlin/jvm/functions/Function4;
public final fun getLambda-5$link_release ()Lkotlin/jvm/functions/Function4;
public final fun getLambda-6$link_release ()Lkotlin/jvm/functions/Function4;
}

public final class com/stripe/android/link/ui/ComposableSingletons$LinkTermsKt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.stripe.android.link.account.LinkAccountManager
import com.stripe.android.link.injection.DaggerNativeLinkComponent
import com.stripe.android.link.injection.NativeLinkComponent
import com.stripe.android.link.model.AccountStatus
import com.stripe.android.link.model.LinkAccount
import com.stripe.android.link.ui.LinkAppBarState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand All @@ -37,6 +38,10 @@ internal class LinkActivityViewModel @Inject constructor(
)
)
val linkState: StateFlow<LinkAppBarState> = _linkState

val linkAccount: LinkAccount?
get() = linkAccountManager.linkAccount.value

var navController: NavHostController? = null
var dismissWithResult: ((LinkActivityResult) -> Unit)? = null

Expand All @@ -54,6 +59,23 @@ internal class LinkActivityViewModel @Inject constructor(
}
}

fun navigate(screen: LinkScreen, clearStack: Boolean) {
val navController = navController ?: return
navController.navigate(screen.route) {
if (clearStack) {
popUpTo(navController.graph.startDestinationId) {
inclusive = true
}
}
}
}

fun goBack() {
if (navController?.popBackStack() == false) {
dismissWithResult?.invoke(LinkActivityResult.Canceled())
}
}

fun unregisterActivity() {
navController = null
dismissWithResult = null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.stripe.android.link

internal class NoLinkAccountFound : IllegalStateException("No link account found")
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ internal class DefaultLinkAccountManager @Inject constructor(

override suspend fun startVerification(): Result<LinkAccount> {
val clientSecret = linkAccount.value?.clientSecret ?: return Result.failure(Throwable("no link account found"))
linkEventsReporter.on2FAStart()
return linkRepository.startVerification(clientSecret, consumerPublishableKey)
.onFailure {
linkEventsReporter.on2FAStartFailure()
Expand All @@ -232,7 +233,11 @@ internal class DefaultLinkAccountManager @Inject constructor(
override suspend fun confirmVerification(code: String): Result<LinkAccount> {
val clientSecret = linkAccount.value?.clientSecret ?: return Result.failure(Throwable("no link account found"))
return linkRepository.confirmVerification(code, clientSecret, consumerPublishableKey)
.map { consumerSession ->
.onSuccess {
linkEventsReporter.on2FAComplete()
}.onFailure {
linkEventsReporter.on2FAFailure()
}.map { consumerSession ->
setAccount(consumerSession, null)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,26 @@ internal class DefaultLinkEventsReporter @Inject constructor(
fireEvent(LinkEvent.AccountLookupFailure, params)
}

override fun on2FAStart() {
fireEvent(LinkEvent.TwoFAStart)
}

override fun on2FAStartFailure() {
fireEvent(LinkEvent.TwoFAStartFailure)
}

override fun on2FAComplete() {
fireEvent(LinkEvent.TwoFAComplete)
}

override fun on2FAFailure() {
fireEvent(LinkEvent.TwoFAFailure)
}

override fun on2FACancel() {
fireEvent(LinkEvent.TwoFACancel)
}

override fun onPopupShow() {
fireEvent(LinkEvent.PopupShow)
}
Expand Down
16 changes: 16 additions & 0 deletions link/src/main/java/com/stripe/android/link/analytics/LinkEvent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,26 @@ internal sealed class LinkEvent : AnalyticsEvent {
override val eventName = "link.account_lookup.failure"
}

object TwoFAStart : LinkEvent() {
override val eventName = "link.2fa.start"
}

object TwoFAStartFailure : LinkEvent() {
override val eventName = "link.2fa.start_failure"
}

object TwoFAComplete : LinkEvent() {
override val eventName = "link.2fa.complete"
}

object TwoFAFailure : LinkEvent() {
override val eventName = "link.2fa.failure"
}

object TwoFACancel : LinkEvent() {
override val eventName = "link.2fa.cancel"
}

object PopupShow : LinkEvent() {
override val eventName = "link.popup.show"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ internal interface LinkEventsReporter {
fun onSignupFailure(isInline: Boolean = false, error: Throwable)
fun onAccountLookupFailure(error: Throwable)

fun on2FAStart()
fun on2FAStartFailure()
fun on2FAComplete()
fun on2FAFailure()
fun on2FACancel()

fun onPopupShow()
fun onPopupSuccess()
Expand Down
36 changes: 33 additions & 3 deletions link/src/main/java/com/stripe/android/link/ui/LinkContent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.stripe.android.link.LinkAction
import com.stripe.android.link.LinkActivityResult
import com.stripe.android.link.LinkActivityViewModel
import com.stripe.android.link.LinkScreen
import com.stripe.android.link.NoLinkAccountFound
import com.stripe.android.link.linkViewModel
import com.stripe.android.link.model.LinkAccount
import com.stripe.android.link.theme.DefaultLinkTheme
import com.stripe.android.link.theme.linkColors
import com.stripe.android.link.theme.linkShapes
Expand All @@ -32,6 +35,7 @@ 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.verification.VerificationViewModel
import com.stripe.android.link.ui.wallet.WalletScreen
import com.stripe.android.ui.core.CircularProgressIndicator
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -86,15 +90,31 @@ internal fun LinkContent(
}
)

Screens(navController)
Screens(
navController = navController,
goBack = viewModel::goBack,
navigateAndClearStack = { screen ->
viewModel.navigate(screen, clearStack = true)
},
dismissWithResult = { result ->
viewModel.dismissWithResult?.invoke(result)
},
getLinkAccount = {
viewModel.linkAccount
}
)
}
}
}
}

@Composable
private fun Screens(
navController: NavHostController
navController: NavHostController,
getLinkAccount: () -> LinkAccount?,
goBack: () -> Unit,
navigateAndClearStack: (route: LinkScreen) -> Unit,
dismissWithResult: (LinkActivityResult) -> Unit
) {
NavHost(
navController = navController,
Expand All @@ -121,7 +141,17 @@ private fun Screens(
}

composable(LinkScreen.Verification.route) {
VerificationScreen()
val linkAccount = getLinkAccount()
?: return@composable dismissWithResult(LinkActivityResult.Failed(NoLinkAccountFound()))
val viewModel: VerificationViewModel = linkViewModel { parentComponent ->
VerificationViewModel.factory(
parentComponent = parentComponent,
goBack = goBack,
navigateAndClearStack = navigateAndClearStack,
linkAccount = linkAccount
)
}
VerificationScreen(viewModel)
}

composable(LinkScreen.Wallet.route) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package com.stripe.android.link.ui.verification
import androidx.compose.material.Text
import androidx.compose.runtime.Composable

@SuppressWarnings("UnusedParameter")
@Composable
internal fun VerificationScreen() {
internal fun VerificationScreen(
viewModel: VerificationViewModel
) {
Text(text = "VerificationScreen")
}
Loading

0 comments on commit 938f70e

Please sign in to comment.