diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardFrozenState.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardFrozenState.kt index b9c0e53cdd..f6cfe18244 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardFrozenState.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/pay/TangemPayCardFrozenState.kt @@ -2,6 +2,7 @@ package com.tangem.domain.models.pay import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import java.util.Locale @Serializable enum class TangemPayCardFrozenState { @@ -22,9 +23,9 @@ enum class TangemPayCardFrozenState { } companion object { - fun fromString(value: String) = when (value) { - "Frozen" -> Frozen - "Unfrozen" -> Unfrozen + fun fromString(value: String) = when (value.lowercase(Locale.US)) { + "frozen" -> Frozen + "unfrozen" -> Unfrozen else -> Pending } } diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt index 58d8d1acc6..fd905dc50e 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayAddToWalletComponent.kt @@ -13,7 +13,6 @@ import com.tangem.features.tangempay.components.cardDetails.DefaultTangemPayCard import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetailsBlockComponent import com.tangem.features.tangempay.model.TangemPayAddToWalletModel import com.tangem.features.tangempay.ui.TangemPayAddToWalletScreen -import com.tangem.features.tangempay.utils.firstCard import com.tangem.features.tangempay.utils.userWalletId internal class TangemPayAddToWalletComponent( @@ -26,7 +25,7 @@ internal class TangemPayAddToWalletComponent( private val cardDetailsBlockComponent = DefaultTangemPayCardDetailsBlockComponent( appComponentContext = child("cardDetailsBlockComponent"), params = TangemPayCardDetailsBlockComponent.Params( - card = params.initialStatus.firstCard(), + initialStatus = params.initialStatus, userWalletId = params.initialStatus.userWalletId, isEditingNameEnabled = false, ), diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt index f2dcb1d346..b68a2c3d74 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayCardPageScreenComponent.kt @@ -35,7 +35,7 @@ internal class TangemPayCardPageScreenComponent( private val cardDetailsBlockComponent = DefaultTangemPayCardDetailsBlockComponent( appComponentContext = child("cardDetailsBlockComponent"), params = TangemPayCardDetailsBlockComponent.Params( - card = params.initialStatus.firstCard(), + initialStatus = params.initialStatus, userWalletId = params.initialStatus.userWalletId, isEditingNameEnabled = true, ), diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt index f59d7bde31..b70a927a75 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/TangemPayEditDisplayNameComponent.kt @@ -14,7 +14,6 @@ import com.tangem.features.tangempay.components.cardDetails.TangemPayCardDetails import com.tangem.features.tangempay.entity.DisplayNameState import com.tangem.features.tangempay.model.TangemPayEditDisplayNameModel import com.tangem.features.tangempay.ui.TangemPayEditDisplayNameScreen -import com.tangem.features.tangempay.utils.firstCard import com.tangem.features.tangempay.utils.userWalletId internal class TangemPayEditDisplayNameComponent( @@ -27,7 +26,7 @@ internal class TangemPayEditDisplayNameComponent( private val cardDetailsBlockComponent = DefaultTangemPayCardDetailsBlockComponent( appComponentContext = child("editDisplayNameCardDetails"), params = TangemPayCardDetailsBlockComponent.Params( - card = params.initialStatus.firstCard(), + initialStatus = params.initialStatus, userWalletId = params.initialStatus.userWalletId, isEditingNameEnabled = false, ), diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/cardDetails/TangemPayCardDetailsBlockComponent.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/cardDetails/TangemPayCardDetailsBlockComponent.kt index 750250f2c1..8d556c14b1 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/cardDetails/TangemPayCardDetailsBlockComponent.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/components/cardDetails/TangemPayCardDetailsBlockComponent.kt @@ -3,7 +3,7 @@ package com.tangem.features.tangempay.components.cardDetails import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.ui.Modifier -import com.tangem.domain.models.pay.TangemPayCard +import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.wallet.UserWalletId import com.tangem.features.tangempay.entity.TangemPayCardDetailsUM import kotlinx.coroutines.flow.StateFlow @@ -16,7 +16,7 @@ internal interface TangemPayCardDetailsBlockComponent { fun CardDetailsBlockContent(state: TangemPayCardDetailsUM, modifier: Modifier) data class Params( - val card: TangemPayCard, + val initialStatus: AccountStatus.Payment, val userWalletId: UserWalletId, val isEditingNameEnabled: Boolean, ) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt index 27bebaf727..9565030d30 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardDetailsBlockModel.kt @@ -12,10 +12,7 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.message.SnackbarMessage import com.tangem.domain.models.StatusSource import com.tangem.domain.models.account.PaymentAccountStatusValue -import com.tangem.domain.models.account.hasCardWithId -import com.tangem.domain.models.account.requireCardWithId import com.tangem.domain.models.pay.TangemPayCardFrozenState -import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository import com.tangem.domain.tangempay.TangemPayAnalyticsEvents @@ -30,11 +27,14 @@ import com.tangem.features.tangempay.model.transformers.DetailsRevealProgressSta import com.tangem.features.tangempay.model.transformers.DetailsRevealedStateTransformer import com.tangem.features.tangempay.model.transformers.TangemPayCardDetailsUpdateNameTransformer import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute +import com.tangem.features.tangempay.utils.findCard +import com.tangem.features.tangempay.utils.firstCard import com.tangem.utils.StringsSigns import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn import com.tangem.utils.transformer.update +import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch @@ -59,11 +59,12 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor( ) : Model() { private val params: TangemPayCardDetailsBlockComponent.Params = paramsContainer.require() - private val card = params.card + private val initialCard = params.initialStatus.firstCard() + private var frozenStateJob: Job? = null private val stateFactory = TangemPayCardDetailsBlockStateFactory( - cardNumberEnd = card.lastDigits, - displayName = card.displayName, + cardNumberEnd = initialCard.lastDigits, + displayName = initialCard.displayName, isEditingNameEnabled = params.isEditingNameEnabled, onEditNameClick = ::startEditingDisplayName, onReveal = ::requestReveal, @@ -77,8 +78,7 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor( private val showCardDetailsTimerJobHolder = JobHolder() init { - subscribeToCardChanges(cardId = card.id, userWalletId = params.userWalletId) - subscribeToCardFrozenState() + subscribeToCardChanges() modelScope.launch { cardDetailsEventListener.event.collectLatest { event -> when (event) { @@ -89,15 +89,12 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor( } } - private fun subscribeToCardChanges(cardId: String, userWalletId: UserWalletId) { - paymentAccountStatusSupplier.invoke(userWalletId) + private fun subscribeToCardChanges() { + paymentAccountStatusSupplier.invoke(params.userWalletId) .onEach { state -> val status = state.value - if (status is PaymentAccountStatusValue.Loaded && - status.source == StatusSource.ACTUAL && - status.hasCardWithId(cardId) - ) { - val card = status.requireCardWithId(cardId) + if (status is PaymentAccountStatusValue.Loaded && status.source == StatusSource.ACTUAL) { + val card = state.findCard(initialCard.id, params.initialStatus) ?: return@onEach if (card.isReissuing) { requestHide() } @@ -109,13 +106,15 @@ internal class TangemPayCardDetailsBlockModel @Inject constructor( isActionsAvailable = !card.isReissuing, ) } + subscribeToCardFrozenState(card.id) } } .launchIn(modelScope) } - private fun subscribeToCardFrozenState() { - cardDetailsRepository.cardFrozenState(card.id) + private fun subscribeToCardFrozenState(cardId: String) { + frozenStateJob?.cancel() + frozenStateJob = cardDetailsRepository.cardFrozenState(cardId) .onEach { cardFrozenState -> if (cardFrozenState == TangemPayCardFrozenState.Pending) { uiState.update { state -> state.copy(cardFrozenState = TangemPayCardFrozenState.Pending) } diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt index f5d80cda1e..0694b3694b 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/model/TangemPayCardPageModel.kt @@ -24,8 +24,6 @@ import com.tangem.core.ui.test.TangemPayTestTags import com.tangem.domain.models.StatusSource import com.tangem.domain.models.TokenReceiveConfig import com.tangem.domain.models.account.PaymentAccountStatusValue -import com.tangem.domain.models.account.hasCardWithId -import com.tangem.domain.models.account.requireCardWithId import com.tangem.domain.models.pay.TangemPayCard import com.tangem.domain.models.pay.TangemPayCardLimitPeriod import com.tangem.domain.models.pay.isFrozen @@ -43,10 +41,7 @@ import com.tangem.features.tangempay.entity.* import com.tangem.features.tangempay.model.listener.CardDetailsEvent import com.tangem.features.tangempay.model.listener.CardDetailsEventListener import com.tangem.features.tangempay.navigation.TangemPayCardDetailsInnerRoute -import com.tangem.features.tangempay.utils.TangemPayMessagesFactory -import com.tangem.features.tangempay.utils.cryptoCurrency -import com.tangem.features.tangempay.utils.firstCard -import com.tangem.features.tangempay.utils.userWalletId +import com.tangem.features.tangempay.utils.* import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn @@ -75,14 +70,18 @@ internal class TangemPayCardPageModel @Inject constructor( ) : Model(), ViewPinListener, ReissueCardListener, AddFundsListener { private val params: TangemPayCardPageComponent.Params = paramsContainer.require() - private val cardId: String = params.initialStatus.firstCard().id - private val userWalletId = params.initialStatus.userWalletId - private val cryptoCurrency = params.initialStatus.cryptoCurrency private val addToWalletBannerJobHolder = JobHolder() private val addFundsJobHolder = JobHolder() private val frozenStateJobHolder = JobHolder() + private val currentStatus = MutableStateFlow(params.initialStatus) + private val initialCardId = params.initialStatus.firstCard().id + private val userWalletId = currentStatus.value.userWalletId + + private val cryptoCurrency + get() = currentStatus.value.cryptoCurrency + val uiState: StateFlow field = MutableStateFlow( TangemPayCardPageUM( @@ -102,12 +101,10 @@ internal class TangemPayCardPageModel @Inject constructor( paymentAccountStatusSupplier.invoke(userWalletId) .onEach { state -> + currentStatus.update { state } val status = state.value - if (status is PaymentAccountStatusValue.Loaded && - status.source == StatusSource.ACTUAL && - status.hasCardWithId(cardId) - ) { - val card = status.requireCardWithId(cardId) + if (status is PaymentAccountStatusValue.Loaded && status.source == StatusSource.ACTUAL) { + val card = state.findCard(initialCardId, params.initialStatus) ?: return@onEach val limit = card.limit?.actualCardLimit?.takeIf { it.period == TangemPayCardLimitPeriod.DAY } val dailyLimitState = if (limit != null) { TangemPayDailyLimitBlockState.Content( @@ -228,10 +225,11 @@ internal class TangemPayCardPageModel @Inject constructor( if (!isPinSet) { router.push(TangemPayCardDetailsInnerRoute.ChangePIN) } else { + val card = currentStatus.value.findCard(initialCardId, params.initialStatus) ?: return bottomSheetNavigation.activate( TangemPayCardNavigation.ViewPinCode( userWalletId = userWalletId, - cardId = cardId, + cardId = card.id, ), ) } @@ -313,10 +311,11 @@ internal class TangemPayCardPageModel @Inject constructor( } private fun freezeCard() { + val card = currentStatus.value.findCard(initialCardId, params.initialStatus) ?: return modelScope.launch { changeCardFrozenStateUseCase( userWalletId = userWalletId, - cardId = cardId, + cardId = card.id, isFreezing = true, ).onLeft { val message = SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_failed)) @@ -329,10 +328,11 @@ internal class TangemPayCardPageModel @Inject constructor( } private fun unfreezeCard() { + val card = currentStatus.value.findCard(initialCardId, params.initialStatus) ?: return modelScope.launch { changeCardFrozenStateUseCase( userWalletId = userWalletId, - cardId = cardId, + cardId = card.id, isFreezing = false, ).onLeft { val message = SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_failed)) diff --git a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/PaymentAccountStatusExt.kt b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/PaymentAccountStatusExt.kt index 025bf5a7b8..29ab477218 100644 --- a/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/PaymentAccountStatusExt.kt +++ b/features/tangempay/details/impl/src/main/kotlin/com/tangem/features/tangempay/utils/PaymentAccountStatusExt.kt @@ -1,7 +1,9 @@ package com.tangem.features.tangempay.utils +import com.tangem.domain.models.StatusSource import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.PaymentAccountStatusValue +import com.tangem.domain.models.account.findCardWithId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.pay.TangemPayCard import com.tangem.domain.models.wallet.UserWalletId @@ -23,4 +25,29 @@ internal fun AccountStatus.Payment.requireLoaded(): PaymentAccountStatusValue.Lo value as? PaymentAccountStatusValue.Loaded ?: error("Card-detail subflow requires Loaded status, got ${value::class.simpleName}") -internal fun AccountStatus.Payment.firstCard(): TangemPayCard = requireLoaded().cards.first() \ No newline at end of file +internal fun AccountStatus.Payment.firstCard(): TangemPayCard = requireLoaded().cards.first() + +internal inline fun AccountStatus.Payment.ifLoadedOrNull(call: (PaymentAccountStatusValue.Loaded) -> T): T? { + val value = value + return if (value is PaymentAccountStatusValue.Loaded) { + call(value) + } else { + null + } +} + +internal fun AccountStatus.Payment.findCard( + initialCardId: String, + initialStatus: AccountStatus.Payment, +): TangemPayCard? { + val value = value + + if (value !is PaymentAccountStatusValue.Loaded || value.source != StatusSource.ACTUAL) return null + + val initialCard = value.findCardWithId(initialCardId) + val newCards = initialStatus.ifLoadedOrNull { status -> + val initialCardIds = status.cards.mapTo(mutableSetOf()) { it.id } + value.cards.filterNot { it.id in initialCardIds } + } + return initialCard ?: newCards?.firstOrNull() +} \ No newline at end of file