diff --git a/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt index 4f41cea873..918b41ff04 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/CardDomainModule.kt @@ -5,6 +5,8 @@ import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.demo.DemoConfig import com.tangem.domain.demo.IsDemoCardUseCase +import com.tangem.domain.wallets.legacy.WalletsStateHolder +import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase import com.tangem.tap.domain.TangemSdkManager import com.tangem.tap.domain.card.DefaultDerivePublicKeysUseCase import dagger.Module @@ -62,4 +64,10 @@ internal object CardDomainModule { fun provideDerivePublicKeysUseCase(tangemSdkManager: TangemSdkManager): DerivePublicKeysUseCase { return DefaultDerivePublicKeysUseCase(tangemSdkManager = tangemSdkManager) } + + @Provides + @ViewModelScoped + fun provideIsNeedToBackupUseCase(walletStateHolder: WalletsStateHolder): IsNeedToBackupUseCase { + return IsNeedToBackupUseCase(walletStateHolder) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index 2ab9ded42f..e686d2f730 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -450,6 +450,23 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) Analytics.send(Onboarding.Backup.Finished(backupState.backupCardsNumber)) } + userWalletsListManager.selectedUserWalletSync?.walletId?.let { + scope.launch { + userWalletsListManager.update( + userWalletId = it, + update = { wallet -> + wallet.copy( + scanResponse = updateScanResponseAfterBackup( + scanResponse = wallet.scanResponse, + backupState = backupState, + ), + ) + }, + ) + store.dispatchOnMain(GlobalAction.UpdateUserWalletsListManager(userWalletsListManager)) + } + } + val notActivatedCardIds = gatherCardIds(backupState, card) .mapNotNull { if (cardActivationIsFinished(it)) null else it } diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/IsNeedToBackupUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/IsNeedToBackupUseCase.kt new file mode 100644 index 0000000000..24fdc5a232 --- /dev/null +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/IsNeedToBackupUseCase.kt @@ -0,0 +1,27 @@ +package com.tangem.domain.wallets.usecase + +import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.wallets.legacy.WalletsStateHolder +import com.tangem.domain.wallets.models.UserWalletId +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +/** + * Use case that checks if wallet need backup cards + */ +class IsNeedToBackupUseCase(private val walletsStateHolder: WalletsStateHolder) { + + operator fun invoke(id: UserWalletId): Flow { + val userWalletsListManager = requireNotNull(walletsStateHolder.userWalletsListManager) + + return userWalletsListManager.userWallets + .map { wallets -> + val wallet = wallets.firstOrNull { it.walletId == id } + if (wallet == null) { + false + } else { + wallet.scanResponse.card.backupStatus is CardDTO.BackupStatus.NoBackup + } + } + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt index 0671449433..59e36af357 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt @@ -43,6 +43,7 @@ internal object WalletPreviewData { imageResId = R.drawable.ill_businessman_3d, onRenameClick = { _, _ -> }, onDeleteClick = {}, + cardCount = 1, ) } @@ -65,6 +66,7 @@ internal object WalletPreviewData { onDeleteClick = {}, balance = "8923,05 $", additionalInfo = TextReference.Str("3 cards • Seed phrase"), + cardCount = 1, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletCardState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletCardState.kt index c9830c2a7b..c968de0013 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletCardState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/components/WalletCardState.kt @@ -34,6 +34,7 @@ internal sealed interface WalletCardState { * @property onRenameClick lambda be invoked when Rename button is clicked * @property onDeleteClick lambda be invoked when Delete button is clicked * @property additionalInfo wallet additional info + * @property cardCount number of cards in the wallet * @property balance wallet balance */ data class Content( @@ -43,6 +44,7 @@ internal sealed interface WalletCardState { override val onRenameClick: (UserWalletId, String) -> Unit, override val onDeleteClick: (UserWalletId) -> Unit, val additionalInfo: TextReference, + val cardCount: Int?, val balance: String, ) : WalletCardState @@ -55,6 +57,7 @@ internal sealed interface WalletCardState { * @property onRenameClick lambda be invoked when Rename button is clicked * @property onDeleteClick lambda be invoked when Delete button is clicked * @property additionalInfo wallet additional info + * @property cardCount number of cards in the wallet * @property balance wallet balance */ data class HiddenContent( @@ -65,6 +68,7 @@ internal sealed interface WalletCardState { override val onDeleteClick: (UserWalletId) -> Unit, val additionalInfo: TextReference, val balance: String, + val cardCount: Int?, ) : WalletCardState /** diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt index ff8df226a1..ccfbe015bc 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt @@ -11,6 +11,7 @@ import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory +import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount import com.tangem.feature.wallet.presentation.wallet.state.WalletMultiCurrencyState import com.tangem.feature.wallet.presentation.wallet.state.WalletSingleCurrencyState import com.tangem.feature.wallet.presentation.wallet.state.WalletState @@ -96,6 +97,7 @@ internal class WalletSingleCurrencyLoadedBalanceConverter( onRenameClick = selectedWallet.onRenameClick, onDeleteClick = selectedWallet.onDeleteClick, balance = formatFiatAmount(status = status, appCurrency = appCurrencyProvider()), + cardCount = currentWalletProvider().getCardsCount(), ) } is CryptoCurrencyStatus.Loading -> { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt index 92783093a4..a46a50cc2c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletStateFactory.kt @@ -61,6 +61,13 @@ internal class WalletStateFactory( private val hiddenStateConverter by lazy { HiddenStateConverter(currentStateProvider) } + private val walletUpdateCardCountConverter by lazy { + WalletUpdateCardCountConverter( + currentStateProvider, + currentWalletProvider, + ) + } + private val tokenListErrorConverter by lazy { TokenListErrorConverter(currentStateProvider) } @@ -134,6 +141,8 @@ internal class WalletStateFactory( fun getStateWithUpdatedWalletName(name: String): WalletState = walletRenameStateConverter.convert(value = name) + fun getStateWithUpdatedWalletCardCount(): WalletState = walletUpdateCardCountConverter.convert(Unit) + fun getUnlockedState(action: WalletsUpdateActionResolver.Action.UnlockWallet): WalletState { return walletsUnlockStateConverter.convert(value = action) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletUpdateCardCountConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletUpdateCardCountConverter.kt new file mode 100644 index 0000000000..805f3168b4 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletUpdateCardCountConverter.kt @@ -0,0 +1,56 @@ +package com.tangem.feature.wallet.presentation.wallet.state.factory + +import com.tangem.common.Provider +import com.tangem.domain.wallets.models.UserWallet +import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory +import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount +import com.tangem.feature.wallet.presentation.wallet.state.WalletState +import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState +import com.tangem.feature.wallet.presentation.wallet.state.components.WalletsListConfig +import com.tangem.utils.converter.Converter +import kotlinx.collections.immutable.toImmutableList + +internal class WalletUpdateCardCountConverter( + private val currentStateProvider: Provider, + private val currentWalletProvider: Provider, +) : Converter { + + override fun convert(value: Unit): WalletState { + return when (val state = currentStateProvider()) { + is WalletState.ContentState -> { + state.copySealed( + walletsListConfig = state.walletsListConfig.refreshCardCount(), + ) + } + is WalletState.Initial -> state + } + } + + private fun WalletsListConfig.refreshCardCount(): WalletsListConfig { + return copy( + wallets = wallets + .mapIndexed { index, walletCard -> + if (index == selectedWalletIndex) { + when (walletCard) { + is WalletCardState.Content -> walletCard.copy( + additionalInfo = WalletAdditionalInfoFactory.resolve( + wallet = currentWalletProvider(), + ), + cardCount = currentWalletProvider().getCardsCount(), + ) + is WalletCardState.HiddenContent -> walletCard.copy( + additionalInfo = WalletAdditionalInfoFactory.resolve( + wallet = currentWalletProvider(), + ), + cardCount = currentWalletProvider().getCardsCount(), + ) + else -> walletCard + } + } else { + walletCard + } + } + .toImmutableList(), + ) + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/FiatBalanceToWalletCardConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/FiatBalanceToWalletCardConverter.kt index 89e3ff8be5..bca1082c42 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/FiatBalanceToWalletCardConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/FiatBalanceToWalletCardConverter.kt @@ -6,6 +6,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.TokenList.FiatBalance import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory +import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState import com.tangem.utils.converter.Converter @@ -54,6 +55,7 @@ internal class FiatBalanceToWalletCardConverter( fiatCurrencySymbol = appCurrency.symbol, ), additionalInfo = WalletAdditionalInfoFactory.resolve(wallet = currentWalletProvider()), + cardCount = currentWalletProvider().getCardsCount(), ) } else { WalletCardState.Content( @@ -68,6 +70,7 @@ internal class FiatBalanceToWalletCardConverter( fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol, ), + cardCount = currentWalletProvider().getCardsCount(), ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/WalletHiddenBalanceStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/WalletHiddenBalanceStateConverter.kt index 7f29843cea..eb85c8f42e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/WalletHiddenBalanceStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/WalletHiddenBalanceStateConverter.kt @@ -25,6 +25,7 @@ internal class WalletHiddenBalanceStateConverter { onRenameClick = content.onRenameClick, onDeleteClick = content.onDeleteClick, balance = content.balance, + cardCount = content.cardCount, ) } @@ -37,6 +38,7 @@ internal class WalletHiddenBalanceStateConverter { onRenameClick = hiddenContent.onRenameClick, onDeleteClick = hiddenContent.onDeleteClick, balance = hiddenContent.balance, + cardCount = hiddenContent.cardCount, ) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt index 928b02cc55..8c0fa79e8d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletNotificationsListFactory.kt @@ -6,6 +6,8 @@ import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.settings.IsReadyToShowRateAppUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase import com.tangem.feature.wallet.presentation.wallet.state.components.WalletNotification import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -16,9 +18,10 @@ import kotlin.collections.count /** * Wallet notifications list factory * - * @property isDemoCardUseCase use case that check if card is demo - * @property isReadyToShowRateAppUseCase use case that check if card is user already rate app - * @property wasCardScannedUseCase use case that check if card was scanned + * @property isDemoCardUseCase use case that checks if card is demo + * @property isReadyToShowRateAppUseCase use case that checks if card is user already rate app + * @property wasCardScannedUseCase use case that checks if card was scanned + * @property isNeedToBackupUseCase use case that checks if wallet need backup cards * @property clickIntents screen click intents * [REDACTED_AUTHOR] @@ -27,17 +30,20 @@ internal class WalletNotificationsListFactory( private val isDemoCardUseCase: IsDemoCardUseCase, private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase, private val wasCardScannedUseCase: WasCardScannedUseCase, + private val isNeedToBackupUseCase: IsNeedToBackupUseCase, private val clickIntents: WalletClickIntents, ) { fun create( + selectedWalletId: UserWalletId, cardTypesResolver: CardTypesResolver, cryptoCurrencyList: List, ): Flow> { return combine( flow = wasCardScannedUseCase(cardTypesResolver.getCardId()), flow2 = isReadyToShowRateAppUseCase(), - ) { wasCardScanned, isReadyToShowRating -> + flow3 = isNeedToBackupUseCase(selectedWalletId), + ) { wasCardScanned, isReadyToShowRating, isNeedToBackup -> buildList { addCriticalNotifications(cardTypesResolver) @@ -45,7 +51,7 @@ internal class WalletNotificationsListFactory( addRateTheAppNotification(isReadyToShowRating) - addWarningNotifications(cardTypesResolver, cryptoCurrencyList, wasCardScanned) + addWarningNotifications(cardTypesResolver, cryptoCurrencyList, wasCardScanned, isNeedToBackup) }.toImmutableList() } } @@ -116,12 +122,13 @@ internal class WalletNotificationsListFactory( cardTypesResolver: CardTypesResolver, cryptoCurrencyList: List, wasCardScanned: Boolean, + isNeedToBackup: Boolean, ) { addIf( element = WalletNotification.Warning.MissingBackup( onStartBackupClick = clickIntents::onBackupCardClick, ), - condition = !cardTypesResolver.isBackupForbidden() && !cardTypesResolver.hasBackup(), + condition = isNeedToBackup, ) val isDemo = isDemoCardUseCase(cardId = cardTypesResolver.getCardId()) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 015c3e99a5..f0c38778bf 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -122,6 +122,7 @@ internal class WalletViewModel @Inject constructor( wasCardScannedUseCase: WasCardScannedUseCase, isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase, isDemoCardUseCase: IsDemoCardUseCase, + isNeedToBackupUseCase: IsNeedToBackupUseCase, // endregion Parameters ) : ViewModel(), DefaultLifecycleObserver, WalletClickIntents { @@ -135,6 +136,7 @@ internal class WalletViewModel @Inject constructor( wasCardScannedUseCase = wasCardScannedUseCase, isReadyToShowRateAppUseCase = isReadyToShowRateAppUseCase, isDemoCardUseCase = isDemoCardUseCase, + isNeedToBackupUseCase = isNeedToBackupUseCase, clickIntents = this, ) @@ -227,6 +229,9 @@ internal class WalletViewModel @Inject constructor( is WalletsUpdateActionResolver.Action.AddWallet -> { scrollAndUpdateState(action.selectedWalletIndex) } + is WalletsUpdateActionResolver.Action.UpdateWalletCardCount -> { + uiState = stateFactory.getStateWithUpdatedWalletCardCount() + } is WalletsUpdateActionResolver.Action.Unknown -> Unit } } @@ -983,6 +988,7 @@ internal class WalletViewModel @Inject constructor( private fun updateNotifications(index: Int, tokenList: TokenList? = null) { notificationsListFactory.create( + selectedWalletId = getWallet(index).walletId, cardTypesResolver = getCardTypeResolver(index = index), cryptoCurrencyList = if (tokenList != null) { when (tokenList) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt index 101f025d4e..bc8aa4f61a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolver.kt @@ -4,6 +4,7 @@ import com.tangem.common.Provider import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase +import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount import com.tangem.feature.wallet.presentation.wallet.state.WalletLockedState import com.tangem.feature.wallet.presentation.wallet.state.WalletState import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState @@ -110,20 +111,29 @@ internal class WalletsUpdateActionResolver( selectedWallet: UserWallet, ): Action { val selectedWalletName = selectedWallet.name + val previousWalletState = state.getPrevSelectedWallet() + return when { + previousWalletState.title != selectedWalletName -> { + Action.UpdateWalletName(selectedWalletName) + } - if (state.getPrevSelectedWallet().title != selectedWalletName) { - return Action.UpdateWalletName(selectedWalletName) + state is WalletLockedState && !selectedWallet.isLocked -> { + Action.UnlockWallet( + selectedWalletIndex = wallets.indexOfWallet(id = selectedWallet.walletId), + selectedWallet = selectedWallet, + unlockedWallets = wallets.filterNot(UserWallet::isLocked), + ) + } + + previousWalletState is WalletCardState.Content && + previousWalletState.cardCount != selectedWallet.getCardsCount() || + previousWalletState is WalletCardState.HiddenContent && + previousWalletState.cardCount != selectedWallet.getCardsCount() -> { + Action.UpdateWalletCardCount + } + + else -> Action.Unknown } - - if (state is WalletLockedState && !selectedWallet.isLocked) { - return Action.UnlockWallet( - selectedWalletIndex = wallets.indexOfWallet(id = selectedWallet.walletId), - selectedWallet = selectedWallet, - unlockedWallets = wallets.filterNot(UserWallet::isLocked), - ) - } - - return Action.Unknown } private fun WalletState.ContentState.getPrevSelectedWallet(): WalletCardState { @@ -163,6 +173,8 @@ internal class WalletsUpdateActionResolver( data class AddWallet(val selectedWalletIndex: Int) : Action() + object UpdateWalletCardCount : Action() + object Unknown : Action() } } \ No newline at end of file