Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-25 13:54:11 +03:00
parent e080401183
commit f97a017f3f
22 changed files with 28 additions and 854 deletions

View file

@ -4,7 +4,6 @@ import com.tangem.tap.common.redux.global.globalReducer
import com.tangem.tap.features.details.redux.DetailsReducer
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer
import com.tangem.tap.features.home.redux.HomeReducer
import com.tangem.tap.features.saveWallet.redux.SaveWalletReducer
import com.tangem.tap.features.welcome.redux.WelcomeReducer
import com.tangem.tap.proxy.redux.DaggerGraphReducer
import org.rekotlin.Action
@ -19,7 +18,6 @@ fun appReducer(action: Action, state: AppState?): AppState {
detailsState = DetailsReducer.reduce(action, state),
walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState),
welcomeState = WelcomeReducer.reduce(action, state),
saveWalletState = SaveWalletReducer.reduce(action, state),
daggerGraphState = DaggerGraphReducer.reduce(action, state),
)
}

View file

@ -10,8 +10,6 @@ import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState
import com.tangem.tap.features.home.redux.HomeMiddleware
import com.tangem.tap.features.home.redux.HomeState
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupMiddleware
import com.tangem.tap.features.saveWallet.redux.SaveWalletMiddleware
import com.tangem.tap.features.saveWallet.redux.SaveWalletState
import com.tangem.tap.features.wallet.redux.middlewares.TradeCryptoMiddleware
import com.tangem.tap.features.welcome.redux.WelcomeMiddleware
import com.tangem.tap.features.welcome.redux.WelcomeState
@ -26,7 +24,6 @@ data class AppState(
val detailsState: DetailsState = DetailsState(),
val walletConnectState: WalletConnectState = WalletConnectState(),
val welcomeState: WelcomeState = WelcomeState(),
val saveWalletState: SaveWalletState = SaveWalletState(),
val daggerGraphState: DaggerGraphState = DaggerGraphState(),
) : StateType {
@ -41,7 +38,6 @@ data class AppState(
WalletConnectMiddleware().walletConnectMiddleware,
BackupMiddleware().backupMiddleware,
WelcomeMiddleware().middleware,
SaveWalletMiddleware().middleware,
LockUserWalletsTimerMiddleware().middleware,
AccessCodeRequestPolicyMiddleware().middleware,
DaggerGraphMiddleware.daggerGraphMiddleware,

View file

@ -1,31 +0,0 @@
package com.tangem.tap.features.saveWallet.redux
import com.tangem.common.core.TangemError
import com.tangem.domain.models.scan.ScanResponse
import org.rekotlin.Action
internal sealed interface SaveWalletAction : Action {
data class ProvideBackupInfo(
val scanResponse: ScanResponse,
val accessCode: String?,
val backupCardsIds: Set<String>?,
) : SaveWalletAction
data object AllowToUseBiometrics : SaveWalletAction {
data object Success : SaveWalletAction
data class Error(val error: TangemError) : SaveWalletAction
}
data object Dismiss : SaveWalletAction
data object CloseError : SaveWalletAction
data object EnrollBiometrics : SaveWalletAction {
data object Enroll : SaveWalletAction
data object Cancel : SaveWalletAction
}
data class SaveWalletAfterBackup(
val hasBackupError: Boolean,
val shouldNavigateToWallet: Boolean,
) : SaveWalletAction
}

View file

@ -1,188 +0,0 @@
package com.tangem.tap.features.saveWallet.redux
import com.tangem.common.*
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.common.routing.AppRoute
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.extensions.dispatchNavigationAction
import com.tangem.tap.common.extensions.dispatchWithMain
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.extensions.onUserWalletSelected
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletAction
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
import kotlinx.coroutines.launch
import org.rekotlin.Middleware
import timber.log.Timber
internal class SaveWalletMiddleware {
private val saveWalletJobHolder = JobHolder()
val middleware: Middleware<AppState> = { _, stateProvider ->
{ next ->
{ action ->
val state = stateProvider()
if (action is SaveWalletAction && state != null) {
handleAction(action, state.saveWalletState)
}
next(action)
}
}
}
private fun handleAction(action: SaveWalletAction, state: SaveWalletState) {
when (action) {
is SaveWalletAction.AllowToUseBiometrics -> allowToUseBiometrics(state)
is SaveWalletAction.EnrollBiometrics.Enroll -> enrollBiometrics()
is SaveWalletAction.Dismiss -> dismiss(state)
is SaveWalletAction.SaveWalletAfterBackup -> saveWalletAfterBackup(
state = state,
hasBackupError = action.hasBackupError,
shouldNavigateToWallet = action.shouldNavigateToWallet,
)
is SaveWalletAction.AllowToUseBiometrics.Success,
is SaveWalletAction.AllowToUseBiometrics.Error,
is SaveWalletAction.ProvideBackupInfo,
is SaveWalletAction.CloseError,
is SaveWalletAction.EnrollBiometrics,
is SaveWalletAction.EnrollBiometrics.Cancel,
-> Unit
}
}
private fun saveWalletAfterBackup(
state: SaveWalletState,
hasBackupError: Boolean,
shouldNavigateToWallet: Boolean,
) {
scope.launch {
val backupInfo = state.backupInfo ?: error("Backup info is null")
val userWalletBuilder = store.inject(DaggerGraphState::userWalletBuilderFactory)
.create(scanResponse = backupInfo.scanResponse)
val userWallet = userWalletBuilder
.backupCardsIds(state.backupInfo.backupCardsIds)
.hasBackupError(hasBackupError)
.build()
.guard {
Timber.e("User wallet not created")
return@launch
}
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
userWalletsListManager.save(userWallet, canOverride = true)
.flatMap {
saveAccessCodeIfNeeded(accessCode = backupInfo.accessCode, cardsInWallet = userWallet.cardsInWallet)
}
.doOnFailure { error ->
Timber.e(error, "Unable to save user wallet")
}
.doOnSuccess {
store.onUserWalletSelected(userWallet)
if (!shouldNavigateToWallet) {
store.dispatchWithMain(OnboardingWalletAction.WalletSaved(userWallet.walletId))
}
}
.doOnResult { if (shouldNavigateToWallet) navigateToWallet() }
}
}
private fun enrollBiometrics() {
store.inject(DaggerGraphState::settingsManager).openBiometricSettings()
}
private fun allowToUseBiometrics(state: SaveWalletState) = scope.launch {
if (tangemSdkManager.checkNeedEnrollBiometrics()) {
store.dispatchWithMain(SaveWalletAction.EnrollBiometrics)
return@launch
}
if (state.backupInfo != null) {
// TODO: Remove after onboarding refactoring
Analytics.send(Onboarding.EnableBiometrics(AnalyticsParam.OnOffState.On))
} else {
Analytics.send(
MainScreenAnalyticsEvent.EnableBiometrics(
state = com.tangem.core.analytics.models.AnalyticsParam.OnOffState.On,
),
)
}
/*
* because it will be automatically saved on UserWalletsListManager switch
*/
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)
val selectedUserWallet = userWalletsListManager.selectedUserWalletSync.guard {
val error = IllegalStateException("No selected user wallet")
Timber.e(error, "Unable to save user wallet")
store.dispatchWithMain(
SaveWalletAction.AllowToUseBiometrics.Error(TangemSdkError.ExceptionError(error)),
)
return@launch
}
handleSuccessAllowing(selectedUserWallet)
}.saveIn(saveWalletJobHolder)
private suspend fun handleSuccessAllowing(userWallet: UserWallet) {
store.inject(DaggerGraphState::walletsRepository).saveShouldSaveUserWallets(item = true)
store.inject(DaggerGraphState::settingsRepository).setShouldSaveAccessCodes(value = true)
store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
isBiometricsRequestPolicy = userWallet.hasAccessCode,
)
store.dispatchWithMain(SaveWalletAction.AllowToUseBiometrics.Success)
store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) }
}
private fun dismiss(state: SaveWalletState) {
if (state.backupInfo != null) {
// TODO: Remove after onboarding refactoring
Analytics.send(Onboarding.EnableBiometrics(AnalyticsParam.OnOffState.Off))
} else {
Analytics.send(
MainScreenAnalyticsEvent.EnableBiometrics(
com.tangem.core.analytics.models.AnalyticsParam.OnOffState.Off,
),
)
}
}
private suspend fun saveAccessCodeIfNeeded(
accessCode: String?,
cardsInWallet: Set<String>,
): CompletionResult<Unit> {
return when {
accessCode.isNullOrBlank() -> {
CompletionResult.Success(Unit)
}
else -> {
tangemSdkManager.saveAccessCode(
accessCode = accessCode,
cardsIds = cardsInWallet,
)
}
}
}
private fun navigateToWallet() {
store.dispatchNavigationAction {
replaceAll(AppRoute.Wallet)
}
}
}

View file

@ -1,53 +0,0 @@
package com.tangem.tap.features.saveWallet.redux
import com.tangem.tap.common.redux.AppState
import org.rekotlin.Action
internal object SaveWalletReducer {
fun reduce(action: Action, state: AppState): SaveWalletState {
return if (action is SaveWalletAction) {
internalReduce(action, state.saveWalletState)
} else {
state.saveWalletState
}
}
private fun internalReduce(action: SaveWalletAction, state: SaveWalletState): SaveWalletState {
return when (action) {
is SaveWalletAction.ProvideBackupInfo -> state.copy(
backupInfo = SaveWalletState.WalletBackupInfo(
scanResponse = action.scanResponse,
accessCode = action.accessCode,
backupCardsIds = action.backupCardsIds,
),
)
is SaveWalletAction.AllowToUseBiometrics,
-> state.copy(isSaveInProgress = true)
is SaveWalletAction.AllowToUseBiometrics.Error -> state.copy(
error = action.error,
isSaveInProgress = false,
)
is SaveWalletAction.AllowToUseBiometrics.Success -> state.copy(
backupInfo = null,
isSaveInProgress = false,
)
is SaveWalletAction.Dismiss -> state.copy(
backupInfo = null,
)
is SaveWalletAction.CloseError -> state.copy(
error = null,
)
is SaveWalletAction.EnrollBiometrics -> state.copy(
needEnrollBiometrics = true,
)
is SaveWalletAction.EnrollBiometrics.Enroll,
is SaveWalletAction.EnrollBiometrics.Cancel,
-> state.copy(
needEnrollBiometrics = false,
isSaveInProgress = false,
)
is SaveWalletAction.SaveWalletAfterBackup,
-> state
}
}
}

View file

@ -1,18 +0,0 @@
package com.tangem.tap.features.saveWallet.redux
import com.tangem.common.core.TangemError
import com.tangem.domain.models.scan.ScanResponse
import org.rekotlin.StateType
data class SaveWalletState(
val backupInfo: WalletBackupInfo? = null,
val isSaveInProgress: Boolean = false,
val needEnrollBiometrics: Boolean = false,
val error: TangemError? = null,
) : StateType {
data class WalletBackupInfo(
val scanResponse: ScanResponse,
val accessCode: String?,
val backupCardsIds: Set<String>?,
)
}

View file

@ -1,81 +0,0 @@
package com.tangem.tap.features.saveWallet.ui
import android.content.DialogInterface
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.fragment.app.viewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.ui.UiDependencies
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.screen.ComposeBottomSheetFragment
import com.tangem.tap.features.details.ui.cardsettings.resolveReference
import com.tangem.tap.features.saveWallet.ui.components.EnrollBiometricsDialogContent
import com.tangem.tap.features.saveWallet.ui.components.SaveWalletScreenContent
import com.tangem.tap.features.saveWallet.ui.models.EnrollBiometricsDialog
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
internal class SaveWalletBottomSheetFragment : ComposeBottomSheetFragment() {
@Inject
override lateinit var uiDependencies: UiDependencies
override val expandedHeightFraction: Float = .98f
private val viewModel by viewModels<SaveWalletViewModel>()
override fun onCancel(dialog: DialogInterface) {
viewModel.cancelOrClose()
super.onCancel(dialog)
}
@Composable
override fun ScreenContent(modifier: Modifier) {
val state by viewModel.state.collectAsStateWithLifecycle()
val snackbarHostState = remember { SnackbarHostState() }
val errorMessage by rememberUpdatedState(newValue = state.error?.resolveReference())
val enrollBiometricsDialog by rememberUpdatedState(newValue = state.enrollBiometricsDialog)
Box(modifier = modifier) {
SaveWalletScreenContent(
showProgress = state.showProgress,
onSaveWalletClick = viewModel::saveWallet,
onCloseClick = {
viewModel.cancelOrClose()
dismissAllowingStateLoss()
},
)
SnackbarHost(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(vertical = TangemTheme.dimens.spacing16)
.fillMaxWidth(),
hostState = snackbarHostState,
)
}
EnrollBiometricsDialog(dialog = enrollBiometricsDialog)
LaunchedEffect(key1 = errorMessage) {
errorMessage?.let {
snackbarHostState.showSnackbar(it)
viewModel.closeError()
}
}
}
@Suppress("TopLevelComposableFunctions")
@Composable
private fun EnrollBiometricsDialog(dialog: EnrollBiometricsDialog?) {
if (dialog == null) return
EnrollBiometricsDialogContent(dialog)
}
}

View file

@ -1,12 +0,0 @@
package com.tangem.tap.features.saveWallet.ui
import androidx.compose.runtime.Immutable
import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.tap.features.saveWallet.ui.models.EnrollBiometricsDialog
@Immutable
internal data class SaveWalletScreenState(
val showProgress: Boolean = false,
val enrollBiometricsDialog: EnrollBiometricsDialog? = null,
val error: TextReference? = null,
)

View file

@ -1,92 +0,0 @@
package com.tangem.tap.features.saveWallet.ui
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.settings.SetSaveWalletScreenShownUseCase
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.features.details.ui.cardsettings.TextReference
import com.tangem.tap.features.saveWallet.redux.SaveWalletAction
import com.tangem.tap.features.saveWallet.redux.SaveWalletState
import com.tangem.tap.features.saveWallet.ui.models.EnrollBiometricsDialog
import com.tangem.tap.store
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.rekotlin.StoreSubscriber
import javax.inject.Inject
@HiltViewModel
internal class SaveWalletViewModel @Inject constructor(
private val analyticsEventHandler: AnalyticsEventHandler,
private val setSaveWalletScreenShownUseCase: SetSaveWalletScreenShownUseCase,
dispatchers: AppCoroutineDispatcherProvider,
) : ViewModel(), StoreSubscriber<SaveWalletState> {
private val stateInternal = MutableStateFlow(SaveWalletScreenState())
val state: StateFlow<SaveWalletScreenState> = stateInternal
init {
subscribeToStoreChanges()
viewModelScope.launch(dispatchers.main) {
setSaveWalletScreenShownUseCase()
}
}
fun saveWallet() {
analyticsEventHandler.send(WalletScreenAnalyticsEvent.MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.On))
store.dispatch(SaveWalletAction.AllowToUseBiometrics)
}
fun cancelOrClose() {
analyticsEventHandler.send(
WalletScreenAnalyticsEvent.MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.Off),
)
store.dispatch(SaveWalletAction.Dismiss)
}
fun closeError() {
store.dispatch(SaveWalletAction.CloseError)
}
override fun newState(state: SaveWalletState) {
stateInternal.update { prevState ->
prevState.copy(
showProgress = state.isSaveInProgress,
enrollBiometricsDialog = if (state.needEnrollBiometrics) createEnrollBiometricsDialog() else null,
error = state.error
?.takeUnless { it.silent }
?.let { error ->
error.messageResId?.let { TextReference.Res(it) }
?: TextReference.Str(error.customMessage)
},
)
}
}
override fun onCleared() {
store.unsubscribe(this)
}
private fun subscribeToStoreChanges() {
store.subscribe(this) { appState ->
appState.skip { old, new -> old.saveWalletState == new.saveWalletState }
.select { it.saveWalletState }
}
}
private fun createEnrollBiometricsDialog() = EnrollBiometricsDialog(
onEnroll = {
store.dispatchOnMain(SaveWalletAction.EnrollBiometrics.Enroll)
},
onCancel = {
store.dispatchOnMain(SaveWalletAction.EnrollBiometrics.Cancel)
},
)
}

View file

@ -1,52 +0,0 @@
package com.tangem.tap.features.saveWallet.ui.components
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.R
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.tap.features.saveWallet.ui.models.EnrollBiometricsDialog
@Composable
fun EnrollBiometricsDialogContent(dialog: EnrollBiometricsDialog) {
BasicDialog(
title = stringResourceSafe(R.string.save_user_wallet_agreement_enroll_biometrics_title),
message = stringResourceSafe(R.string.save_user_wallet_agreement_enroll_biometrics_description),
confirmButton = DialogButtonUM(
title = stringResourceSafe(R.string.common_enable),
onClick = dialog.onEnroll,
),
dismissButton = DialogButtonUM(
onClick = dialog.onCancel,
),
onDismissDialog = dialog.onCancel,
)
}
// region Preview
@Composable
private fun EnrollBiometricDialogContentSample(modifier: Modifier = Modifier) {
Column(
modifier = modifier
.background(TangemTheme.colors.background.primary),
) {
EnrollBiometricsDialogContent(dialog = EnrollBiometricsDialog({}, {}))
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun EnrollBiometricDialogContentPreview() {
TangemThemePreview {
EnrollBiometricDialogContentSample()
}
}
// endregion Preview

View file

@ -1,193 +0,0 @@
package com.tangem.tap.features.saveWallet.ui.components
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
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.painter.Painter
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.wallet.R
@Composable
internal fun SaveWalletScreenContent(showProgress: Boolean, onSaveWalletClick: () -> Unit, onCloseClick: () -> Unit) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Header(onCloseClick = onCloseClick)
SpacerHHalf()
Title(modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing22))
SpacerH32()
Description(
modifier = Modifier
.padding(
start = TangemTheme.dimens.spacing34,
end = TangemTheme.dimens.spacing56,
)
.fillMaxWidth(),
)
SpacerHHalf()
Footer(
showProgress = showProgress,
onSaveWalletClick = onSaveWalletClick,
)
SpacerH16()
}
}
@Composable
private fun Header(onCloseClick: () -> Unit) {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
) {
Hand()
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End,
) {
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()
}
}
}
@Composable
private fun Title(modifier: Modifier = Modifier) {
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing32),
) {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size56),
painter = painterResource(id = R.drawable.ic_fingerprint_24),
tint = TangemTheme.colors.icon.primary1,
contentDescription = null,
)
Text(
text = stringResourceSafe(id = R.string.save_user_wallet_agreement_header_biometrics),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
)
}
}
@Composable
private fun Description(modifier: Modifier = Modifier) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing24),
horizontalAlignment = Alignment.Start,
) {
DescriptionItem(
iconPainter = painterResource(id = R.drawable.ic_face_recognition_24),
title = stringResourceSafe(id = R.string.save_user_wallet_agreement_access_title),
description = stringResourceSafe(id = R.string.save_user_wallet_agreement_access_description),
)
DescriptionItem(
iconPainter = painterResource(id = R.drawable.ic_lock_24),
title = stringResourceSafe(id = R.string.save_user_wallet_agreement_code_title),
description = stringResourceSafe(id = R.string.save_user_wallet_agreement_code_description_biometrics),
)
}
}
@Composable
private fun Footer(showProgress: Boolean, onSaveWalletClick: () -> Unit) {
Column(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens.spacing16)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
) {
PrimaryButton(
modifier = Modifier.fillMaxWidth(),
showProgress = showProgress,
text = stringResourceSafe(id = R.string.save_user_wallet_agreement_allow_biometrics),
onClick = onSaveWalletClick,
)
Text(
modifier = Modifier.fillMaxWidth(fraction = .7f),
text = stringResourceSafe(R.string.save_user_wallet_agreement_notice),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,
)
}
}
@Composable
private fun DescriptionItem(iconPainter: Painter, title: String, description: String) {
Row(
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.SpaceEvenly,
) {
Icon(
modifier = Modifier.size(TangemTheme.dimens.size24),
painter = iconPainter,
tint = TangemTheme.colors.icon.primary1,
contentDescription = null,
)
SpacerW24()
Column {
Text(
text = title,
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.primary1,
)
SpacerH4()
Text(
text = description,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.secondary,
)
}
}
}
// region Preview
@Composable
private fun SaveWalletScreenContentSample(modifier: Modifier = Modifier) {
Column(
modifier = modifier
.background(TangemTheme.colors.background.primary),
) {
SaveWalletScreenContent(
showProgress = false,
onSaveWalletClick = { /* no-op */ },
onCloseClick = { /* no-op */ },
)
}
}
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun SaveWalletScreenContentPreview() {
TangemThemePreview {
SaveWalletScreenContentSample()
}
}
// endregion Preview

View file

@ -1,9 +0,0 @@
package com.tangem.tap.features.saveWallet.ui.models
import androidx.compose.runtime.Immutable
@Immutable
data class EnrollBiometricsDialog(
val onEnroll: () -> Unit,
val onCancel: () -> Unit,
)

View file

@ -33,7 +33,6 @@ import com.tangem.tap.features.details.ui.resetcard.api.ResetCardComponent
import com.tangem.tap.features.details.ui.securitymode.api.SecurityModeComponent
import com.tangem.tap.features.details.ui.walletconnect.api.WalletConnectComponent
import com.tangem.tap.features.home.api.HomeComponent
import com.tangem.tap.features.saveWallet.ui.SaveWalletBottomSheetFragment
import com.tangem.tap.features.welcome.component.WelcomeComponent
import com.tangem.tap.routing.component.RoutingComponent.Child
import com.tangem.tap.routing.toggle.RoutingFeatureToggles
@ -41,7 +40,7 @@ import com.tangem.utils.Provider
import dagger.hilt.android.scopes.ActivityScoped
import java.util.WeakHashMap
import javax.inject.Inject
import com.tangem.features.walletconnect.components.WalletConnectEntryComponent as RedisegnedWalletConnectComponent
import com.tangem.features.walletconnect.components.WalletConnectEntryComponent as RedesignedWalletConnectComponent
@ActivityScoped
@Suppress("LongParameterList", "LargeClass")
@ -77,7 +76,7 @@ internal class ChildFactory @Inject constructor(
private val walletComponentFactory: WalletEntryComponent.Factory,
private val sendComponentFactoryV2: com.tangem.features.send.v2.api.SendComponent.Factory,
private val sendFeatureToggles: SendFeatureToggles,
private val redesignedWalletConnectComponentFactory: RedisegnedWalletConnectComponent.Factory,
private val redesignedWalletConnectComponentFactory: RedesignedWalletConnectComponent.Factory,
private val nftComponentFactory: NFTComponent.Factory,
private val nftSendComponentFactory: NFTSendComponent.Factory,
private val testerRouter: TesterRouter,
@ -419,8 +418,6 @@ internal class ChildFactory @Inject constructor(
componentFactory = nftSendComponentFactory,
)
}
is AppRoute.SaveWallet,
-> error("Unsupported route: $route")
}
// endregion
}
@ -448,9 +445,6 @@ internal class ChildFactory @Inject constructor(
componentFactory = appCurrencySelectorComponentFactory,
)
}
is AppRoute.SaveWallet -> {
route.asFragmentChild(Provider { SaveWalletBottomSheetFragment() })
}
is AppRoute.Send -> {
if (sendFeatureToggles.isSendV2Enabled) {
route.asComponentChild(