Updated on 2026-08-14
This commit is contained in:
parent
e080401183
commit
f97a017f3f
22 changed files with 28 additions and 854 deletions
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>?,
|
||||
)
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue