Updated on 2026-08-14
This commit is contained in:
parent
0cceaf3110
commit
d99a6bf31e
11 changed files with 137 additions and 40 deletions
|
|
@ -11,6 +11,7 @@ data class TangemPayDetailsConfig(
|
|||
val isPinSet: Boolean,
|
||||
val cardFrozenState: TangemPayCardFrozenState,
|
||||
val cardNumberEnd: String,
|
||||
val isReissuing: Boolean,
|
||||
val chainId: Int,
|
||||
val isTangemPayDeactivated: Boolean,
|
||||
val displayName: CardDisplayName?,
|
||||
|
|
|
|||
|
|
@ -65,9 +65,9 @@ internal class DefaultTangemPayDetailsContainerComponent @AssistedInject constru
|
|||
tokenReceiveComponentFactory = tokenReceiveComponentFactory,
|
||||
expressTransactionsComponentProvider = expressTransactionsComponentProvider,
|
||||
)
|
||||
TangemPayAccountDetailsInnerRoute.CardDetails -> tangemPayCardPageFactory.create(
|
||||
is TangemPayAccountDetailsInnerRoute.CardDetails -> tangemPayCardPageFactory.create(
|
||||
context = childByContext(componentContext = componentContext, router = innerRouter),
|
||||
params = TangemPayCardPageComponent.Params(userWalletId = params.userWalletId, config = params.config),
|
||||
params = TangemPayCardPageComponent.Params(userWalletId = params.userWalletId, config = config.config),
|
||||
)
|
||||
TangemPayAccountDetailsInnerRoute.AddToWallet -> TangemPayAddToWalletComponent(
|
||||
appComponentContext = childByContext(componentContext = componentContext, router = innerRouter),
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ internal class TangemPayDetailsStateFactory(
|
|||
private val cardFrozenState: TangemPayCardFrozenState,
|
||||
) {
|
||||
@Suppress("LongMethod")
|
||||
fun getInitialState(isTangemPayDeactivated: Boolean, cardNumberEnd: String): TangemPayDetailsUM {
|
||||
fun getInitialState(
|
||||
isTangemPayDeactivated: Boolean,
|
||||
cardNumberEnd: String,
|
||||
isReissuing: Boolean,
|
||||
): TangemPayDetailsUM {
|
||||
return TangemPayDetailsUM(
|
||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||
onBackClick = onBack,
|
||||
|
|
@ -51,7 +55,8 @@ internal class TangemPayDetailsStateFactory(
|
|||
cards = persistentListOf(
|
||||
TangemPayDetailsBalanceBlockState.Card(
|
||||
lastDigits = cardNumberEnd,
|
||||
onClick = intents::onCardClick,
|
||||
onClick = {},
|
||||
isReissuing = isReissuing,
|
||||
),
|
||||
),
|
||||
onAddCardClick = intents::onAddCardClick,
|
||||
|
|
|
|||
|
|
@ -84,7 +84,11 @@ internal sealed class TangemPayDetailsBalanceBlockState {
|
|||
) : TangemPayDetailsBalanceBlockState()
|
||||
|
||||
data class CardsBlockState(val cards: ImmutableList<Card>, val onAddCardClick: () -> Unit)
|
||||
data class Card(val lastDigits: String, val onClick: () -> Unit)
|
||||
data class Card(
|
||||
val lastDigits: String,
|
||||
val onClick: () -> Unit,
|
||||
val isReissuing: Boolean,
|
||||
)
|
||||
}
|
||||
|
||||
internal data class AddToWalletBlockState(
|
||||
|
|
|
|||
|
|
@ -19,10 +19,14 @@ import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
|||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.feedback.models.WalletMetaInfo
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.pay.TangemPayCryptoCurrencyFactory
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
||||
import com.tangem.domain.pay.model.TangemPayCardBalance
|
||||
import com.tangem.domain.pay.model.TangemPayTopUpData
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
|
|
@ -53,10 +57,7 @@ import com.tangem.utils.coroutines.saveIn
|
|||
import com.tangem.utils.logging.TangemLogger
|
||||
import com.tangem.utils.transformer.update
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -65,6 +66,7 @@ import javax.inject.Inject
|
|||
@ModelScoped
|
||||
internal class TangemPayDetailsModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
paymentAccountStatusSupplier: PaymentAccountStatusSupplier,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analytics: AnalyticsEventHandler,
|
||||
private val router: Router,
|
||||
|
|
@ -95,6 +97,7 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
stateFactory.getInitialState(
|
||||
isTangemPayDeactivated = params.config.isTangemPayDeactivated,
|
||||
cardNumberEnd = params.config.cardNumberEnd,
|
||||
isReissuing = params.config.isReissuing,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -118,6 +121,21 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
if (!params.config.isTangemPayDeactivated) {
|
||||
subscribeToCardFrozenState()
|
||||
fetchAddToWalletBanner()
|
||||
|
||||
paymentAccountStatusSupplier.invoke(params.userWalletId)
|
||||
.map { it.value }
|
||||
.filterIsInstance<PaymentAccountStatusValue.Loaded>()
|
||||
.filter { it.source == StatusSource.ACTUAL }
|
||||
.onEach { state ->
|
||||
val card = state.cards.firstOrNull() ?: return@onEach
|
||||
uiState.update(
|
||||
TangemPayCardDataTransformer(
|
||||
card = card,
|
||||
onCardClick = { onCardClick(params.config.copy(cardId = card.id)) },
|
||||
),
|
||||
)
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -363,9 +381,9 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
urlOpener.openUrl(TangemPayConstants.TERMS_AND_LIMITS_LINK)
|
||||
}
|
||||
|
||||
override fun onCardClick() {
|
||||
override fun onCardClick(config: TangemPayDetailsConfig) {
|
||||
analytics.send(TangemPayAnalyticsEvents.CardIconClicked())
|
||||
router.push(TangemPayAccountDetailsInnerRoute.CardDetails)
|
||||
router.push(TangemPayAccountDetailsInnerRoute.CardDetails(config))
|
||||
}
|
||||
|
||||
override fun onAddCardClick() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.features.tangempay.model.transformers
|
||||
|
||||
import com.tangem.domain.models.pay.TangemPayCard
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsBalanceBlockState
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal class TangemPayCardDataTransformer(
|
||||
private val card: TangemPayCard,
|
||||
private val onCardClick: () -> Unit,
|
||||
) : Transformer<TangemPayDetailsUM> {
|
||||
|
||||
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
|
||||
val updatedCard = TangemPayDetailsBalanceBlockState.Card(
|
||||
lastDigits = card.lastDigits,
|
||||
onClick = onCardClick,
|
||||
isReissuing = card.isReissuing,
|
||||
)
|
||||
val cardsBlockState = prevState.balanceBlockState.cardsBlockState.copy(
|
||||
cards = persistentListOf(updatedCard),
|
||||
)
|
||||
val newBalanceBlockState = when (val bs = prevState.balanceBlockState) {
|
||||
is TangemPayDetailsBalanceBlockState.Loading -> bs.copy(cardsBlockState = cardsBlockState)
|
||||
is TangemPayDetailsBalanceBlockState.Content -> bs.copy(cardsBlockState = cardsBlockState)
|
||||
is TangemPayDetailsBalanceBlockState.Error -> bs.copy(cardsBlockState = cardsBlockState)
|
||||
}
|
||||
return prevState.copy(balanceBlockState = newBalanceBlockState)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.tangempay.navigation
|
||||
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
|
|
@ -9,7 +10,7 @@ internal sealed class TangemPayAccountDetailsInnerRoute : Route {
|
|||
data object AccountDetails : TangemPayAccountDetailsInnerRoute()
|
||||
|
||||
@Serializable
|
||||
data object CardDetails : TangemPayAccountDetailsInnerRoute()
|
||||
data class CardDetails(val config: TangemPayDetailsConfig) : TangemPayAccountDetailsInnerRoute()
|
||||
|
||||
@Serializable
|
||||
data object AddToWallet : TangemPayAccountDetailsInnerRoute()
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.util.fastAny
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
|
|
@ -114,30 +115,45 @@ internal fun TangemPayDetailsScreen(
|
|||
SpacerH12()
|
||||
},
|
||||
)
|
||||
if (state.addToWalletBlockState != null) {
|
||||
|
||||
if (state.balanceBlockState.cardsBlockState.cards.fastAny { it.isReissuing }) {
|
||||
item(
|
||||
key = AddToWalletBlockState::class.java,
|
||||
key = "REISSUE_MESSAGE",
|
||||
content = {
|
||||
TangemPayAddToWalletBlock(
|
||||
state = state.addToWalletBlockState,
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
if (state.accountDeactivatedNotificationConfig != null) {
|
||||
item(
|
||||
key = "DEACTIVATION_MESSAGE",
|
||||
content = {
|
||||
Notification(
|
||||
modifier = modifier
|
||||
TangemPayReplacingCardBlock(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
config = state.accountDeactivatedNotificationConfig,
|
||||
)
|
||||
SpacerH12()
|
||||
},
|
||||
)
|
||||
} else {
|
||||
if (state.addToWalletBlockState != null) {
|
||||
item(
|
||||
key = AddToWalletBlockState::class.java,
|
||||
content = {
|
||||
TangemPayAddToWalletBlock(
|
||||
state = state.addToWalletBlockState,
|
||||
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
if (state.accountDeactivatedNotificationConfig != null) {
|
||||
item(
|
||||
key = "DEACTIVATION_MESSAGE",
|
||||
content = {
|
||||
Notification(
|
||||
modifier = modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
config = state.accountDeactivatedNotificationConfig,
|
||||
)
|
||||
SpacerH12()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
if (state.accountDeactivatedNotificationConfig == null) {
|
||||
with(expressTransactionsComponent) {
|
||||
|
|
@ -289,14 +305,26 @@ private fun TangemPayCardItem(card: TangemPayDetailsBalanceBlockState.Card, modi
|
|||
painter = painterResource(R.drawable.img_visa_card_48x32),
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomStart)
|
||||
.padding(4.dp, bottom = 2.dp),
|
||||
text = card.lastDigits,
|
||||
style = TangemTheme.typography.overline.copy(letterSpacing = 0.sp),
|
||||
color = TangemTheme.colors.text.constantWhite,
|
||||
)
|
||||
if (card.isReissuing) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(16.dp)
|
||||
.align(Alignment.BottomStart)
|
||||
.padding(2.dp),
|
||||
painter = painterResource(R.drawable.ic_update_32),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.text.constantWhite,
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomStart)
|
||||
.padding(4.dp, bottom = 2.dp),
|
||||
text = card.lastDigits,
|
||||
style = TangemTheme.typography.overline.copy(letterSpacing = 0.sp),
|
||||
color = TangemTheme.colors.text.constantWhite,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -421,8 +449,8 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<Ta
|
|||
isBalanceFlickering = false,
|
||||
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
|
||||
cards = persistentListOf(
|
||||
TangemPayDetailsBalanceBlockState.Card(lastDigits = "1234", onClick = {}),
|
||||
TangemPayDetailsBalanceBlockState.Card(lastDigits = "3456", onClick = {}),
|
||||
TangemPayDetailsBalanceBlockState.Card(lastDigits = "1234", onClick = {}, isReissuing = false),
|
||||
TangemPayDetailsBalanceBlockState.Card(lastDigits = "3456", onClick = {}, isReissuing = false),
|
||||
),
|
||||
onAddCardClick = {},
|
||||
),
|
||||
|
|
@ -438,7 +466,13 @@ private class TangemPayDetailsUMProvider : CollectionPreviewParameterProvider<Ta
|
|||
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
|
||||
actionButtons = persistentListOf(),
|
||||
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
|
||||
cards = persistentListOf(TangemPayDetailsBalanceBlockState.Card(lastDigits = "1234", onClick = {})),
|
||||
cards = persistentListOf(
|
||||
TangemPayDetailsBalanceBlockState.Card(
|
||||
lastDigits = "1234",
|
||||
onClick = {},
|
||||
isReissuing = true,
|
||||
),
|
||||
),
|
||||
onAddCardClick = {},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.tangempay.utils
|
||||
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig.ShowRefreshState
|
||||
import com.tangem.domain.pay.TangemPayDetailsConfig
|
||||
|
||||
internal interface TangemPayDetailIntents {
|
||||
fun onContactSupportClicked()
|
||||
|
|
@ -8,6 +9,6 @@ internal interface TangemPayDetailIntents {
|
|||
fun onClickAddFunds()
|
||||
fun onClickWithdraw()
|
||||
fun onClickTermsAndLimits()
|
||||
fun onCardClick()
|
||||
fun onCardClick(config: TangemPayDetailsConfig)
|
||||
fun onAddCardClick()
|
||||
}
|
||||
|
|
@ -53,6 +53,7 @@ internal class TangemPayCardLimitSetupModelTest {
|
|||
chainId = 1,
|
||||
isTangemPayDeactivated = false,
|
||||
displayName = null,
|
||||
isReissuing = false,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ internal class TangemPayMainBlockConverter(
|
|||
chainId = POLYGON_CHAIN_ID,
|
||||
displayName = null,
|
||||
isTangemPayDeactivated = true,
|
||||
isReissuing = false,
|
||||
),
|
||||
)
|
||||
},
|
||||
|
|
@ -114,6 +115,7 @@ internal class TangemPayMainBlockConverter(
|
|||
chainId = POLYGON_CHAIN_ID,
|
||||
displayName = card.displayName,
|
||||
isTangemPayDeactivated = false,
|
||||
isReissuing = card.isReissuing,
|
||||
),
|
||||
)
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue