From 56164d0b8bc977464de87343128143ed07c47977 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 13 Mar 2025 11:34:30 +0300 Subject: [PATCH] Updated on 2026-08-14 --- app/build.gradle.kts | 4 +- .../askbiometry/AskBiometryFeatureToggles.kt | 5 -- .../{ask-biometry => biometry}/api/.gitignore | 0 .../api/build.gradle.kts | 2 +- .../biometry}/AskBiometryComponent.kt | 2 +- .../biometry/BiometryFeatureToggles.kt | 5 ++ .../impl/.gitignore | 0 .../impl/build.gradle.kts | 4 +- .../impl/DefaultAskBiometryComponent.kt | 27 ++++++-- .../impl/DefaultBiometryFeatureToggles.kt} | 10 +-- .../biometry}/impl/di/FeatureModule.kt | 14 ++-- .../biometry}/impl/model/AskBiometryModel.kt | 21 ++++-- .../features/biometry}/impl/ui/AskBiometry.kt | 48 +++++++------- .../biometry}/impl/ui/state/AskBiometryUM.kt | 3 +- features/onboarding-v2/impl/build.gradle.kts | 1 + .../impl/DefaultOnboardingEntryComponent.kt | 18 ++++- .../impl/analytics/OnboardingEntryEvent.kt | 22 +++++++ .../entry/impl/model/OnboardingEntryModel.kt | 65 ++++++++++++++----- .../impl/routing/OnboardingChildFactory.kt | 11 +++- .../v2/entry/impl/routing/OnboardingRoute.kt | 5 ++ .../v2/entry/impl/ui/OnboardingEntry.kt | 30 +-------- .../DefaultOnboardingMultiWalletComponent.kt | 2 +- .../backup/MultiWalletBackupComponent.kt | 2 +- .../Wallet1ChooseOptionComponent.kt | 2 +- .../MultiWalletCreateWalletComponent.kt | 2 +- .../finalize/MultiWalletFinalizeComponent.kt | 2 +- .../Wallet1ScanPrimaryComponent.kt | 2 +- .../MultiWalletSeedPhraseComponent.kt | 2 +- .../SetConfirmationStateInitTransformer.kt | 1 + .../AddStakingNotificationsTransformer.kt | 1 + features/wallet/impl/build.gradle.kts | 1 + .../wallet/child/wallet/WalletComponent.kt | 19 +++++- .../wallet/child/wallet/model/WalletModel.kt | 33 +++++++++- .../router/DefaultWalletRouter.kt | 6 +- .../wallet/state/model/WalletDialogConfig.kt | 3 + settings.gradle.kts | 4 +- 36 files changed, 255 insertions(+), 124 deletions(-) delete mode 100644 features/ask-biometry/api/src/main/kotlin/com/tangem/features/askbiometry/AskBiometryFeatureToggles.kt rename features/{ask-biometry => biometry}/api/.gitignore (100%) rename features/{ask-biometry => biometry}/api/build.gradle.kts (83%) rename features/{ask-biometry/api/src/main/kotlin/com/tangem/features/askbiometry => biometry/api/src/main/kotlin/com/tangem/features/biometry}/AskBiometryComponent.kt (93%) create mode 100644 features/biometry/api/src/main/kotlin/com/tangem/features/biometry/BiometryFeatureToggles.kt rename features/{ask-biometry => biometry}/impl/.gitignore (100%) rename features/{ask-biometry => biometry}/impl/build.gradle.kts (93%) rename features/{ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry => biometry/impl/src/main/kotlin/com/tangem/features/biometry}/impl/DefaultAskBiometryComponent.kt (68%) rename features/{ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/DefaultAskBiometryFeatureToggles.kt => biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/DefaultBiometryFeatureToggles.kt} (50%) rename features/{ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry => biometry/impl/src/main/kotlin/com/tangem/features/biometry}/impl/di/FeatureModule.kt (58%) rename features/{ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry => biometry/impl/src/main/kotlin/com/tangem/features/biometry}/impl/model/AskBiometryModel.kt (88%) rename features/{ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry => biometry/impl/src/main/kotlin/com/tangem/features/biometry}/impl/ui/AskBiometry.kt (84%) rename features/{ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry => biometry/impl/src/main/kotlin/com/tangem/features/biometry}/impl/ui/state/AskBiometryUM.kt (77%) create mode 100644 features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/analytics/OnboardingEntryEvent.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 65f7822aff..efdd10e6d0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -188,8 +188,8 @@ dependencies { implementation(projects.features.stories.impl) implementation(projects.features.txhistory.api) implementation(projects.features.txhistory.impl) - implementation(projects.features.askBiometry.api) - implementation(projects.features.askBiometry.impl) + implementation(projects.features.biometry.api) + implementation(projects.features.biometry.impl) implementation(projects.features.nft.api) implementation(projects.features.nft.impl) diff --git a/features/ask-biometry/api/src/main/kotlin/com/tangem/features/askbiometry/AskBiometryFeatureToggles.kt b/features/ask-biometry/api/src/main/kotlin/com/tangem/features/askbiometry/AskBiometryFeatureToggles.kt deleted file mode 100644 index 22425c768e..0000000000 --- a/features/ask-biometry/api/src/main/kotlin/com/tangem/features/askbiometry/AskBiometryFeatureToggles.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.features.askbiometry - -interface AskBiometryFeatureToggles { - val isEnabled: Boolean -} \ No newline at end of file diff --git a/features/ask-biometry/api/.gitignore b/features/biometry/api/.gitignore similarity index 100% rename from features/ask-biometry/api/.gitignore rename to features/biometry/api/.gitignore diff --git a/features/ask-biometry/api/build.gradle.kts b/features/biometry/api/build.gradle.kts similarity index 83% rename from features/ask-biometry/api/build.gradle.kts rename to features/biometry/api/build.gradle.kts index 4e2e227056..d61052da36 100644 --- a/features/ask-biometry/api/build.gradle.kts +++ b/features/biometry/api/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } android { - namespace = "com.tangem.features.askbiometry" + namespace = "com.tangem.features.biometry" } dependencies { diff --git a/features/ask-biometry/api/src/main/kotlin/com/tangem/features/askbiometry/AskBiometryComponent.kt b/features/biometry/api/src/main/kotlin/com/tangem/features/biometry/AskBiometryComponent.kt similarity index 93% rename from features/ask-biometry/api/src/main/kotlin/com/tangem/features/askbiometry/AskBiometryComponent.kt rename to features/biometry/api/src/main/kotlin/com/tangem/features/biometry/AskBiometryComponent.kt index c01180af46..b8540bfc50 100644 --- a/features/ask-biometry/api/src/main/kotlin/com/tangem/features/askbiometry/AskBiometryComponent.kt +++ b/features/biometry/api/src/main/kotlin/com/tangem/features/biometry/AskBiometryComponent.kt @@ -1,4 +1,4 @@ -package com.tangem.features.askbiometry +package com.tangem.features.biometry import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableBottomSheetComponent diff --git a/features/biometry/api/src/main/kotlin/com/tangem/features/biometry/BiometryFeatureToggles.kt b/features/biometry/api/src/main/kotlin/com/tangem/features/biometry/BiometryFeatureToggles.kt new file mode 100644 index 0000000000..8d9da24f06 --- /dev/null +++ b/features/biometry/api/src/main/kotlin/com/tangem/features/biometry/BiometryFeatureToggles.kt @@ -0,0 +1,5 @@ +package com.tangem.features.biometry + +interface BiometryFeatureToggles { + val isAskForBiometryEnabled: Boolean +} \ No newline at end of file diff --git a/features/ask-biometry/impl/.gitignore b/features/biometry/impl/.gitignore similarity index 100% rename from features/ask-biometry/impl/.gitignore rename to features/biometry/impl/.gitignore diff --git a/features/ask-biometry/impl/build.gradle.kts b/features/biometry/impl/build.gradle.kts similarity index 93% rename from features/ask-biometry/impl/build.gradle.kts rename to features/biometry/impl/build.gradle.kts index c9d6bc3fac..d324ef311d 100644 --- a/features/ask-biometry/impl/build.gradle.kts +++ b/features/biometry/impl/build.gradle.kts @@ -8,11 +8,11 @@ plugins { } android { - namespace = "com.tangem.features.askbiometry.impl" + namespace = "com.tangem.features.biometry.impl" } dependencies { - api(projects.features.askBiometry.api) + api(projects.features.biometry.api) /** Core modules */ implementation(projects.core.ui) diff --git a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/DefaultAskBiometryComponent.kt b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/DefaultAskBiometryComponent.kt similarity index 68% rename from features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/DefaultAskBiometryComponent.kt rename to features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/DefaultAskBiometryComponent.kt index 3f93ca138e..f76042e8fb 100644 --- a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/DefaultAskBiometryComponent.kt +++ b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/DefaultAskBiometryComponent.kt @@ -1,21 +1,26 @@ -package com.tangem.features.askbiometry.impl +package com.tangem.features.biometry.impl +import androidx.compose.foundation.layout.navigationBarsPadding 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.arkivanov.essenty.instancekeeper.getOrCreateSimple import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.model.getOrCreateModel import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent -import com.tangem.features.askbiometry.AskBiometryComponent -import com.tangem.features.askbiometry.impl.model.AskBiometryModel -import com.tangem.features.askbiometry.impl.ui.AskBiometry +import com.tangem.features.biometry.AskBiometryComponent +import com.tangem.features.biometry.impl.model.AskBiometryModel +import com.tangem.features.biometry.impl.ui.AskBiometry import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach internal class DefaultAskBiometryComponent @AssistedInject constructor( @Assisted appComponentContext: AppComponentContext, @@ -23,15 +28,23 @@ internal class DefaultAskBiometryComponent @AssistedInject constructor( ) : AskBiometryComponent, AppComponentContext by appComponentContext { private val model: AskBiometryModel = getOrCreateModel(params) + private val bsShown = instanceKeeper.getOrCreateSimple { MutableStateFlow(true) } + + init { + model.dismissBSFlow + .onEach { bsShown.value = false } + .launchIn(componentScope) + } override fun dismiss() = model.dismiss() @Composable override fun BottomSheet() { val state by model.uiState.collectAsStateWithLifecycle() - val bsConfig = remember(this) { + val bsShown by bsShown.collectAsStateWithLifecycle() + val bsConfig = remember(this, bsShown) { TangemBottomSheetConfig( - isShown = true, + isShown = bsShown, onDismissRequest = ::dismiss, content = TangemBottomSheetConfigContent.Empty, ) @@ -48,7 +61,7 @@ internal class DefaultAskBiometryComponent @AssistedInject constructor( val state by model.uiState.collectAsStateWithLifecycle() AskBiometry( - modifier = modifier, + modifier = modifier.navigationBarsPadding(), state = state, ) } diff --git a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/DefaultAskBiometryFeatureToggles.kt b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/DefaultBiometryFeatureToggles.kt similarity index 50% rename from features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/DefaultAskBiometryFeatureToggles.kt rename to features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/DefaultBiometryFeatureToggles.kt index e2be13dfb9..4cbc7b25ac 100644 --- a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/DefaultAskBiometryFeatureToggles.kt +++ b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/DefaultBiometryFeatureToggles.kt @@ -1,12 +1,12 @@ -package com.tangem.features.askbiometry.impl +package com.tangem.features.biometry.impl import com.tangem.core.configtoggle.feature.FeatureTogglesManager -import com.tangem.features.askbiometry.AskBiometryFeatureToggles +import com.tangem.features.biometry.BiometryFeatureToggles import javax.inject.Inject -class DefaultAskBiometryFeatureToggles @Inject constructor( +internal class DefaultBiometryFeatureToggles @Inject constructor( private val featureTogglesManager: FeatureTogglesManager, -) : AskBiometryFeatureToggles { - override val isEnabled: Boolean +) : BiometryFeatureToggles { + override val isAskForBiometryEnabled: Boolean get() = featureTogglesManager.isFeatureEnabled("ASK_BIOMETRY_REFACTORING_ENABLED") } \ No newline at end of file diff --git a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/di/FeatureModule.kt b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/di/FeatureModule.kt similarity index 58% rename from features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/di/FeatureModule.kt rename to features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/di/FeatureModule.kt index e9e8bc3bc1..3e33b8ce67 100644 --- a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/di/FeatureModule.kt +++ b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/di/FeatureModule.kt @@ -1,12 +1,12 @@ -package com.tangem.features.askbiometry.impl.di +package com.tangem.features.biometry.impl.di import com.tangem.core.decompose.di.ModelComponent import com.tangem.core.decompose.model.Model -import com.tangem.features.askbiometry.AskBiometryComponent -import com.tangem.features.askbiometry.AskBiometryFeatureToggles -import com.tangem.features.askbiometry.impl.DefaultAskBiometryComponent -import com.tangem.features.askbiometry.impl.DefaultAskBiometryFeatureToggles -import com.tangem.features.askbiometry.impl.model.AskBiometryModel +import com.tangem.features.biometry.AskBiometryComponent +import com.tangem.features.biometry.BiometryFeatureToggles +import com.tangem.features.biometry.impl.DefaultAskBiometryComponent +import com.tangem.features.biometry.impl.DefaultBiometryFeatureToggles +import com.tangem.features.biometry.impl.model.AskBiometryModel import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -19,7 +19,7 @@ import dagger.multibindings.IntoMap internal interface FeatureModule { @Binds - fun bindFeatureToggles(impl: DefaultAskBiometryFeatureToggles): AskBiometryFeatureToggles + fun bindFeatureToggles(impl: DefaultBiometryFeatureToggles): BiometryFeatureToggles @Binds fun bindComponentFactory(impl: DefaultAskBiometryComponent.Factory): AskBiometryComponent.Factory diff --git a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/model/AskBiometryModel.kt b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/model/AskBiometryModel.kt similarity index 88% rename from features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/model/AskBiometryModel.kt rename to features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/model/AskBiometryModel.kt index a72832828f..7de4c4bbd3 100644 --- a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/model/AskBiometryModel.kt +++ b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/model/AskBiometryModel.kt @@ -1,4 +1,4 @@ -package com.tangem.features.askbiometry.impl.model +package com.tangem.features.biometry.impl.model import androidx.compose.runtime.Stable import com.tangem.core.decompose.di.ModelScoped @@ -18,10 +18,12 @@ import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.repository.WalletsRepository -import com.tangem.features.askbiometry.AskBiometryComponent -import com.tangem.features.askbiometry.impl.ui.state.AskBiometryUM +import com.tangem.features.biometry.AskBiometryComponent +import com.tangem.features.biometry.impl.ui.state.AskBiometryUM import com.tangem.sdk.api.TangemSdkManager import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update @@ -52,9 +54,11 @@ internal class AskBiometryModel @Inject constructor( bottomSheetVariant = params.bottomSheetVariant, onAllowClick = ::onAllowClick, onDontAllowClick = ::dontAllow, + onDismiss = ::dismiss, ), ) val uiState = _uiState.asStateFlow() + val dismissBSFlow = MutableSharedFlow() init { modelScope.launch { @@ -72,7 +76,11 @@ internal class AskBiometryModel @Inject constructor( } fun dismiss() { - dontAllow() + modelScope.launch { + dismissBSFlow.emit(Unit) + delay(timeMillis = 500) + dontAllow() + } } private fun allowToUseBiometrics() { @@ -107,6 +115,11 @@ internal class AskBiometryModel @Inject constructor( isBiometricsRequestPolicy = userWallet.hasAccessCode, ) + if (_uiState.value.bottomSheetVariant) { + dismissBSFlow.emit(Unit) + delay(timeMillis = 500) + } + params.modelCallbacks.onAllowed() } diff --git a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/ui/AskBiometry.kt b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/ui/AskBiometry.kt similarity index 84% rename from features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/ui/AskBiometry.kt rename to features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/ui/AskBiometry.kt index 09521a2b56..913b028223 100644 --- a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/ui/AskBiometry.kt +++ b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/ui/AskBiometry.kt @@ -1,4 +1,4 @@ -package com.tangem.features.askbiometry.impl.ui +package com.tangem.features.biometry.impl.ui import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState @@ -14,12 +14,11 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import com.tangem.core.ui.components.* -import com.tangem.core.ui.components.atoms.Hand import com.tangem.core.ui.extensions.stringResourceSafe import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.features.askbiometry.impl.ui.state.AskBiometryUM -import com.tangem.features.askbiometry.impl.R +import com.tangem.features.biometry.impl.ui.state.AskBiometryUM +import com.tangem.features.biometry.R @Composable internal fun AskBiometry(state: AskBiometryUM, modifier: Modifier = Modifier) { @@ -31,15 +30,16 @@ internal fun AskBiometry(state: AskBiometryUM, modifier: Modifier = Modifier) { modifier = Modifier.weight(1f), ) { if (state.bottomSheetVariant) { - Header(onCloseClick = state.onDontAllowClick) + Header(onCloseClick = state.onDismiss) } SpacerH32() + SpacerHHalf() Column( modifier = Modifier.verticalScroll(rememberScrollState()), ) { - Title(modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing22)) + Title(modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing56)) SpacerH32() Description( modifier = Modifier @@ -47,6 +47,8 @@ internal fun AskBiometry(state: AskBiometryUM, modifier: Modifier = Modifier) { .fillMaxWidth(), ) } + + SpacerHHalf() } Footer(state = state) SpacerH16() @@ -54,29 +56,23 @@ internal fun AskBiometry(state: AskBiometryUM, modifier: Modifier = Modifier) { } @Composable -private fun Header(onCloseClick: () -> Unit) { - Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), +private fun Header(onCloseClick: () -> Unit, modifier: Modifier = Modifier) { + Row( + modifier = modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End, ) { - Hand() - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.End, + IconButton( + modifier = Modifier.size(TangemTheme.dimens.size32), + onClick = onCloseClick, ) { - IconButton( - modifier = Modifier.size(TangemTheme.dimens.size32), - onClick = onCloseClick, - ) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size24), - painter = painterResource(id = R.drawable.ic_close_24), - tint = TangemTheme.colors.icon.secondary, - contentDescription = stringResourceSafe(id = R.string.common_cancel), - ) - } - SpacerW8() + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = R.drawable.ic_close_24), + tint = TangemTheme.colors.icon.secondary, + contentDescription = stringResourceSafe(id = R.string.common_cancel), + ) } + SpacerW8() } } diff --git a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/ui/state/AskBiometryUM.kt b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/ui/state/AskBiometryUM.kt similarity index 77% rename from features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/ui/state/AskBiometryUM.kt rename to features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/ui/state/AskBiometryUM.kt index 27a511e379..0148aba873 100644 --- a/features/ask-biometry/impl/src/main/kotlin/com/tangem/features/askbiometry/impl/ui/state/AskBiometryUM.kt +++ b/features/biometry/impl/src/main/kotlin/com/tangem/features/biometry/impl/ui/state/AskBiometryUM.kt @@ -1,4 +1,4 @@ -package com.tangem.features.askbiometry.impl.ui.state +package com.tangem.features.biometry.impl.ui.state import com.tangem.core.ui.extensions.TextReference @@ -8,4 +8,5 @@ internal data class AskBiometryUM( val error: TextReference? = null, val onAllowClick: () -> Unit = {}, val onDontAllowClick: () -> Unit = {}, + val onDismiss: () -> Unit = {}, ) \ No newline at end of file diff --git a/features/onboarding-v2/impl/build.gradle.kts b/features/onboarding-v2/impl/build.gradle.kts index 636d71237b..a848d97068 100644 --- a/features/onboarding-v2/impl/build.gradle.kts +++ b/features/onboarding-v2/impl/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { /** Api */ implementation(projects.features.onboardingV2.api) implementation(projects.features.manageTokens.api) + implementation(projects.features.biometry.api) /** Core modules */ implementation(projects.core.configToggles) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt index 3c69bb169d..05eabc3965 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/DefaultOnboardingEntryComponent.kt @@ -14,11 +14,13 @@ import com.tangem.core.decompose.context.child import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.model.getOrCreateModel import com.tangem.core.decompose.navigation.inner.InnerNavigationHolder +import com.tangem.core.ui.extensions.resourceReference import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent import com.tangem.features.onboarding.v2.entry.impl.model.OnboardingEntryModel import com.tangem.features.onboarding.v2.entry.impl.routing.OnboardingChildFactory import com.tangem.features.onboarding.v2.entry.impl.routing.OnboardingRoute import com.tangem.features.onboarding.v2.entry.impl.ui.OnboardingEntry +import com.tangem.features.onboarding.v2.impl.R import com.tangem.features.onboarding.v2.stepper.api.OnboardingStepperComponent import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn @@ -110,9 +112,19 @@ internal class DefaultOnboardingEntryComponent @AssistedInject constructor( } else { stepperComponent.state.update { it.copy( - currentStep = if (stack.active.configuration is OnboardingRoute.ManageTokens) 7 else 8, - steps = 8, - title = model.titleProvider.currentTitle.value, + currentStep = when (stack.active.configuration) { + is OnboardingRoute.AskBiometry -> 7 + is OnboardingRoute.ManageTokens -> 8 + is OnboardingRoute.Done -> 9 + else -> error("Unsupported route") + }, + steps = 9, + title = when (stack.active.configuration) { + is OnboardingRoute.AskBiometry -> resourceReference(R.string.onboarding_navbar_save_wallet) + is OnboardingRoute.ManageTokens -> resourceReference(R.string.main_manage_tokens) + is OnboardingRoute.Done -> resourceReference(R.string.onboarding_done_header) + else -> error("Unsupported route") + }, showProgress = true, ) } diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/analytics/OnboardingEntryEvent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/analytics/OnboardingEntryEvent.kt new file mode 100644 index 0000000000..67c0f50765 --- /dev/null +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/analytics/OnboardingEntryEvent.kt @@ -0,0 +1,22 @@ +package com.tangem.features.onboarding.v2.entry.impl.analytics + +import com.tangem.core.analytics.models.AnalyticsEvent + +internal sealed class OnboardingEntryEvent( + category: String, + event: String, + params: Map = mapOf(), +) : AnalyticsEvent(category, event, params) { + + data class Biometric( + val state: State, + ) : OnboardingEntryEvent( + category = "Onboarding / Biometric", + event = "Biometry", + params = mapOf("State" to state.name), + ) { + enum class State { + On, Off + } + } +} \ No newline at end of file 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 ff272adfb8..ef5e1ffa37 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 @@ -1,8 +1,9 @@ package com.tangem.features.onboarding.v2.entry.impl.model import com.arkivanov.decompose.router.stack.StackNavigation -import com.arkivanov.decompose.router.stack.navigate +import com.arkivanov.decompose.router.stack.replaceAll import com.tangem.common.routing.AppRoute +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -14,8 +15,11 @@ import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.settings.repositories.SettingsRepository import com.tangem.domain.wallets.models.UserWallet +import com.tangem.features.biometry.AskBiometryComponent +import com.tangem.features.biometry.BiometryFeatureToggles import com.tangem.features.onboarding.v2.TitleProvider import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent +import com.tangem.features.onboarding.v2.entry.impl.analytics.OnboardingEntryEvent import com.tangem.features.onboarding.v2.entry.impl.routing.OnboardingRoute import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent import com.tangem.sdk.api.TangemSdkManager @@ -26,6 +30,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import javax.inject.Inject +@Suppress("LongParameterList") @ModelScoped internal class OnboardingEntryModel @Inject constructor( paramsContainer: ParamsContainer, @@ -33,6 +38,8 @@ internal class OnboardingEntryModel @Inject constructor( private val router: Router, private val tangemSdkManager: TangemSdkManager, private val settingsRepository: SettingsRepository, + private val askBiometryFeatureToggles: BiometryFeatureToggles, + private val analyticsEventHandler: AnalyticsEventHandler, ) : Model() { private val params = paramsContainer.require() @@ -78,7 +85,7 @@ internal class OnboardingEntryModel @Inject constructor( ProductType.Note -> OnboardingRoute.Note( scanResponse = scanResponse, titleProvider = titleProvider, - onDone = ::navigateToWalletScreen, + onDone = ::navigateToFinalScreenFlow, ) else -> error("Unsupported") } @@ -86,34 +93,58 @@ internal class OnboardingEntryModel @Inject constructor( private fun onMultiWalletOnboardingDone(userWallet: UserWallet) { if (userWallet.scanResponse.cardTypesResolver.isMultiwalletAllowed()) { - stackNavigation.navigate { - listOf(OnboardingRoute.ManageTokens(userWallet)) - } + stackNavigation.replaceAll(OnboardingRoute.ManageTokens(userWallet)) } else { - stackNavigation.navigate { - listOf(OnboardingRoute.Done(onDone = ::navigateToWalletScreen)) - } + navigateToFinalScreenFlow() } } fun onManageTokensDone() { - stackNavigation.navigate { - listOf(OnboardingRoute.Done(onDone = ::navigateToWalletScreen)) - } + navigateToFinalScreenFlow() } private fun onVisaOnboardingDone() { - stackNavigation.navigate { - listOf(OnboardingRoute.Done(onDone = ::navigateToWalletScreen)) + navigateToFinalScreenFlow() + } + + private fun navigateToFinalScreenFlow() { + if (askBiometryFeatureToggles.isAskForBiometryEnabled) { + modelScope.launch { + if (tangemSdkManager.checkCanUseBiometry() && settingsRepository.shouldShowSaveUserWalletScreen()) { + stackNavigation.replaceAll( + OnboardingRoute.AskBiometry(modelCallbacks = AskBiometryModelCallbacks()), + ) + } else { + stackNavigation.replaceAll(OnboardingRoute.Done(onDone = ::navigateToWalletScreen)) + } + } + } else { + stackNavigation.replaceAll(OnboardingRoute.Done(onDone = ::navigateToWalletScreen)) + } + } + + inner class AskBiometryModelCallbacks : AskBiometryComponent.ModelCallbacks { + override fun onAllowed() { + analyticsEventHandler.send(OnboardingEntryEvent.Biometric(OnboardingEntryEvent.Biometric.State.On)) + stackNavigation.replaceAll(OnboardingRoute.Done(onDone = ::navigateToWalletScreen)) + } + + override fun onDenied() { + analyticsEventHandler.send(OnboardingEntryEvent.Biometric(OnboardingEntryEvent.Biometric.State.Off)) + stackNavigation.replaceAll(OnboardingRoute.Done(onDone = ::navigateToWalletScreen)) } } private fun navigateToWalletScreen() { - modelScope.launch(NonCancellable) { + if (askBiometryFeatureToggles.isAskForBiometryEnabled) { router.replaceAll(AppRoute.Wallet) - if (tangemSdkManager.checkCanUseBiometry() && settingsRepository.shouldShowSaveUserWalletScreen()) { - delay(timeMillis = 1_800) - router.push(AppRoute.SaveWallet) + } else { + modelScope.launch(NonCancellable) { + router.replaceAll(AppRoute.Wallet) + if (tangemSdkManager.checkCanUseBiometry() && settingsRepository.shouldShowSaveUserWalletScreen()) { + delay(timeMillis = 1_800) + router.push(AppRoute.SaveWallet) + } } } } 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 21976c01cb..608d542ebe 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 @@ -1,6 +1,7 @@ package com.tangem.features.onboarding.v2.entry.impl.routing import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.features.biometry.AskBiometryComponent import com.tangem.features.managetokens.component.OnboardingManageTokensComponent import com.tangem.features.onboarding.v2.done.api.OnboardingDoneComponent import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent @@ -13,6 +14,7 @@ internal class OnboardingChildFactory @Inject constructor( private val onboardingManageTokensComponentFactory: OnboardingManageTokensComponent.Factory, private val onboardingDoneComponentFactory: OnboardingDoneComponent.Factory, private val onBoardingVisaComponentFactory: OnboardingVisaComponent.Factory, + private val askBiometryComponentFactory: AskBiometryComponent.Factory, private val onboardingNoteComponentFactory: OnboardingNoteComponent.Factory, ) { @@ -57,7 +59,14 @@ internal class OnboardingChildFactory @Inject constructor( onDone = route.onDone, ), ) - else -> Unit + is OnboardingRoute.AskBiometry -> askBiometryComponentFactory.create( + context = childContext, + params = AskBiometryComponent.Params( + bottomSheetVariant = false, + modelCallbacks = route.modelCallbacks, + ), + ) + is OnboardingRoute.None -> Unit } } } \ No newline at end of file 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 4686de8c0e..b111c82d91 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 @@ -3,6 +3,7 @@ package com.tangem.features.onboarding.v2.entry.impl.routing import com.tangem.core.decompose.navigation.Route import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.models.UserWallet +import com.tangem.features.biometry.AskBiometryComponent import com.tangem.features.onboarding.v2.TitleProvider import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent @@ -34,6 +35,10 @@ sealed class OnboardingRoute : Route { val userWallet: UserWallet, ) : OnboardingRoute() + data class AskBiometry( + val modelCallbacks: AskBiometryComponent.ModelCallbacks, + ) : OnboardingRoute() + data class Done( val onDone: () -> Unit, ) : OnboardingRoute() diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/ui/OnboardingEntry.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/ui/OnboardingEntry.kt index bfc7be83af..65dd778fc4 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/ui/OnboardingEntry.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/entry/impl/ui/OnboardingEntry.kt @@ -11,7 +11,6 @@ import com.arkivanov.decompose.router.stack.ChildStack import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.res.TangemTheme import com.tangem.features.onboarding.v2.entry.impl.routing.OnboardingRoute -import com.tangem.features.onboarding.v2.multiwallet.api.OnboardingMultiWalletComponent @Composable internal inline fun OnboardingEntry( @@ -31,34 +30,7 @@ internal inline fun OnboardingEntry( stack = childStack, animation = stackAnimation(slide()), ) { - when (it.configuration) { - is OnboardingRoute.MultiWallet -> { - (it.instance as OnboardingMultiWalletComponent).Content( - modifier = modifier, - ) - } - is OnboardingRoute.ManageTokens -> { - (it.instance as ComposableContentComponent).Content( - modifier = modifier, - ) - } - is OnboardingRoute.Done -> { - (it.instance as ComposableContentComponent).Content( - modifier = modifier, - ) - } - is OnboardingRoute.Visa -> { - (it.instance as ComposableContentComponent).Content( - modifier = modifier, - ) - } - is OnboardingRoute.Note -> { - (it.instance as ComposableContentComponent).Content( - modifier = modifier, - ) - } - is OnboardingRoute.None -> {} - } + (it.instance as? ComposableContentComponent)?.Content(modifier = modifier) } } } \ No newline at end of file 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 0c783b964c..b7d96ab79a 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 @@ -70,7 +70,7 @@ internal class DefaultOnboardingMultiWalletComponent @AssistedInject constructor private val innerNavigationStateFlow = instanceKeeper.getOrCreateSimple(key = "innerNavigationState") { MutableStateFlow( - MultiWalletInnerNavigationState(1, 5), + MultiWalletInnerNavigationState(1, 6), ) } diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/MultiWalletBackupComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/MultiWalletBackupComponent.kt index 6b63fc8c48..26eb6e5be7 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/MultiWalletBackupComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/backup/MultiWalletBackupComponent.kt @@ -28,7 +28,7 @@ class MultiWalletBackupComponent( params.innerNavigation.update { it.copy( stackSize = 5, - stackMaxSize = 8, + stackMaxSize = 9, ) } diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/Wallet1ChooseOptionComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/Wallet1ChooseOptionComponent.kt index 33bd477297..391228b718 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/Wallet1ChooseOptionComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/chooseoption/Wallet1ChooseOptionComponent.kt @@ -27,7 +27,7 @@ class Wallet1ChooseOptionComponent( params.innerNavigation.update { it.copy( stackSize = 3, - stackMaxSize = 8, + stackMaxSize = 9, ) } diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/MultiWalletCreateWalletComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/MultiWalletCreateWalletComponent.kt index 88f37db96d..2cf4d4435f 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/MultiWalletCreateWalletComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/MultiWalletCreateWalletComponent.kt @@ -30,7 +30,7 @@ internal class MultiWalletCreateWalletComponent( params.innerNavigation.update { it.copy( stackSize = 2, - stackMaxSize = 8, + stackMaxSize = 9, ) } diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/finalize/MultiWalletFinalizeComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/finalize/MultiWalletFinalizeComponent.kt index 22025b3798..5c8f75423b 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/finalize/MultiWalletFinalizeComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/finalize/MultiWalletFinalizeComponent.kt @@ -32,7 +32,7 @@ internal class MultiWalletFinalizeComponent( params.innerNavigation.update { it.copy( stackSize = 7, - stackMaxSize = 8, + stackMaxSize = 9, ) } params.parentParams.titleProvider.changeTitle( diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/Wallet1ScanPrimaryComponent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/Wallet1ScanPrimaryComponent.kt index a6d80fd63b..f17700e3ed 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/Wallet1ScanPrimaryComponent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/scanprimary/Wallet1ScanPrimaryComponent.kt @@ -25,7 +25,7 @@ internal class Wallet1ScanPrimaryComponent( params.innerNavigation.update { it.copy( stackSize = 4, - stackMaxSize = 8, + stackMaxSize = 9, ) } 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 0e2df84fa6..2f85b1a45c 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 @@ -39,7 +39,7 @@ internal class MultiWalletSeedPhraseComponent( params.innerNavigation.update { st -> st.copy( stackSize = 3 + it.order, - stackMaxSize = 10, + stackMaxSize = 11, ) } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt index 86e99b6bde..29c70b9c15 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt @@ -41,6 +41,7 @@ internal class SetConfirmationStateInitTransformer( private val isImplicitExit: Boolean get() = pendingAction == null && pendingActions?.isEmpty() == true || isTronStakedBalance + @Suppress("CyclomaticComplexMethod") override fun transform(prevState: StakingUiState): StakingUiState { val actionType = when { isEnter -> StakingActionCommonType.Enter( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt index 1543edd128..f82dff2923 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt @@ -54,6 +54,7 @@ internal class AddStakingNotificationsTransformer( isSubtractAvailable = isSubtractAvailable, ) + @Suppress("LongMethod") override fun transform(prevState: StakingUiState): StakingUiState { val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() val balance = cryptoCurrencyStatus.value.amount.orZero() diff --git a/features/wallet/impl/build.gradle.kts b/features/wallet/impl/build.gradle.kts index d36dc2c763..f786056d52 100644 --- a/features/wallet/impl/build.gradle.kts +++ b/features/wallet/impl/build.gradle.kts @@ -107,6 +107,7 @@ dependencies { implementation(projects.features.tokendetails.api) implementation(projects.features.wallet.api) implementation(projects.features.walletSettings.api) + implementation(projects.features.biometry.api) /** Common modules */ implementation(projects.common) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt index a0bad13d8b..7e8e90b260 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/WalletComponent.kt @@ -13,13 +13,16 @@ import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.decompose.context.child import com.tangem.core.decompose.context.childByContext import com.tangem.core.decompose.model.getOrCreateModel +import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.core.ui.decompose.ComposableContentComponent +import com.tangem.core.ui.decompose.ComposableDialogComponent import com.tangem.core.ui.utils.findActivity import com.tangem.feature.wallet.child.wallet.model.WalletModel import com.tangem.feature.wallet.navigation.WalletRoute import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen import com.tangem.feature.walletsettings.component.RenameWalletComponent +import com.tangem.features.biometry.AskBiometryComponent import com.tangem.features.markets.entry.MarketsEntryComponent import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -31,6 +34,7 @@ internal class WalletComponent @AssistedInject constructor( @Assisted navigate: (WalletRoute) -> Unit, private val renameWalletComponentFactory: RenameWalletComponent.Factory, private val marketsEntryComponentFactory: MarketsEntryComponent.Factory, + private val askBiometryComponentFactory: AskBiometryComponent.Factory, ) : ComposableContentComponent, AppComponentContext by appComponentContext { private val model: WalletModel = getOrCreateModel() @@ -56,6 +60,15 @@ internal class WalletComponent @AssistedInject constructor( ), ) } + is WalletDialogConfig.AskForBiometry -> { + askBiometryComponentFactory.create( + context = childByContext(componentContext), + params = AskBiometryComponent.Params( + bottomSheetVariant = true, + modelCallbacks = model.askBiometryModelCallbacks, + ), + ) + } } }, ) @@ -74,7 +87,11 @@ internal class WalletComponent @AssistedInject constructor( marketsEntryComponent = marketsEntryComponent, ) - dialog.child?.instance?.Dialog() + when (val dialog = dialog.child?.instance) { + is ComposableDialogComponent -> dialog.Dialog() + is ComposableBottomSheetComponent -> dialog.BottomSheet() + else -> {} + } } @AssistedFactory diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 044aaec8c6..590d0d0bec 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -2,7 +2,11 @@ package com.tangem.feature.wallet.child.wallet.model import androidx.compose.runtime.Stable import arrow.core.getOrElse +import com.arkivanov.decompose.router.slot.activate +import com.arkivanov.decompose.router.slot.dismiss import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase @@ -23,12 +27,15 @@ import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationU import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.model.PushNotificationsBottomSheetConfig +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent.DemonstrateWalletsScrollPreview.Direction import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState import com.tangem.feature.wallet.presentation.wallet.state.transformers.* import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider +import com.tangem.features.biometry.AskBiometryComponent +import com.tangem.features.biometry.BiometryFeatureToggles import com.tangem.features.pushnotifications.api.utils.PUSH_PERMISSION import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles @@ -67,11 +74,13 @@ internal class WalletModel @Inject constructor( private val tokenListStore: MultiWalletTokenListStore, private val onrampStatusFactory: OnrampStatusFactory, private val walletFeatureToggles: WalletFeatureToggles, + private val biometryFeatureToggles: BiometryFeatureToggles, + private val analyticsEventsHandler: AnalyticsEventHandler, val screenLifecycleProvider: ScreenLifecycleProvider, val innerWalletRouter: InnerWalletRouter, - analyticsEventsHandler: AnalyticsEventHandler, ) : Model() { + val askBiometryModelCallbacks = AskBiometryModelCallbacks() val uiState: StateFlow = stateHolder.uiState private val walletsUpdateJobHolder = JobHolder() @@ -116,7 +125,15 @@ internal class WalletModel @Inject constructor( modelScope.launch(dispatchers.main) { withContext(dispatchers.io) { delay(timeMillis = 1_800) } - if (isShowSaveWalletScreenEnabled()) innerWalletRouter.openSaveUserWalletScreen() + if (isShowSaveWalletScreenEnabled()) { + if (biometryFeatureToggles.isAskForBiometryEnabled) { + innerWalletRouter.dialogNavigation.activate( + configuration = WalletDialogConfig.AskForBiometry, + ) + } else { + innerWalletRouter.openSaveUserWalletScreen() + } + } } } @@ -446,6 +463,18 @@ internal class WalletModel @Inject constructor( ) } + inner class AskBiometryModelCallbacks : AskBiometryComponent.ModelCallbacks { + override fun onAllowed() { + analyticsEventsHandler.send(MainScreenAnalyticsEvent.EnableBiometrics(AnalyticsParam.OnOffState.On)) + innerWalletRouter.dialogNavigation.dismiss() + } + + override fun onDenied() { + analyticsEventsHandler.send(MainScreenAnalyticsEvent.EnableBiometrics(AnalyticsParam.OnOffState.Off)) + innerWalletRouter.dialogNavigation.dismiss() + } + } + private companion object { const val REFRESH_WALLET_BACKGROUND_TIMER_MILLIS = 10000L const val EXPRESS_STATUS_UPDATE_DELAY = 10000L diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index fe1c52f5bc..c32de7180a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -13,6 +13,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.wallet.navigation.WalletRoute import com.tangem.feature.wallet.presentation.wallet.state.model.WalletDialogConfig +import com.tangem.features.biometry.BiometryFeatureToggles import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow @@ -25,6 +26,7 @@ internal class DefaultWalletRouter @Inject constructor( private val urlOpener: UrlOpener, private val reduxStateHolder: ReduxStateHolder, private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles, + private val biometryFeatureToggles: BiometryFeatureToggles, ) : InnerWalletRouter { override val dialogNavigation: SlotNavigation = SlotNavigation() @@ -98,7 +100,9 @@ internal class DefaultWalletRouter @Inject constructor( } override fun openSaveUserWalletScreen() { - router.push(AppRoute.SaveWallet) + if (biometryFeatureToggles.isAskForBiometryEnabled.not()) { + router.push(AppRoute.SaveWallet) + } } override fun isWalletLastScreen(): Boolean { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDialogConfig.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDialogConfig.kt index 71dc159435..5ce5ac2dbd 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDialogConfig.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/model/WalletDialogConfig.kt @@ -13,4 +13,7 @@ internal sealed interface WalletDialogConfig { @Serializable data class RenameWallet(val userWalletId: UserWalletId, val currentName: String) : WalletDialogConfig + + @Serializable + data object AskForBiometry : WalletDialogConfig } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index cbc2e965dd..35ef36ff52 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -228,8 +228,8 @@ include(":features:stories:impl") include(":features:txhistory:api") include(":features:txhistory:impl") -include(":features:ask-biometry:api") -include(":features:ask-biometry:impl") +include(":features:biometry:api") +include(":features:biometry:impl") include(":features:nft:api") include(":features:nft:impl")