Updated on 2026-08-14
This commit is contained in:
parent
72c9e20396
commit
514e142989
8 changed files with 70 additions and 45 deletions
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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<TangemPayCardPageUM>
|
||||
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))
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
internal fun AccountStatus.Payment.firstCard(): TangemPayCard = requireLoaded().cards.first()
|
||||
|
||||
internal inline fun <T> 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()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue