diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt index 93810c48da..87edec2202 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt @@ -62,7 +62,7 @@ internal class DefaultUserWalletsListRepository( // If we don't save persistent information, we don't need to load user wallets // and we should clear any existing data clearPersistentData() - userWallets.value = emptyList() + updateWallets { emptyList() } return } @@ -118,7 +118,7 @@ internal class DefaultUserWalletsListRepository( } // update the userWallets state and add if it doesn't exist - userWallets.update { currentWallets -> + updateWallets { currentWallets -> val wallets = currentWallets ?: emptyList() if (wallets.any { it.walletId == userWallet.walletId }) { wallets.map { if (it.walletId == userWallet.walletId) userWallet else it } @@ -248,7 +248,7 @@ internal class DefaultUserWalletsListRepository( removePasswordAttempts(userWallet) sensitiveInformationRepository.getAll(listOf(encryptionKey)) - .doOnSuccess { sensitiveInfo -> userWallets.update { it?.updateWith(sensitiveInfo) } } + .doOnSuccess { sensitiveInfo -> updateWallets { it?.updateWith(sensitiveInfo) } } .doOnFailure { error -> raise(UnlockWalletError.UnableToUnlock) } @@ -306,7 +306,7 @@ internal class DefaultUserWalletsListRepository( sensitiveInformationRepository.getAll(allKeys) .doOnSuccess { sensitiveInfo -> - userWallets.update { it?.updateWith(sensitiveInfo) } + updateWallets { it?.updateWith(sensitiveInfo) } } .doOnFailure { raise(UnlockWalletError.UnableToUnlock) } } @@ -318,7 +318,7 @@ internal class DefaultUserWalletsListRepository( raise(LockWalletsError.NothingToLock) } - userWallets.update { + updateWallets { it?.map { if (it.walletId !in unsecuredWalletIds) { it.lock() @@ -389,6 +389,15 @@ internal class DefaultUserWalletsListRepository( return tangemSdkManagerProvider.invoke().canUseBiometry && useBiometricAuthentication } + private fun updateWallets(block: (List?) -> List?) { + userWallets.update(block) + + selectedUserWallet.update { currentSelected -> + if (currentSelected == null) return@update null + userWallets.value?.find { it.walletId == currentSelected.walletId } + } + } + /** * Find the nearest available wallet that can be selected * 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 e7a00027c6..d90595d32f 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 @@ -363,6 +363,9 @@ internal class WalletModel @Inject constructor( is WalletsUpdateActionResolver.Action.RenameWallets -> { stateHolder.update(transformer = RenameWalletsTransformer(renamedWallets = action.renamedWallets)) } + is WalletsUpdateActionResolver.Action.ReloadWarningsForWallets -> { + reloadWarnings(action) + } WalletsUpdateActionResolver.Action.EmptyWallets -> { Timber.w("Wallets list is empty!") } @@ -372,6 +375,17 @@ internal class WalletModel @Inject constructor( } } + private fun reloadWarnings(action: WalletsUpdateActionResolver.Action.ReloadWarningsForWallets) { + action.wallets.forEach { + walletScreenContentLoader.load( + userWallet = it, + clickIntents = clickIntents, + coroutineScope = modelScope, + isRefresh = true, + ) + } + } + private suspend fun initializeWallets(action: WalletsUpdateActionResolver.Action.InitializeWallets) { stateHolder.update( transformer = InitializeWalletsTransformer( diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt index 3e9a4d114b..5c27b29b42 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletsUpdateActionResolver.kt @@ -9,6 +9,7 @@ import com.tangem.domain.models.wallet.isLocked import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase import com.tangem.feature.wallet.presentation.wallet.state.model.NOT_INITIALIZED_WALLET_INDEX import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState +import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification import com.tangem.feature.wallet.presentation.wallet.state.model.WalletScreenState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import timber.log.Timber @@ -75,10 +76,20 @@ internal class WalletsUpdateActionResolver @Inject constructor( isAnyWalletNameChanged(state, wallets) -> { getRenameWalletsAction(state, wallets) } + isAnyHotWalletBackedUp(state, wallets) -> { + getHotWalletsBackedUpAction(state, wallets) + } else -> getUpdateSelectedWalletAction(state, wallets, selectedWallet) } } + private fun isAnyHotWalletBackedUp(state: WalletScreenState, wallets: List): Boolean { + val incompleteActivationWalletIds = state.incompleteActivationWalletIds() + return incompleteActivationWalletIds.mapNotNull { walletId -> + wallets.firstOrNull { it.walletId == walletId && it is UserWallet.Hot && it.backedUp } + }.isNotEmpty() + } + private fun isWalletsCountChanged(state: WalletScreenState, wallets: List): Boolean { val prevWalletsSize = state.wallets.size val walletsSize = wallets.size @@ -145,6 +156,20 @@ internal class WalletsUpdateActionResolver @Inject constructor( return prevWalletsIds == newWalletsIds && isAnyNameChanged } + private fun getHotWalletsBackedUpAction( + state: WalletScreenState, + wallets: List, + ): Action.ReloadWarningsForWallets { + val incompleteActivationWalletIds = state.incompleteActivationWalletIds() + + val walletsToUpdate = wallets.filter { + it is UserWallet.Hot && it.backedUp && + incompleteActivationWalletIds.contains(it.walletId) + } + + return Action.ReloadWarningsForWallets(walletsToUpdate) + } + private fun getRenameWalletsAction(state: WalletScreenState, wallets: List): Action.RenameWallets { val prevWallets = state.wallets.map { it.walletCardState.id to it.walletCardState.title } val newWallets = wallets.map { it.walletId to it.name } @@ -199,6 +224,16 @@ internal class WalletsUpdateActionResolver @Inject constructor( ?: error("Previous selected wallet is not found") } + private fun WalletScreenState.incompleteActivationWalletIds(): List { + return wallets.mapNotNull { + if (it.warnings.any { it is WalletNotification.FinishWalletActivation }) { + it.walletCardState.id + } else { + null + } + } + } + private fun List.indexOfWallet(id: UserWalletId): Int { val selectedIndex = indexOfFirst { it.walletId == id } @@ -323,6 +358,10 @@ internal class WalletsUpdateActionResolver @Inject constructor( } } + data class ReloadWarningsForWallets( + val wallets: List, + ) : Action() + data object EmptyWallets : Action() data object Unknown : Action() diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt index cc5a440140..da6c773a77 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt @@ -24,6 +24,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBot import com.tangem.feature.wallet.presentation.wallet.state.transformers.OpenBottomSheetTransformer import com.tangem.feature.wallet.presentation.wallet.state.transformers.converter.MultiWalletCurrencyActionsConverter import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender +import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.take @@ -76,9 +77,16 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( private val reduxStateHolder: ReduxStateHolder, private val walletEventSender: WalletEventSender, private val analyticsEventHandler: AnalyticsEventHandler, + private val hotWalletFeatureToggles: HotWalletFeatureToggles, ) : BaseWalletClickIntents(), WalletContentClickIntents { override fun onDetailsClick() { + if (hotWalletFeatureToggles.isHotWalletEnabled) { + router.openDetailsScreen(stateHolder.getSelectedWalletId()) + return + } + + // Will be removed after Hot Wallet release modelScope.launch(dispatchers.main) { val userWalletId = stateHolder.getSelectedWalletId() val userWallet = getUserWalletUseCase(userWalletId).getOrElse { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt index 28d03a317a..203128c7ce 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletWarningsClickIntents.kt @@ -12,6 +12,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase import com.tangem.domain.card.SetCardWasScannedUseCase import com.tangem.domain.feedback.GetWalletMetaInfoUseCase +import com.tangem.domain.core.wallets.UserWalletsListRepository import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.models.currency.CryptoCurrency @@ -44,6 +45,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletBottomShe import com.tangem.feature.wallet.presentation.wallet.state.model.WalletEvent import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBottomSheetTransformer import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender +import com.tangem.features.hotwallet.HotWalletFeatureToggles import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll @@ -117,6 +119,8 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher, private val stakingIdFactory: StakingIdFactory, private val appRouter: AppRouter, + private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val userWalletsListRepository: UserWalletsListRepository, ) : BaseWalletClickIntents(), WalletWarningsClickIntents { override fun onAddBackupCardClick() { @@ -168,6 +172,22 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( override fun onOpenUnlockWalletsBottomSheetClick() { analyticsEventHandler.send(MainScreen.WalletUnlockTapped) + if (hotWalletFeatureToggles.isHotWalletEnabled) { + modelScope.launch { + userWalletsListRepository.unlockAllWallets() + .onLeft { + val selectedUserWallet = getSelectedUserWallet() ?: return@onLeft + val method = when (selectedUserWallet) { + is UserWallet.Cold -> UserWalletsListRepository.UnlockMethod.Scan + is UserWallet.Hot -> UserWalletsListRepository.UnlockMethod.AccessCode + } + userWalletsListRepository.unlock(stateHolder.getSelectedWalletId(), method) + } + } + return + } + + // Will be removed after hot wallet release stateHolder.showBottomSheet( WalletBottomSheetConfig.UnlockWallets( onUnlockClick = this::onUnlockWalletClick, @@ -176,6 +196,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( ) } + @Deprecated("Will be removed with hot wallet release") override fun onUnlockWalletClick() { analyticsEventHandler.send(MainScreen.UnlockAllWithBiometrics) @@ -203,6 +224,7 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor( walletEventSender.send(event) } + @Deprecated("Will be removed with hot wallet release") override fun onScanToUnlockWalletClick() { analyticsEventHandler.send(MainScreen.UnlockWithCardScan) openScanCardDialog()