diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt
index 796b99ce27..5551a4af79 100644
--- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt
+++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt
@@ -14,6 +14,7 @@ import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.settings.usercountry.models.UserCountry
+import com.tangem.domain.visa.model.VisaCardActivationStatus
import com.tangem.domain.wallets.builder.UserWalletBuilder
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
import com.tangem.domain.wallets.models.UserWallet
@@ -44,6 +45,12 @@ object OnboardingHelper {
store.state.globalState.onboardingState.onboardingManager ?: OnboardingManager(response)
val cardId = response.card.cardId
return when {
+ response.cardTypesResolver.isVisaWallet() -> {
+ if (response.visaCardActivationStatus == null) error("Visa card activation status is null")
+
+ response.visaCardActivationStatus !is VisaCardActivationStatus.Activated
+ }
+
response.cardTypesResolver.isTangemTwins() -> {
if (!response.twinsIsTwinned()) {
true
@@ -68,7 +75,8 @@ object OnboardingHelper {
fun whereToNavigate(scanResponse: ScanResponse): AppRoute {
val newOnboardingSupportTypes = scanResponse.productType == ProductType.Wallet2 ||
scanResponse.productType == ProductType.Ring ||
- scanResponse.productType == ProductType.Wallet // AppRoute.OnboardingOther is also supported
+ scanResponse.productType == ProductType.Wallet ||
+ scanResponse.productType == ProductType.Visa // AppRoute.OnboardingOther is also supported
if (store.inject(DaggerGraphState::onboardingV2FeatureToggles).isOnboardingV2Enabled &&
newOnboardingSupportTypes
) {
diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/OutsetBorder.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/OutsetBorder.kt
new file mode 100644
index 0000000000..8dfc3ecd52
--- /dev/null
+++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/OutsetBorder.kt
@@ -0,0 +1,42 @@
+package com.tangem.core.ui.extensions
+
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithCache
+import androidx.compose.ui.geometry.CornerRadius
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.isSimple
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Outline
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.unit.Dp
+
+/**
+ * Modifier that adds an outset border to the content.
+ * @see [androidx.compose.foundation.border]
+ *
+ * @param width The width of the border.
+ * @param color The color of the border.
+ * @param shape The shape of the border.
+ */
+fun Modifier.outsetBorder(width: Dp, color: Color, shape: Shape) = drawWithCache {
+ val outline = shape.createOutline(size, layoutDirection, this)
+ val cornerRadius = when {
+ outline is Outline.Rounded && outline.roundRect.isSimple -> outline.roundRect.topLeftCornerRadius
+ else -> CornerRadius.Zero
+ }
+
+ onDrawWithContent {
+ drawContent()
+ drawRoundRect(
+ color = color,
+ topLeft = Offset(-width.toPx() / 2, -width.toPx() / 2),
+ size = size.copy(
+ width = size.width + width.toPx(),
+ height = size.height + width.toPx(),
+ ),
+ cornerRadius = cornerRadius,
+ style = Stroke(width = width.toPx()),
+ )
+ }
+}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/tangem/core/ui/security/DisableScreenshots.kt b/core/ui/src/main/java/com/tangem/core/ui/security/DisableScreenshots.kt
new file mode 100644
index 0000000000..4a421ead77
--- /dev/null
+++ b/core/ui/src/main/java/com/tangem/core/ui/security/DisableScreenshots.kt
@@ -0,0 +1,24 @@
+package com.tangem.core.ui.security
+
+import android.view.WindowManager
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.ui.platform.LocalContext
+import com.tangem.core.ui.utils.findActivity
+
+/**
+ * Disables screenshots for the current composition.
+ */
+@Composable
+fun DisableScreenshotsDisposableEffect() {
+ val activity = LocalContext.current.findActivity()
+ DisposableEffect(activity) {
+ activity.window.setFlags(
+ WindowManager.LayoutParams.FLAG_SECURE,
+ WindowManager.LayoutParams.FLAG_SECURE,
+ )
+ onDispose {
+ activity.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/ContextUtils.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/ContextUtils.kt
new file mode 100644
index 0000000000..576cf1f08a
--- /dev/null
+++ b/core/ui/src/main/java/com/tangem/core/ui/utils/ContextUtils.kt
@@ -0,0 +1,14 @@
+package com.tangem.core.ui.utils
+
+import android.app.Activity
+import android.content.Context
+import android.content.ContextWrapper
+
+fun Context.findActivity(): Activity {
+ var context = this
+ while (context is ContextWrapper) {
+ if (context is Activity) return context
+ context = context.baseContext
+ }
+ error("Cannot find activity. Please make sure that the context is attached to an activity.")
+}
\ No newline at end of file
diff --git a/core/ui/src/main/res/drawable/ic_loader.xml b/core/ui/src/main/res/drawable/ic_loader.xml
new file mode 100644
index 0000000000..5c61f9a912
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_loader.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/core/ui/src/main/res/drawable/ic_tangem_card_grey.xml b/core/ui/src/main/res/drawable/ic_tangem_card_grey.xml
new file mode 100644
index 0000000000..fb390ee999
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_tangem_card_grey.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/core/ui/src/main/res/drawable/ic_wallet_filled_24.xml b/core/ui/src/main/res/drawable/ic_wallet_filled_24.xml
new file mode 100644
index 0000000000..c2e83ec569
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_wallet_filled_24.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/core/ui/src/main/res/drawable/img_card_visa.webp b/core/ui/src/main/res/drawable/img_card_visa.webp
index bd2804ca99..f51b3d8f95 100644
Binary files a/core/ui/src/main/res/drawable/img_card_visa.webp and b/core/ui/src/main/res/drawable/img_card_visa.webp differ
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt
index ef564c6194..281ec29e57 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/model/OnboardingEntryModel.kt
@@ -72,6 +72,7 @@ internal class OnboardingEntryModel @Inject constructor(
ProductType.Visa -> OnboardingRoute.Visa(
scanResponse = scanResponse,
titleProvider = titleProvider,
+ onDone = ::onVisaOnboardingDone,
)
else -> error("Unsupported")
}
@@ -89,6 +90,12 @@ internal class OnboardingEntryModel @Inject constructor(
}
}
+ private fun onVisaOnboardingDone() {
+ stackNavigation.navigate {
+ listOf(OnboardingRoute.Done(onDone = ::navigateToWalletScreen))
+ }
+ }
+
private fun navigateToWalletScreen() {
modelScope.launch(NonCancellable) {
router.replaceAll(AppRoute.Wallet)
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/routing/OnboardingChildFactory.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/routing/OnboardingChildFactory.kt
index a7488de99a..6e614deefd 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/routing/OnboardingChildFactory.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/routing/OnboardingChildFactory.kt
@@ -31,6 +31,7 @@ internal class OnboardingChildFactory @Inject constructor(
params = OnboardingVisaComponent.Params(
scanResponse = route.scanResponse,
titleProvider = route.titleProvider,
+ onDone = route.onDone,
),
)
is OnboardingRoute.ManageTokens -> onboardingManageTokensComponentFactory.create(
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/routing/OnboardingRoute.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/routing/OnboardingRoute.kt
index 090724dff0..69778da3b4 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/routing/OnboardingRoute.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/routing/OnboardingRoute.kt
@@ -21,6 +21,7 @@ sealed class OnboardingRoute : Route {
data class Visa(
val titleProvider: TitleProvider,
val scanResponse: ScanResponse,
+ val onDone: () -> Unit,
) : OnboardingRoute()
data class ManageTokens(
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt
index 6e7321f878..51bf2171ca 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/DefaultOnboardingMultiWalletComponent.kt
@@ -54,7 +54,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
private val model: OnboardingMultiWalletModel = getOrCreateModel(params)
private val stackNavigation = StackNavigation()
- private val artworksState = instanceKeeper.getOrCreateSimple {
+ private val artworksState = instanceKeeper.getOrCreateSimple(key = "artworksState") {
MutableStateFlow(
when (model.state.value.currentStep) {
CreateWallet -> WalletArtworksState.Folded
@@ -68,9 +68,11 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor
)
}
- private val innerNavigationStateFlow = MutableStateFlow(
- MultiWalletInnerNavigationState(1, 5),
- )
+ private val innerNavigationStateFlow = instanceKeeper.getOrCreateSimple(key = "innerNavigationState") {
+ MutableStateFlow(
+ MultiWalletInnerNavigationState(1, 5),
+ )
+ }
private val childParams = MultiWalletChildParams(
multiWalletState = model.state,
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/MultiWalletSeedPhraseComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/MultiWalletSeedPhraseComponent.kt
index 2a9df6122b..6e6722ddb7 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/MultiWalletSeedPhraseComponent.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/MultiWalletSeedPhraseComponent.kt
@@ -1,19 +1,14 @@
package com.tangem.features.onboarding.v2.multiwallet.impl.child.seedphrase
-import android.app.Activity
-import android.content.Context
-import android.content.ContextWrapper
-import android.view.WindowManager
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.security.DisableScreenshotsDisposableEffect
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildComponent
import com.tangem.features.onboarding.v2.multiwallet.impl.child.MultiWalletChildParams
@@ -79,30 +74,11 @@ internal class MultiWalletSeedPhraseComponent(
model.onBack()
}
- // disable screenshots
- val activity = LocalContext.current.findActivity()
- DisposableEffect(activity) {
- activity.window.setFlags(
- WindowManager.LayoutParams.FLAG_SECURE,
- WindowManager.LayoutParams.FLAG_SECURE,
- )
- onDispose {
- activity.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
- }
- }
+ DisableScreenshotsDisposableEffect()
MultiWalletSeedPhrase(
modifier = modifier,
state = state,
)
}
-
- private fun Context.findActivity(): Activity {
- var context = this
- while (context is ContextWrapper) {
- if (context is Activity) return context
- context = context.baseContext
- }
- error("")
- }
}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/api/OnboardingVisaComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/api/OnboardingVisaComponent.kt
index 19cf83fac8..6aa983e077 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/api/OnboardingVisaComponent.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/api/OnboardingVisaComponent.kt
@@ -11,6 +11,7 @@ interface OnboardingVisaComponent : ComposableContentComponent, InnerNavigationH
data class Params(
val scanResponse: ScanResponse,
val titleProvider: TitleProvider,
+ val onDone: () -> Unit,
)
interface Factory : ComponentFactory
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/DefaultOnboardingVisaComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/DefaultOnboardingVisaComponent.kt
index 67982e4535..4f5b70b7a8 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/DefaultOnboardingVisaComponent.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/DefaultOnboardingVisaComponent.kt
@@ -1,15 +1,34 @@
package com.tangem.features.onboarding.v2.visa.impl
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import com.arkivanov.decompose.extensions.compose.jetpack.stack.Children
+import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.slide
+import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation
+import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState
+import com.arkivanov.decompose.router.stack.*
+import com.arkivanov.decompose.value.Value
+import com.arkivanov.essenty.instancekeeper.getOrCreateSimple
import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.context.childByContext
+import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.decompose.navigation.inner.InnerNavigation
import com.tangem.core.decompose.navigation.inner.InnerNavigationState
+import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.onboarding.v2.visa.api.OnboardingVisaComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.OnboardingVisaAccessCodeComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.approve.OnboardingVisaApproveComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.OnboardingVisaChooseWalletComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.inprogress.OnboardingVisaInProgressComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.OnboardingVisaOtherWalletComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.pincode.OnboardingVisaPinCodeComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.welcome.OnboardingVisaWelcomeComponent
+import com.tangem.features.onboarding.v2.visa.impl.model.OnboardingVisaModel
+import com.tangem.features.onboarding.v2.visa.impl.route.OnboardingVisaRoute
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -21,27 +40,144 @@ internal class DefaultOnboardingVisaComponent @AssistedInject constructor(
@Assisted private val params: OnboardingVisaComponent.Params,
) : OnboardingVisaComponent, AppComponentContext by appComponentContext {
- private val innerNavigationState = MutableStateFlow(
- OnboardingVisaInnerNavigationState(
- stackSize = 1,
- stackMaxSize = 7,
- ),
- )
+ private val model: OnboardingVisaModel = getOrCreateModel(params)
- private val currentChildBackEventHandle = MutableSharedFlow(onBufferOverflow = BufferOverflow.DROP_LATEST)
+ private val innerNavigationState = instanceKeeper.getOrCreateSimple(key = "innerNavigationState") {
+ MutableStateFlow(
+ OnboardingVisaInnerNavigationState(
+ stackSize = 1,
+ stackMaxSize = 7,
+ ),
+ )
+ }
+
+ private val currentChildBackEventHandle = instanceKeeper.getOrCreateSimple(key = "currentChildBackEventHandle") {
+ MutableSharedFlow()
+ }
+
+ private val stackNavigation = StackNavigation()
+
+ private val childStack: Value> =
+ childStack(
+ key = "innerStack",
+ source = stackNavigation,
+ serializer = null,
+ initialConfiguration = model.initialRoute,
+ handleBackButton = true,
+ childFactory = { configuration, factoryContext ->
+ createChild(
+ configuration,
+ childByContext(factoryContext),
+ )
+ },
+ )
override val innerNavigation: InnerNavigation = object : InnerNavigation {
override val state: StateFlow = innerNavigationState
override fun pop(onComplete: (Boolean) -> Unit) {
- // TODO add stack handling
- componentScope.launch { currentChildBackEventHandle.emit(Unit) }
+ if (childStack.value.active.configuration is OnboardingVisaRoute.AccessCode) {
+ componentScope.launch { currentChildBackEventHandle.emit(Unit) }
+ } else {
+ stackNavigation.pop()
+ }
+ }
+ }
+
+ private fun createChild(
+ route: OnboardingVisaRoute,
+ factoryContext: AppComponentContext,
+ ): ComposableContentComponent {
+ return when (route) {
+ is OnboardingVisaRoute.Welcome -> OnboardingVisaWelcomeComponent(
+ appComponentContext = factoryContext,
+ params = OnboardingVisaWelcomeComponent.Params(
+ isWelcomeBack = route.isWelcomeBack,
+ onBack = ::onChildBack,
+ onDone = { stackNavigation.push(OnboardingVisaRoute.AccessCode) },
+ ),
+ )
+ OnboardingVisaRoute.AccessCode -> OnboardingVisaAccessCodeComponent(
+ appComponentContext = factoryContext,
+ params = OnboardingVisaAccessCodeComponent.Params(
+ onBack = ::onChildBack,
+ parentBackEvent = currentChildBackEventHandle,
+ onDone = { stackNavigation.push(OnboardingVisaRoute.ChooseWallet) },
+ ),
+ )
+ OnboardingVisaRoute.ChooseWallet -> OnboardingVisaChooseWalletComponent(
+ appComponentContext = factoryContext,
+ params = OnboardingVisaChooseWalletComponent.Params(
+ onBack = ::onChildBack,
+ onEvent = { event ->
+ stackNavigation.push(
+ when (event) {
+ OnboardingVisaChooseWalletComponent.Params.Event.TangemWallet ->
+ OnboardingVisaRoute.TangemWalletApproveOption
+ OnboardingVisaChooseWalletComponent.Params.Event.OtherWallet ->
+ OnboardingVisaRoute.OtherWalletApproveOption
+ },
+ )
+ },
+ ),
+ )
+ OnboardingVisaRoute.InProgress -> OnboardingVisaInProgressComponent(
+ appComponentContext = factoryContext,
+ params = OnboardingVisaInProgressComponent.Params(
+ onBack = ::onChildBack,
+ onDone = { stackNavigation.push(OnboardingVisaRoute.PinCode) },
+ ),
+ )
+ OnboardingVisaRoute.OtherWalletApproveOption -> OnboardingVisaOtherWalletComponent(
+ appComponentContext = factoryContext,
+ params = OnboardingVisaOtherWalletComponent.Params(
+ onBack = ::onChildBack,
+ onDone = { stackNavigation.push(OnboardingVisaRoute.InProgress) },
+ ),
+ )
+ OnboardingVisaRoute.PinCode -> OnboardingVisaPinCodeComponent(
+ appComponentContext = factoryContext,
+ params = OnboardingVisaPinCodeComponent.Params(
+ onBack = ::onChildBack,
+ onDone = { params.onDone() },
+ ),
+ )
+ OnboardingVisaRoute.TangemWalletApproveOption -> OnboardingVisaApproveComponent(
+ appComponentContext = factoryContext,
+ params = OnboardingVisaApproveComponent.Params(
+ onBack = ::onChildBack,
+ onDone = { stackNavigation.push(OnboardingVisaRoute.InProgress) },
+ ),
+ )
+ }
+ }
+
+ private fun onChildBack() {
+ when (childStack.value.active.configuration) {
+ OnboardingVisaRoute.AccessCode,
+ OnboardingVisaRoute.TangemWalletApproveOption,
+ OnboardingVisaRoute.OtherWalletApproveOption,
+ -> stackNavigation.pop()
+ is OnboardingVisaRoute.Welcome,
+ OnboardingVisaRoute.ChooseWallet,
+ OnboardingVisaRoute.InProgress,
+ OnboardingVisaRoute.OtherWalletApproveOption,
+ OnboardingVisaRoute.PinCode,
+ -> {
+ }
}
}
@Composable
override fun Content(modifier: Modifier) {
- TODO("Not yet implemented")
+ val stackState by childStack.subscribeAsState()
+
+ Children(
+ stack = stackState,
+ animation = stackAnimation(slide()),
+ ) {
+ it.instance.Content(modifier)
+ }
}
@AssistedFactory
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/OnboardingVisaAccessCodeComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/OnboardingVisaAccessCodeComponent.kt
index 5ffff0e28f..06faafcbd7 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/OnboardingVisaAccessCodeComponent.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/OnboardingVisaAccessCodeComponent.kt
@@ -8,6 +8,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableContentComponent
+import com.tangem.core.ui.security.DisableScreenshotsDisposableEffect
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.model.OnboardingVisaAccessCodeModel
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui.OnboardingVisaAccessCode
import kotlinx.coroutines.flow.SharedFlow
@@ -29,6 +30,9 @@ internal class OnboardingVisaAccessCodeComponent(
model.onBack()
}
}
+ componentScope.launch {
+ model.onDone.collect { params.onDone() }
+ }
}
@Composable
@@ -37,11 +41,14 @@ internal class OnboardingVisaAccessCodeComponent(
BackHandler(onBack = model::onBack)
+ DisableScreenshotsDisposableEffect()
+
OnboardingVisaAccessCode(state, modifier)
}
data class Params(
val parentBackEvent: SharedFlow,
val onBack: () -> Unit,
+ val onDone: () -> Unit,
)
}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt
index 24d171ebb9..4281e33a1a 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/model/OnboardingVisaAccessCodeModel.kt
@@ -1,6 +1,7 @@
package com.tangem.features.onboarding.v2.visa.impl.child.accesscode.model
import androidx.compose.runtime.Stable
+import androidx.compose.ui.text.input.TextFieldValue
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui.state.OnboardingVisaAccessCodeUM
@@ -14,12 +15,14 @@ import javax.inject.Inject
@ComponentScoped
internal class OnboardingVisaAccessCodeModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
+ @Suppress("UnusedPrivateMember")
private val tangemSdkManager: TangemSdkManager,
) : Model() {
private val _uiState = MutableStateFlow(getInitialState())
val uiState = _uiState.asStateFlow()
val onBack = MutableSharedFlow()
+ val onDone = MutableSharedFlow()
fun onBack() {
when (uiState.value.step) {
@@ -31,64 +34,90 @@ internal class OnboardingVisaAccessCodeModel @Inject constructor(
private fun getInitialState(): OnboardingVisaAccessCodeUM {
return OnboardingVisaAccessCodeUM(
- onAccessCodeFirstChange = { _uiState.update { it.copy(accessCodeFirst = it.accessCodeFirst) } },
- onAccessCodeSecondChange = { _uiState.update { it.copy(accessCodeSecond = it.accessCodeSecond) } },
+ onAccessCodeFirstChange = ::onAccessCodeFirstChange,
+ onAccessCodeSecondChange = ::onAccessCodeSecondChange,
onAccessCodeHideClick = { _uiState.update { it.copy(accessCodeHidden = !it.accessCodeHidden) } },
onContinue = { onContinue() },
)
}
- private fun onContinue() {
- if (checkAccessCode().not()) return
+ private fun onAccessCodeFirstChange(textFieldValue: TextFieldValue) {
+ _uiState.update {
+ it.copy(
+ accessCodeFirst = textFieldValue,
+ atLeastMinCharsError = false,
+ )
+ }
+ }
+ private fun onAccessCodeSecondChange(textFieldValue: TextFieldValue) {
+ _uiState.update {
+ it.copy(
+ accessCodeSecond = textFieldValue,
+ codesNotMatchError = false,
+ )
+ }
+ }
+
+ private fun onContinue() {
when (uiState.value.step) {
OnboardingVisaAccessCodeUM.Step.Enter -> {
+ if (checkAccessCodeMinChars().not()) return
_uiState.update { it.copy(step = OnboardingVisaAccessCodeUM.Step.ReEnter) }
}
OnboardingVisaAccessCodeUM.Step.ReEnter -> {
+ if (checkAccessCodesMatch().not()) return
startActivationProcess(accessCode = uiState.value.accessCodeFirst.text)
}
}
}
- private fun checkAccessCode(): Boolean {
+ private fun checkAccessCodeMinChars(): Boolean {
val first = uiState.value.accessCodeFirst.text
- val second = uiState.value.accessCodeSecond.text
- when {
- first.length < ACCESS_CODE_MIN_LENGTH -> {
- _uiState.update { it.copy(atLeastMinCharsError = true) }
- return false
- }
- first != second -> {
- _uiState.update { it.copy(codesNotMatchError = true) }
- return false
- }
+ if (first.length < ACCESS_CODE_MIN_LENGTH) {
+ _uiState.update { it.copy(atLeastMinCharsError = true) }
+ return false
}
return true
}
- private fun startActivationProcess(accessCode: String) {
- modelScope.launch {
- @Suppress("UnusedPrivateMember")
- val result = tangemSdkManager.activateVisaCard(
- accessCode = accessCode,
- challengeToSign = null,
- activationInput = TODO(),
- )
+ private fun checkAccessCodesMatch(): Boolean {
+ val first = uiState.value.accessCodeFirst.text
+ val second = uiState.value.accessCodeSecond.text
- // when (result) {
- // is CompletionResult.Success -> {
- // val response = result.data
- // TODO()
- // }
- // is CompletionResult.Failure -> {
- // // show alert
- // TODO()
- // }
- // }
+ if (first != second) {
+ _uiState.update { it.copy(codesNotMatchError = true) }
+ return false
}
+
+ return true
+ }
+
+ @Suppress("UnusedPrivateMember")
+ private fun startActivationProcess(accessCode: String) {
+ modelScope.launch { onDone.emit(Unit) }
+
+ // modelScope.launch {
+ // @Suppress("UnusedPrivateMember")
+ // val result = tangemSdkManager.activateVisaCard(
+ // accessCode = accessCode,
+ // challengeToSign = null,
+ // activationInput = TODO(),
+ // )
+ //
+ // when (result) {
+ // is CompletionResult.Success -> {
+ // val response = result.data
+ // TODO()
+ // }
+ // is CompletionResult.Failure -> {
+ // // show alert
+ // TODO()
+ // }
+ // }
+ // }
}
private companion object {
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/ui/OnboardingVisaAccessCode.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/ui/OnboardingVisaAccessCode.kt
index f5c8364420..6fefcee506 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/ui/OnboardingVisaAccessCode.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/ui/OnboardingVisaAccessCode.kt
@@ -43,7 +43,7 @@ internal fun OnboardingVisaAccessCode(state: OnboardingVisaAccessCodeUM, modifie
.weight(1f),
targetState = state.step,
transitionSpec = TangemAnimations.AnimatedContent
- .slide { initial, target -> initial.ordinal < target.ordinal },
+ .slide { initial, target -> initial.ordinal > target.ordinal },
) { step ->
Content(
state = state,
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/ui/state/OnboardingVisaAccessCodeUM.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/ui/state/OnboardingVisaAccessCodeUM.kt
index 0cf7770ac0..b707b9067c 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/ui/state/OnboardingVisaAccessCodeUM.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/accesscode/ui/state/OnboardingVisaAccessCodeUM.kt
@@ -2,7 +2,7 @@ package com.tangem.features.onboarding.v2.visa.impl.child.accesscode.ui.state
import androidx.compose.ui.text.input.TextFieldValue
-data class OnboardingVisaAccessCodeUM(
+internal data class OnboardingVisaAccessCodeUM(
val step: Step = Step.Enter,
val accessCodeFirst: TextFieldValue = TextFieldValue(""),
val accessCodeSecond: TextFieldValue = TextFieldValue(""),
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/OnboardingVisaApproveComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/OnboardingVisaApproveComponent.kt
new file mode 100644
index 0000000000..70a5560fc0
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/OnboardingVisaApproveComponent.kt
@@ -0,0 +1,45 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.approve
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.model.getOrCreateModel
+import com.tangem.core.ui.decompose.ComposableContentComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.approve.model.OnboardingVisaApproveModel
+import com.tangem.features.onboarding.v2.visa.impl.child.approve.ui.OnboardingVisaApprove
+import kotlinx.coroutines.launch
+
+internal class OnboardingVisaApproveComponent(
+ appComponentContext: AppComponentContext,
+ private val params: Params,
+) : ComposableContentComponent, AppComponentContext by appComponentContext {
+
+ private val model: OnboardingVisaApproveModel = getOrCreateModel()
+
+ init {
+ componentScope.launch {
+ model.onDone.collect { params.onDone() }
+ }
+ }
+
+ @Composable
+ override fun Content(modifier: Modifier) {
+ val state by model.uiState.collectAsStateWithLifecycle()
+
+ BackHandler(onBack = remember(this) { { params.onBack() } })
+
+ OnboardingVisaApprove(
+ state = state,
+ modifier = modifier,
+ )
+ }
+
+ data class Params(
+ val onBack: () -> Unit,
+ val onDone: () -> Unit,
+ )
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/model/OnboardingVisaApproveModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/model/OnboardingVisaApproveModel.kt
new file mode 100644
index 0000000000..11bd07d94b
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/model/OnboardingVisaApproveModel.kt
@@ -0,0 +1,35 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.approve.model
+
+import androidx.compose.runtime.Stable
+import com.tangem.core.decompose.di.ComponentScoped
+import com.tangem.core.decompose.model.Model
+import com.tangem.features.onboarding.v2.visa.impl.child.approve.ui.state.OnboardingVisaApproveUM
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@Stable
+@ComponentScoped
+internal class OnboardingVisaApproveModel @Inject constructor(
+ override val dispatchers: CoroutineDispatcherProvider,
+) : Model() {
+
+ private val _uiState = MutableStateFlow(getInitialState())
+
+ val uiState = _uiState.asStateFlow()
+ val onDone = MutableSharedFlow()
+
+ private fun getInitialState(): OnboardingVisaApproveUM {
+ return OnboardingVisaApproveUM(
+ onApproveClick = ::onApproveClick,
+ )
+ }
+
+ private fun onApproveClick() {
+ // TODO
+ modelScope.launch { onDone.emit(Unit) }
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/ui/OnboardingVisaApprove.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/ui/OnboardingVisaApprove.kt
new file mode 100644
index 0000000000..bc1b5f0ff9
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/ui/OnboardingVisaApprove.kt
@@ -0,0 +1,83 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.approve.ui
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.tangem.common.ui.navigationButtons.NavigationButton
+import com.tangem.common.ui.navigationButtons.NavigationPrimaryButton
+import com.tangem.core.ui.components.SpacerH
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.features.onboarding.v2.impl.R
+import com.tangem.features.onboarding.v2.visa.impl.child.approve.ui.state.OnboardingVisaApproveUM
+
+@Composable
+internal fun OnboardingVisaApprove(state: OnboardingVisaApproveUM, modifier: Modifier = Modifier) {
+ Column(
+ modifier
+ .fillMaxSize()
+ .navigationBarsPadding(),
+ ) {
+ Column(
+ modifier = Modifier
+ .weight(1f)
+ .padding(top = 56.dp, bottom = 32.dp)
+ .padding(horizontal = 34.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Image(
+ imageVector = ImageVector.vectorResource(R.drawable.ic_tangem_card_grey),
+ contentDescription = null,
+ modifier = Modifier.fillMaxWidth(),
+ )
+
+ SpacerH(86.dp)
+
+ Text(
+ text = "Prepare Tangem Wallet",
+ style = TangemTheme.typography.h2,
+ color = TangemTheme.colors.text.primary1,
+ textAlign = TextAlign.Center,
+ )
+
+ SpacerH(12.dp)
+
+ Text(
+ text = "Prepare the Tangem card\nand tap to approve",
+ style = TangemTheme.typography.body1,
+ color = TangemTheme.colors.text.secondary,
+ textAlign = TextAlign.Center,
+ )
+ }
+
+ NavigationPrimaryButton(
+ modifier = Modifier
+ .imePadding()
+ .padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
+ .fillMaxWidth(),
+ primaryButton = NavigationButton(
+ textReference = TextReference.Str("Approve"),
+ iconRes = R.drawable.ic_tangem_24,
+ isIconVisible = true,
+ onClick = state.onApproveClick,
+ ),
+ )
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun Preview() {
+ TangemThemePreview {
+ OnboardingVisaApprove(state = OnboardingVisaApproveUM())
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/ui/state/OnboardingVisaApproveUM.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/ui/state/OnboardingVisaApproveUM.kt
new file mode 100644
index 0000000000..90bb2ef920
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/approve/ui/state/OnboardingVisaApproveUM.kt
@@ -0,0 +1,5 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.approve.ui.state
+
+internal data class OnboardingVisaApproveUM(
+ val onApproveClick: () -> Unit = {},
+)
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/OnboardingVisaChooseWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/OnboardingVisaChooseWalletComponent.kt
new file mode 100644
index 0000000000..f8310b209e
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/OnboardingVisaChooseWalletComponent.kt
@@ -0,0 +1,50 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.choosewallet
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.model.getOrCreateModel
+import com.tangem.core.ui.decompose.ComposableContentComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.model.OnboardingVisaChooseWalletModel
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui.OnboardingVisaChooseWallet
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+
+internal class OnboardingVisaChooseWalletComponent(
+ appComponentContext: AppComponentContext,
+ private val params: Params,
+) : ComposableContentComponent, AppComponentContext by appComponentContext {
+
+ private val model: OnboardingVisaChooseWalletModel = getOrCreateModel()
+
+ init {
+ model.onEvent
+ .onEach { params.onEvent(it) }
+ .launchIn(componentScope)
+ }
+
+ @Composable
+ override fun Content(modifier: Modifier) {
+ val state by model.uiState.collectAsStateWithLifecycle()
+
+ BackHandler(onBack = remember(this) { { params.onBack() } })
+
+ OnboardingVisaChooseWallet(
+ modifier = modifier,
+ state = state,
+ )
+ }
+
+ data class Params(
+ val onBack: () -> Unit,
+ val onEvent: (Event) -> Unit,
+ ) {
+ enum class Event {
+ TangemWallet, OtherWallet
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/model/OnboardingVisaChooseWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/model/OnboardingVisaChooseWalletModel.kt
new file mode 100644
index 0000000000..4f6629cae9
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/model/OnboardingVisaChooseWalletModel.kt
@@ -0,0 +1,59 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.model
+
+import androidx.compose.runtime.Stable
+import com.tangem.core.decompose.di.ComponentScoped
+import com.tangem.core.decompose.model.Model
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.features.onboarding.v2.impl.R
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.OnboardingVisaChooseWalletComponent.Params.Event
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui.state.OnboardingVisaChooseWalletUM
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui.state.SelectableChainRowUM
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.collections.immutable.persistentListOf
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@Stable
+@ComponentScoped
+internal class OnboardingVisaChooseWalletModel @Inject constructor(
+ override val dispatchers: CoroutineDispatcherProvider,
+) : Model() {
+
+ private val _uiState = MutableStateFlow(getInitialState())
+
+ val onEvent = MutableSharedFlow()
+ val uiState = _uiState.asStateFlow()
+
+ private fun getInitialState(): OnboardingVisaChooseWalletUM {
+ val selectedOption = SelectableChainRowUM(
+ event = Event.TangemWallet,
+ icon = R.drawable.ic_tangem_24,
+ text = TextReference.Str("Tangem Wallet"),
+ )
+
+ return OnboardingVisaChooseWalletUM(
+ options = persistentListOf(
+ selectedOption,
+ SelectableChainRowUM(
+ event = Event.OtherWallet,
+ icon = R.drawable.ic_wallet_filled_24,
+ text = TextReference.Str("Other Wallet"),
+ ),
+ ),
+ selectedOption = selectedOption,
+ onOptionSelected = { option -> _uiState.update { it.copy(selectedOption = option) } },
+ onContinueClick = ::onContinueClicked,
+ )
+ }
+
+ private fun onContinueClicked() {
+ modelScope.launch {
+ val selectedOption = _uiState.value.selectedOption ?: return@launch
+ onEvent.emit(selectedOption.event)
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/ui/OnboardingVisaChooseWallet.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/ui/OnboardingVisaChooseWallet.kt
new file mode 100644
index 0000000000..b44e28c2c6
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/ui/OnboardingVisaChooseWallet.kt
@@ -0,0 +1,174 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui
+
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.tangem.core.ui.components.PrimaryButton
+import com.tangem.core.ui.components.notifications.Notification
+import com.tangem.core.ui.components.notifications.NotificationConfig
+import com.tangem.core.ui.components.rows.RowContentContainer
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.extensions.outsetBorder
+import com.tangem.core.ui.extensions.resolveReference
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.features.onboarding.v2.impl.R
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.OnboardingVisaChooseWalletComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui.state.OnboardingVisaChooseWalletUM
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui.state.SelectableChainRowUM
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.persistentListOf
+
+@Composable
+internal fun OnboardingVisaChooseWallet(state: OnboardingVisaChooseWalletUM, modifier: Modifier = Modifier) {
+ Column(
+ modifier
+ .fillMaxSize()
+ .navigationBarsPadding(),
+ ) {
+ Column(
+ Modifier
+ .weight(1f)
+ .padding(top = 12.dp)
+ .padding(horizontal = 16.dp),
+ ) {
+ Notification(
+ config = NotificationConfig(
+ subtitle = TextReference.Str(
+ "Please choose the wallet you started the registration" +
+ " process with to sign the transaction for creating your account on the Blockchain.",
+ ),
+ iconResId = R.drawable.ic_alert_circle_24,
+ ),
+ iconTint = TangemTheme.colors.icon.accent,
+ )
+
+ Text(
+ modifier = Modifier
+ .padding(
+ top = 12.dp,
+ bottom = 8.dp,
+ start = 12.dp,
+ end = 12.dp,
+ ),
+ text = "Choose wallet",
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+
+ SelectableChainRows(
+ items = state.options,
+ selected = state.selectedOption,
+ onClick = state.onOptionSelected,
+ )
+ }
+
+ PrimaryButton(
+ modifier = Modifier
+ .imePadding()
+ .padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
+ .fillMaxWidth(),
+ text = "Continue",
+ onClick = state.onContinueClick,
+ )
+ }
+}
+
+@Composable
+private fun SelectableChainRows(
+ items: ImmutableList,
+ selected: SelectableChainRowUM?,
+ onClick: (SelectableChainRowUM) -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Column(modifier) {
+ items.forEach { item ->
+ SelectableChainRow(
+ state = item,
+ selected = item == selected,
+ onClick = { onClick(item) },
+ )
+ }
+ }
+}
+
+@Composable
+private fun SelectableChainRow(
+ state: SelectableChainRowUM,
+ selected: Boolean,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ RowContentContainer(
+ modifier = modifier
+ .heightIn(min = 48.dp)
+ .outsetBorder(
+ color = if (selected) TangemTheme.colors.icon.accent.copy(alpha = 0.15f) else Color.Transparent,
+ width = 5.dp,
+ shape = RoundedCornerShape(size = 18.dp),
+ )
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .border(
+ width = 1.dp,
+ color = if (selected) TangemTheme.colors.icon.accent else Color.Transparent,
+ shape = TangemTheme.shapes.roundedCornersXMedium,
+ )
+ .clickable(onClick = onClick)
+ .padding(12.dp),
+ icon = {
+ Icon(
+ imageVector = ImageVector.vectorResource(id = state.icon),
+ tint = if (selected) TangemTheme.colors.icon.primary1 else TangemTheme.colors.icon.informative,
+ contentDescription = null,
+ )
+ },
+ text = {
+ Text(
+ text = state.text.resolveReference(),
+ style = TangemTheme.typography.button,
+ color = if (selected) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.secondary,
+ )
+ },
+ action = {},
+ horizontalArrangement = Arrangement.spacedBy(12.dp),
+ )
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun Preview() {
+ TangemThemePreview {
+ OnboardingVisaChooseWallet(
+ state = OnboardingVisaChooseWalletUM(
+ options = persistentListOf(
+ SelectableChainRowUM(
+ event = OnboardingVisaChooseWalletComponent.Params.Event.TangemWallet,
+ icon = R.drawable.ic_tangem_24,
+ text = TextReference.Str("Tangem Wallet"),
+ ),
+ SelectableChainRowUM(
+ event = OnboardingVisaChooseWalletComponent.Params.Event.OtherWallet,
+ icon = R.drawable.ic_wallet_filled_24,
+ text = TextReference.Str("Other Wallet"),
+ ),
+ ),
+ selectedOption = SelectableChainRowUM(
+ event = OnboardingVisaChooseWalletComponent.Params.Event.OtherWallet,
+ icon = R.drawable.ic_tangem_24,
+ text = TextReference.Str("Tangem Wallet"),
+ ),
+ ),
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/ui/state/OnboardingVisaChooseWalletUM.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/ui/state/OnboardingVisaChooseWalletUM.kt
new file mode 100644
index 0000000000..0281417755
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/ui/state/OnboardingVisaChooseWalletUM.kt
@@ -0,0 +1,11 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui.state
+
+import kotlinx.collections.immutable.ImmutableList
+import kotlinx.collections.immutable.persistentListOf
+
+internal data class OnboardingVisaChooseWalletUM(
+ val options: ImmutableList = persistentListOf(),
+ val selectedOption: SelectableChainRowUM? = null,
+ val onOptionSelected: (SelectableChainRowUM) -> Unit = {},
+ val onContinueClick: () -> Unit = {},
+)
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/ui/state/SelectableChainRowUM.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/ui/state/SelectableChainRowUM.kt
new file mode 100644
index 0000000000..dee93cf95f
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/choosewallet/ui/state/SelectableChainRowUM.kt
@@ -0,0 +1,11 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.ui.state
+
+import androidx.annotation.DrawableRes
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.OnboardingVisaChooseWalletComponent
+
+internal data class SelectableChainRowUM(
+ val event: OnboardingVisaChooseWalletComponent.Params.Event,
+ @DrawableRes val icon: Int,
+ val text: TextReference,
+)
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/OnboardingVisaInProgressComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/OnboardingVisaInProgressComponent.kt
new file mode 100644
index 0000000000..f1fca1c49b
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/OnboardingVisaInProgressComponent.kt
@@ -0,0 +1,41 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.inprogress
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.model.getOrCreateModel
+import com.tangem.core.ui.decompose.ComposableContentComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.inprogress.model.OnboardingVisaInProgressModel
+import com.tangem.features.onboarding.v2.visa.impl.child.inprogress.ui.OnboardingVisaInProgress
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+
+class OnboardingVisaInProgressComponent(
+ appComponentContext: AppComponentContext,
+ private val params: Params,
+) : ComposableContentComponent, AppComponentContext by appComponentContext {
+
+ private val model: OnboardingVisaInProgressModel = getOrCreateModel()
+
+ init {
+ model.onDone
+ .onEach { params.onDone() }
+ .launchIn(componentScope)
+ }
+
+ @Composable
+ override fun Content(modifier: Modifier) {
+ BackHandler(onBack = remember(this) { { params.onBack() } })
+
+ OnboardingVisaInProgress(
+ modifier = modifier,
+ )
+ }
+
+ data class Params(
+ val onBack: () -> Unit,
+ val onDone: () -> Unit,
+ )
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/model/OnboardingVisaInProgressModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/model/OnboardingVisaInProgressModel.kt
new file mode 100644
index 0000000000..9639c4ddc8
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/model/OnboardingVisaInProgressModel.kt
@@ -0,0 +1,27 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.inprogress.model
+
+import androidx.compose.runtime.Stable
+import com.tangem.core.decompose.di.ComponentScoped
+import com.tangem.core.decompose.model.Model
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@Stable
+@ComponentScoped
+internal class OnboardingVisaInProgressModel @Inject constructor(
+ override val dispatchers: CoroutineDispatcherProvider,
+) : Model() {
+
+ val onDone = MutableSharedFlow()
+
+ init {
+ modelScope.launch {
+ // TODO check state
+ delay(timeMillis = 2000)
+ onDone.emit(Unit)
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/ui/OnboardingVisaInProgress.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/ui/OnboardingVisaInProgress.kt
new file mode 100644
index 0000000000..d30e9a0b79
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/inprogress/ui/OnboardingVisaInProgress.kt
@@ -0,0 +1,37 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.inprogress.ui
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.navigationBarsPadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.tangem.core.ui.res.TangemThemePreview
+
+@Composable
+internal fun OnboardingVisaInProgress(modifier: Modifier = Modifier) {
+ Column(
+ modifier
+ .fillMaxSize()
+ .navigationBarsPadding(),
+ ) {
+ Column(
+ Modifier
+ .weight(1f)
+ .padding(top = 12.dp)
+ .padding(horizontal = 16.dp),
+ ) {
+ // TODO
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun Preview() {
+ TangemThemePreview {
+ OnboardingVisaInProgress()
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/OnboardingVisaOtherWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/OnboardingVisaOtherWalletComponent.kt
new file mode 100644
index 0000000000..50ca03977d
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/OnboardingVisaOtherWalletComponent.kt
@@ -0,0 +1,46 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.otherwallet
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.model.getOrCreateModel
+import com.tangem.core.ui.decompose.ComposableContentComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.model.OnboardingVisaOtherWalletModel
+import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.ui.OnboardingVisaOtherWallet
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+
+internal class OnboardingVisaOtherWalletComponent(
+ appComponentContext: AppComponentContext,
+ private val params: Params,
+) : ComposableContentComponent, AppComponentContext by appComponentContext {
+
+ private val model: OnboardingVisaOtherWalletModel = getOrCreateModel()
+
+ init {
+ model.onDone
+ .onEach { params.onDone() }
+ .launchIn(componentScope)
+ }
+
+ @Composable
+ override fun Content(modifier: Modifier) {
+ val state by model.uiState.collectAsStateWithLifecycle()
+
+ BackHandler(onBack = remember(this) { { params.onBack() } })
+
+ OnboardingVisaOtherWallet(
+ modifier = modifier,
+ state = state,
+ )
+ }
+
+ data class Params(
+ val onBack: () -> Unit,
+ val onDone: () -> Unit,
+ )
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/model/OnboardingVisaOtherWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/model/OnboardingVisaOtherWalletModel.kt
new file mode 100644
index 0000000000..42254b2c08
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/model/OnboardingVisaOtherWalletModel.kt
@@ -0,0 +1,38 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.model
+
+import androidx.compose.runtime.Stable
+import com.tangem.core.decompose.di.ComponentScoped
+import com.tangem.core.decompose.model.Model
+import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.ui.state.OnboardingVisaOtherWalletUM
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import javax.inject.Inject
+
+@Stable
+@ComponentScoped
+internal class OnboardingVisaOtherWalletModel @Inject constructor(
+ override val dispatchers: CoroutineDispatcherProvider,
+) : Model() {
+
+ private val _uiState = MutableStateFlow(getInitialState())
+
+ val uiState = _uiState.asStateFlow()
+ val onDone = MutableSharedFlow()
+
+ private fun getInitialState(): OnboardingVisaOtherWalletUM {
+ return OnboardingVisaOtherWalletUM(
+ onShareClick = ::onShareClicked,
+ onOpenInBrowserClick = ::onOpenInBrowserClicked,
+ )
+ }
+
+ private fun onShareClicked() {
+ // TODO
+ }
+
+ private fun onOpenInBrowserClicked() {
+ // TODO
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/ui/OnboardingVisaOtherWallet.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/ui/OnboardingVisaOtherWallet.kt
new file mode 100644
index 0000000000..4b0a8c2f3f
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/ui/OnboardingVisaOtherWallet.kt
@@ -0,0 +1,137 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.ui
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.tangem.core.ui.components.PrimaryButton
+import com.tangem.core.ui.components.SecondaryButton
+import com.tangem.core.ui.components.SpacerH12
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.features.onboarding.v2.impl.R
+import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.ui.state.OnboardingVisaOtherWalletUM
+
+@Composable
+internal fun OnboardingVisaOtherWallet(state: OnboardingVisaOtherWalletUM, modifier: Modifier = Modifier) {
+ Column(
+ modifier
+ .fillMaxSize()
+ .navigationBarsPadding(),
+ ) {
+ Box(
+ modifier = Modifier
+ .weight(1f)
+ .padding(top = 12.dp, bottom = 32.dp)
+ .padding(horizontal = 16.dp),
+ contentAlignment = Alignment.Center,
+ ) {
+ Column(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ IconBlock()
+
+ SpacerH12()
+
+ Text(
+ text = "Go to Website",
+ style = TangemTheme.typography.h2,
+ color = TangemTheme.colors.text.primary1,
+ textAlign = TextAlign.Center,
+ )
+
+ SpacerH12()
+
+ Text(
+ text = "You will be able to complete your connection \n" +
+ "on the third-party web-site \n" +
+ "and back to the Tangem app",
+ style = TangemTheme.typography.body1,
+ color = TangemTheme.colors.text.secondary,
+ textAlign = TextAlign.Center,
+ )
+ }
+ }
+
+ Column {
+ PrimaryButton(
+ modifier = Modifier
+ .padding(horizontal = 16.dp)
+ .fillMaxWidth(),
+ text = "Open in Browser",
+ onClick = state.onOpenInBrowserClick,
+ )
+
+ SpacerH12()
+
+ SecondaryButton(
+ modifier = Modifier
+ .padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
+ .fillMaxWidth(),
+ text = "Share Link",
+ onClick = state.onOpenInBrowserClick,
+ )
+ }
+ }
+}
+
+@Composable
+private fun IconBlock(modifier: Modifier = Modifier) {
+ Row(
+ modifier = modifier,
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(12.dp),
+ ) {
+ Box(
+ modifier = Modifier
+ .size(64.dp)
+ .background(TangemTheme.colors.button.primary, TangemTheme.shapes.roundedCorners8),
+ contentAlignment = Alignment.Center,
+ ) {
+ Icon(
+ imageVector = ImageVector.vectorResource(id = R.drawable.ic_tangem_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.primary2,
+ modifier = Modifier.size(38.dp),
+ )
+ }
+
+ Image(
+ imageVector = ImageVector.vectorResource(id = R.drawable.ic_loader),
+ contentDescription = null,
+ modifier = Modifier.width(32.dp),
+ )
+
+ Box(
+ modifier = Modifier
+ .size(64.dp)
+ .background(TangemTheme.colors.background.tertiary, TangemTheme.shapes.roundedCorners8),
+ contentAlignment = Alignment.Center,
+ ) {
+ Icon(
+ imageVector = ImageVector.vectorResource(id = R.drawable.ic_web_24),
+ contentDescription = null,
+ tint = TangemTheme.colors.icon.primary1,
+ modifier = Modifier.size(48.dp),
+ )
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun Preview() {
+ TangemThemePreview {
+ OnboardingVisaOtherWallet(OnboardingVisaOtherWalletUM())
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/ui/state/OnboardingVisaOtherWalletUM.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/ui/state/OnboardingVisaOtherWalletUM.kt
new file mode 100644
index 0000000000..11895f4ca9
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/otherwallet/ui/state/OnboardingVisaOtherWalletUM.kt
@@ -0,0 +1,6 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.ui.state
+
+internal data class OnboardingVisaOtherWalletUM(
+ val onShareClick: () -> Unit = {},
+ val onOpenInBrowserClick: () -> Unit = {},
+)
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/OnboardingVisaPinCodeComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/OnboardingVisaPinCodeComponent.kt
new file mode 100644
index 0000000000..6df8920a6f
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/OnboardingVisaPinCodeComponent.kt
@@ -0,0 +1,48 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.pincode
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.model.getOrCreateModel
+import com.tangem.core.ui.decompose.ComposableContentComponent
+import com.tangem.core.ui.security.DisableScreenshotsDisposableEffect
+import com.tangem.features.onboarding.v2.visa.impl.child.pincode.model.OnboardingVisaPinCodeModel
+import com.tangem.features.onboarding.v2.visa.impl.child.pincode.ui.OnboardingVisaPinCode
+import kotlinx.coroutines.launch
+
+internal class OnboardingVisaPinCodeComponent(
+ appComponentContext: AppComponentContext,
+ private val params: Params,
+) : ComposableContentComponent, AppComponentContext by appComponentContext {
+
+ private val model: OnboardingVisaPinCodeModel = getOrCreateModel()
+
+ init {
+ componentScope.launch {
+ model.onDone.collect { params.onDone() }
+ }
+ }
+
+ @Composable
+ override fun Content(modifier: Modifier) {
+ val state by model.uiState.collectAsStateWithLifecycle()
+
+ BackHandler(onBack = remember(this) { { params.onBack() } })
+
+ DisableScreenshotsDisposableEffect()
+
+ OnboardingVisaPinCode(
+ modifier = modifier,
+ state = state,
+ )
+ }
+
+ data class Params(
+ val onBack: () -> Unit,
+ val onDone: () -> Unit,
+ )
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/model/OnboardingVisaPinCodeModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/model/OnboardingVisaPinCodeModel.kt
new file mode 100644
index 0000000000..19f65cfd96
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/model/OnboardingVisaPinCodeModel.kt
@@ -0,0 +1,52 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.pincode.model
+
+import androidx.compose.runtime.Stable
+import com.tangem.core.decompose.di.ComponentScoped
+import com.tangem.core.decompose.model.Model
+import com.tangem.features.onboarding.v2.visa.impl.child.pincode.ui.state.OnboardingVisaPinCodeUM
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@Stable
+@ComponentScoped
+internal class OnboardingVisaPinCodeModel @Inject constructor(
+ override val dispatchers: CoroutineDispatcherProvider,
+) : Model() {
+
+ private val _uiState = MutableStateFlow(getInitialState())
+
+ val uiState = _uiState.asStateFlow()
+ val onDone = MutableSharedFlow()
+
+ private fun getInitialState(): OnboardingVisaPinCodeUM {
+ return OnboardingVisaPinCodeUM(
+ onPinCodeChange = ::onPinCodeChange,
+ onSubmitClick = ::onSubmitClick,
+ )
+ }
+
+ private fun onPinCodeChange(pin: String) {
+ if (pin.all { it.isDigit() }) _uiState.update { it.copy(pinCode = pin) }
+ }
+
+ private fun onSubmitClick() {
+ if (checkPinCode(_uiState.value.pinCode).not()) return
+
+ // TODO
+
+ modelScope.launch { onDone.emit(Unit) }
+ }
+
+ private fun checkPinCode(pin: String): Boolean {
+ return pin.length == PIN_CODE_LENGTH
+ }
+
+ private companion object {
+ const val PIN_CODE_LENGTH = 4
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/ui/OnboardingVisaPinCode.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/ui/OnboardingVisaPinCode.kt
new file mode 100644
index 0000000000..cf47762749
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/ui/OnboardingVisaPinCode.kt
@@ -0,0 +1,195 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.pincode.ui
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Color.Companion.Transparent
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.rememberTextMeasurer
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import com.tangem.core.ui.components.PrimaryButton
+import com.tangem.core.ui.components.SpacerH
+import com.tangem.core.ui.components.SpacerH16
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.features.onboarding.v2.visa.impl.child.pincode.ui.state.OnboardingVisaPinCodeUM
+import kotlinx.coroutines.delay
+
+@Composable
+internal fun OnboardingVisaPinCode(state: OnboardingVisaPinCodeUM, modifier: Modifier = Modifier) {
+ Column(
+ modifier = modifier
+ .fillMaxSize()
+ .navigationBarsPadding(),
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 48.dp)
+ .padding(horizontal = 36.dp)
+ .weight(1f),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Text(
+ text = "Create\nPIN Code",
+ style = TangemTheme.typography.h2,
+ color = TangemTheme.colors.text.primary1,
+ textAlign = TextAlign.Center,
+ )
+
+ SpacerH16()
+
+ Text(
+ text = "Set up a 4-digit code.\nIt will be used for payments.",
+ style = TangemTheme.typography.body1,
+ color = TangemTheme.colors.text.secondary,
+ textAlign = TextAlign.Center,
+ )
+
+ SpacerH(26.dp)
+
+ PinCodeSection(state)
+ }
+
+ PrimaryButton(
+ modifier = Modifier
+ .imePadding()
+ .padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
+ .fillMaxWidth(),
+ text = "Submit",
+ onClick = state.onSubmitClick,
+ )
+ }
+}
+
+@Composable
+private fun PinCodeSection(state: OnboardingVisaPinCodeUM, modifier: Modifier = Modifier) {
+ val focusRequester = remember { FocusRequester() }
+
+ PinCode(
+ modifier = modifier,
+ value = state.pinCode,
+ onValueChange = state.onPinCodeChange,
+ focusRequester = focusRequester,
+ )
+
+ LaunchedEffect(Unit) {
+ delay(timeMillis = 300)
+ focusRequester.requestFocus()
+ }
+}
+
+@Composable
+private fun PinCode(
+ value: String,
+ onValueChange: (String) -> Unit,
+ modifier: Modifier = Modifier,
+ numbersCount: Int = 4,
+ focusRequester: FocusRequester = remember { FocusRequester() },
+ onDone: ((String) -> Unit)? = null,
+) {
+ val keyboardController = LocalSoftwareKeyboardController.current
+
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier = modifier,
+ ) {
+ BasicTextField(
+ value = value,
+ onValueChange = { text ->
+ if (text.length <= numbersCount) {
+ onValueChange(text)
+ if (text.length == numbersCount) {
+ onDone?.invoke(text)
+ }
+ }
+ },
+ keyboardOptions = KeyboardOptions.Default.copy(
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done,
+ ),
+ keyboardActions = KeyboardActions(onDone = {
+ keyboardController?.hide()
+ },),
+ modifier = Modifier
+ .alpha(alpha = 0.01f)
+ .focusRequester(focusRequester),
+ textStyle = TextStyle.Default.copy(color = Transparent),
+ )
+
+ Row(
+ modifier = Modifier
+ .clickable(
+ indication = null,
+ interactionSource = remember { MutableInteractionSource() },
+ onClick = {
+ keyboardController?.show()
+ focusRequester.requestFocus()
+ },
+ ),
+ horizontalArrangement = Arrangement.spacedBy(12.dp),
+ ) {
+ repeat(numbersCount) { index ->
+ Box(
+ modifier = Modifier
+ .background(
+ color = Color(color = 0xFFF5F5F5),
+ shape = TangemTheme.shapes.roundedCornersXMedium,
+ )
+ .padding(
+ vertical = 12.dp,
+ horizontal = 16.dp,
+ ),
+ contentAlignment = Alignment.Center,
+ ) {
+ Text(
+ modifier = Modifier.widthIn(min = measureTextWidth("0", TangemTheme.typography.h1)),
+ text = value.getOrNull(index)?.toString() ?: "",
+ style = TangemTheme.typography.h1,
+ color = TangemTheme.colors.text.primary1,
+ )
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun measureTextWidth(text: String, style: TextStyle): Dp {
+ val textMeasurer = rememberTextMeasurer()
+ val widthInPixels = textMeasurer.measure(text, style).size.width
+ return with(LocalDensity.current) { widthInPixels.toDp() }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun Preview() {
+ TangemThemePreview {
+ OnboardingVisaPinCode(
+ state = OnboardingVisaPinCodeUM(
+ pinCode = "1234",
+ ),
+ )
+ }
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/ui/state/OnboardingVisaPinCodeUM.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/ui/state/OnboardingVisaPinCodeUM.kt
new file mode 100644
index 0000000000..a8d26f44a3
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/pincode/ui/state/OnboardingVisaPinCodeUM.kt
@@ -0,0 +1,7 @@
+package com.tangem.features.onboarding.v2.visa.impl.child.pincode.ui.state
+
+internal data class OnboardingVisaPinCodeUM(
+ val pinCode: String = "",
+ val onPinCodeChange: (String) -> Unit = {},
+ val onSubmitClick: () -> Unit = {},
+)
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/OnboardingVisaWelcomeComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/OnboardingVisaWelcomeComponent.kt
index 0194489e69..3180bdfba5 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/OnboardingVisaWelcomeComponent.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/OnboardingVisaWelcomeComponent.kt
@@ -16,16 +16,29 @@ internal class OnboardingVisaWelcomeComponent(
@Composable
override fun Content(modifier: Modifier) {
+ val state = remember(this) {
+ OnboardingVisaWelcomeUM(
+ mode = if (params.isWelcomeBack) {
+ OnboardingVisaWelcomeUM.Mode.WelcomeBack
+ } else {
+ OnboardingVisaWelcomeUM.Mode.Hello
+ },
+ userName = "User", // TODO:
+ onContinueClick = params.onDone,
+ )
+ }
+
BackHandler(onBack = remember(this) { { params.onBack() } })
OnboardingVisaWelcome(
modifier = modifier,
- state = OnboardingVisaWelcomeUM(),
+ state = state,
)
}
data class Params(
+ val isWelcomeBack: Boolean,
val onBack: () -> Unit,
- val startActivation: () -> Unit,
+ val onDone: () -> Unit,
)
}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/ui/OnboardingVisaWelcome.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/ui/OnboardingVisaWelcome.kt
index 61c2b6e0d8..26516e4075 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/ui/OnboardingVisaWelcome.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/child/welcome/ui/OnboardingVisaWelcome.kt
@@ -1,14 +1,16 @@
package com.tangem.features.onboarding.v2.visa.impl.child.welcome.ui
import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
+import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import coil.compose.AsyncImage
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.PrimaryButtonIconEnd
import com.tangem.core.ui.components.SpacerH
@@ -87,10 +89,12 @@ internal fun OnboardingVisaWelcome(state: OnboardingVisaWelcomeUM, modifier: Mod
}
}
+@Suppress("MagicNumber")
@Composable
fun Artwork(modifier: Modifier = Modifier) {
Box(modifier) {
val circleColor = TangemTheme.colors.background.secondary
+ var cardHeightPx by remember { mutableIntStateOf(0) }
Canvas(
modifier = Modifier
@@ -100,17 +104,19 @@ fun Artwork(modifier: Modifier = Modifier) {
) {
drawCircle(
color = circleColor,
- radius = size.width / 2,
+ radius = cardHeightPx / 2 + cardHeightPx / 8f,
center = center,
)
}
- AsyncImage(
- model = R.drawable.img_card_visa,
+ Image(
+ painter = painterResource(R.drawable.img_card_visa),
contentDescription = null,
- modifier = Modifier
+ modifier = modifier
.align(Alignment.Center)
- .size(128.dp), // Adjust the size as needed
+ .onSizeChanged { cardHeightPx = it.height }
+ .widthIn(max = 512.dp)
+ .fillMaxWidth(),
)
}
}
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/di/ComponentModule.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/di/ComponentModule.kt
index abb9a0cecf..5ee550c847 100644
--- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/di/ComponentModule.kt
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/di/ComponentModule.kt
@@ -1,11 +1,22 @@
package com.tangem.features.onboarding.v2.visa.impl.di
+import com.tangem.core.decompose.di.DecomposeComponent
+import com.tangem.core.decompose.model.Model
import com.tangem.features.onboarding.v2.visa.api.OnboardingVisaComponent
import com.tangem.features.onboarding.v2.visa.impl.DefaultOnboardingVisaComponent
+import com.tangem.features.onboarding.v2.visa.impl.child.accesscode.model.OnboardingVisaAccessCodeModel
+import com.tangem.features.onboarding.v2.visa.impl.child.approve.model.OnboardingVisaApproveModel
+import com.tangem.features.onboarding.v2.visa.impl.child.choosewallet.model.OnboardingVisaChooseWalletModel
+import com.tangem.features.onboarding.v2.visa.impl.child.inprogress.model.OnboardingVisaInProgressModel
+import com.tangem.features.onboarding.v2.visa.impl.child.otherwallet.model.OnboardingVisaOtherWalletModel
+import com.tangem.features.onboarding.v2.visa.impl.child.pincode.model.OnboardingVisaPinCodeModel
+import com.tangem.features.onboarding.v2.visa.impl.model.OnboardingVisaModel
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
import javax.inject.Singleton
@Module
@@ -15,4 +26,44 @@ internal interface ComponentModule {
@Binds
@Singleton
fun bindComponentFactory(factory: DefaultOnboardingVisaComponent.Factory): OnboardingVisaComponent.Factory
+}
+
+@Module
+@InstallIn(DecomposeComponent::class)
+internal interface ModelModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(OnboardingVisaAccessCodeModel::class)
+ fun provideModel(model: OnboardingVisaAccessCodeModel): Model
+
+ @Binds
+ @IntoMap
+ @ClassKey(OnboardingVisaChooseWalletModel::class)
+ fun provideModel2(model: OnboardingVisaChooseWalletModel): Model
+
+ @Binds
+ @IntoMap
+ @ClassKey(OnboardingVisaPinCodeModel::class)
+ fun provideModel3(model: OnboardingVisaPinCodeModel): Model
+
+ @Binds
+ @IntoMap
+ @ClassKey(OnboardingVisaApproveModel::class)
+ fun provideModel4(model: OnboardingVisaApproveModel): Model
+
+ @Binds
+ @IntoMap
+ @ClassKey(OnboardingVisaOtherWalletModel::class)
+ fun provideModel5(model: OnboardingVisaOtherWalletModel): Model
+
+ @Binds
+ @IntoMap
+ @ClassKey(OnboardingVisaInProgressModel::class)
+ fun provideModel6(model: OnboardingVisaInProgressModel): Model
+
+ @Binds
+ @IntoMap
+ @ClassKey(OnboardingVisaModel::class)
+ fun provideModel7(model: OnboardingVisaModel): Model
}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/model/OnboardingVisaModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/model/OnboardingVisaModel.kt
new file mode 100644
index 0000000000..f3d92c1ea3
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/model/OnboardingVisaModel.kt
@@ -0,0 +1,23 @@
+package com.tangem.features.onboarding.v2.visa.impl.model
+
+import androidx.compose.runtime.Stable
+import com.tangem.core.decompose.di.ComponentScoped
+import com.tangem.core.decompose.model.Model
+import com.tangem.core.decompose.model.ParamsContainer
+import com.tangem.features.onboarding.v2.visa.api.OnboardingVisaComponent
+import com.tangem.features.onboarding.v2.visa.impl.route.OnboardingVisaRoute
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import javax.inject.Inject
+
+@Stable
+@ComponentScoped
+internal class OnboardingVisaModel @Inject constructor(
+ paramsContainer: ParamsContainer,
+ override val dispatchers: CoroutineDispatcherProvider,
+) : Model() {
+
+ @Suppress("UnusedPrivateMember")
+ private val params = paramsContainer.require()
+
+ val initialRoute = OnboardingVisaRoute.Welcome(isWelcomeBack = false)
+}
\ No newline at end of file
diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/route/OnboardingVisaRoute.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/route/OnboardingVisaRoute.kt
new file mode 100644
index 0000000000..8eba780fd5
--- /dev/null
+++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/visa/impl/route/OnboardingVisaRoute.kt
@@ -0,0 +1,28 @@
+package com.tangem.features.onboarding.v2.visa.impl.route
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+sealed class OnboardingVisaRoute {
+
+ @Serializable
+ data class Welcome(val isWelcomeBack: Boolean) : OnboardingVisaRoute()
+
+ @Serializable
+ data object AccessCode : OnboardingVisaRoute()
+
+ @Serializable
+ data object ChooseWallet : OnboardingVisaRoute()
+
+ @Serializable
+ data object TangemWalletApproveOption : OnboardingVisaRoute()
+
+ @Serializable
+ data object OtherWalletApproveOption : OnboardingVisaRoute()
+
+ @Serializable
+ data object InProgress : OnboardingVisaRoute()
+
+ @Serializable
+ data object PinCode : OnboardingVisaRoute()
+}
\ No newline at end of file
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/ReviewManagerRequester.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/ReviewManagerRequester.kt
index 1826afb74d..a04cb17d49 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/ReviewManagerRequester.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/utils/ReviewManagerRequester.kt
@@ -2,11 +2,11 @@ package com.tangem.feature.wallet.presentation.wallet.ui.utils
import android.app.Activity
import android.content.Context
-import android.content.ContextWrapper
import com.google.android.gms.tasks.Task
import com.google.android.play.core.review.ReviewInfo
import com.google.android.play.core.review.ReviewManager
import com.google.android.play.core.review.ReviewManagerFactory
+import com.tangem.core.ui.utils.findActivity
import timber.log.Timber
internal object ReviewManagerRequester {
@@ -44,13 +44,4 @@ internal object ReviewManagerRequester {
Timber.e(task.exception)
}
}
-
- private fun Context.findActivity(): Activity {
- var context = this
- while (context is ContextWrapper) {
- if (context is Activity) return context
- context = context.baseContext
- }
- error("Permissions should be called in the context of an Activity")
- }
}
\ No newline at end of file