Updated on 2026-08-14
This commit is contained in:
parent
1edf995ab0
commit
2dadb60975
26 changed files with 1110 additions and 48 deletions
|
|
@ -16,6 +16,7 @@ import com.tangem.domain.wallets.hot.HotWalletAccessCodeAttemptsRepository
|
|||
import com.tangem.domain.wallets.hot.HotWalletAccessCodeAttemptsRepository.Attempts
|
||||
import com.tangem.domain.wallets.hot.HotWalletAccessCodeAttemptsRepository.Companion.MAX_FAST_FORWARD_ATTEMPTS
|
||||
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||
import com.tangem.domain.wallets.usecase.DeleteWalletUseCase
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.features.hotwallet.accesscode.ACCESS_CODE_LENGTH
|
||||
import com.tangem.features.hotwallet.accesscoderequest.entity.HotAccessCodeRequestUM
|
||||
|
|
@ -37,6 +38,7 @@ internal class HotAccessCodeRequestModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val hotAccessCodeAttemptsRepository: HotWalletAccessCodeAttemptsRepository,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val deleteWalletUseCase: DeleteWalletUseCase,
|
||||
private val canUseBiometryUseCase: CanUseBiometryUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val startAssetsDiscoveryUseCase: StartAssetsDiscoveryUseCase,
|
||||
|
|
@ -224,7 +226,7 @@ internal class HotAccessCodeRequestModel @Inject constructor(
|
|||
startAssetsDiscoveryUseCase.cancel(userWallet.walletId)
|
||||
}
|
||||
|
||||
userWalletsListRepository.delete(listOf(userWallet.walletId))
|
||||
deleteWalletUseCase(userWallet.walletId)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ internal sealed class TangemPayDetailsBalanceBlockState {
|
|||
override val cardsBlockState: CardsBlockState?,
|
||||
val fiatBalance: TextReference,
|
||||
val isBalanceFlickering: Boolean,
|
||||
val isMuted: Boolean = false,
|
||||
) : TangemPayDetailsBalanceBlockState()
|
||||
|
||||
data class Error(
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ 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.account.TangemPayCustomerTariffPlan
|
||||
|
|
@ -139,17 +140,25 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
.onEach { state ->
|
||||
when (state) {
|
||||
is PaymentAccountStatusValue.Deactivated -> {
|
||||
val balanceTransformer = DetailsBalanceTransformer(
|
||||
fiatBalance = state.balance.fiatBalance,
|
||||
isMuted = state.source != StatusSource.ACTUAL,
|
||||
)
|
||||
uiState.update {
|
||||
stateFactory.getDeactivatedState(
|
||||
hasWithdrawableBalance = state.balance.hasWithdrawableAmount,
|
||||
balanceTransformer.transform(
|
||||
stateFactory.getDeactivatedState(
|
||||
hasWithdrawableBalance = state.balance.hasWithdrawableAmount,
|
||||
),
|
||||
)
|
||||
}
|
||||
uiState.update(DetailsBalanceTransformer(state.balance.fiatBalance))
|
||||
}
|
||||
is PaymentAccountStatusValue.Loaded -> {
|
||||
fetchAddToWalletBanner()
|
||||
uiState.update { stateFactory.getLoadedState(state) }
|
||||
uiState.update(DetailsBalanceTransformer(state.balance.fiatBalance))
|
||||
val balanceTransformer = DetailsBalanceTransformer(
|
||||
fiatBalance = state.balance.fiatBalance,
|
||||
isMuted = !state.isFresh,
|
||||
)
|
||||
uiState.update { balanceTransformer.transform(stateFactory.getLoadedState(state)) }
|
||||
state.cards.firstOrNull()?.let { card ->
|
||||
subscribeToCardFrozenState(card.id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import java.util.Currency
|
|||
|
||||
internal class DetailsBalanceTransformer(
|
||||
private val fiatBalance: PaymentAccountStatusValue.FiatBalance,
|
||||
private val isMuted: Boolean = false,
|
||||
) : Transformer<TangemPayDetailsUM> {
|
||||
|
||||
override fun transform(prevState: TangemPayDetailsUM): TangemPayDetailsUM {
|
||||
|
|
@ -20,6 +21,7 @@ internal class DetailsBalanceTransformer(
|
|||
fiatBalance = getFiatBalanceText(fiatBalance),
|
||||
actionButtons = prevState.balanceBlockState.actionButtons,
|
||||
cardsBlockState = prevState.balanceBlockState.cardsBlockState,
|
||||
isMuted = isMuted,
|
||||
)
|
||||
return prevState.copy(balanceBlockState = balance)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -355,21 +355,28 @@ private fun BalanceBlock(
|
|||
style = TextShimmerStyle.HEADING_MEDIUM,
|
||||
radius = TangemTheme.dimens2.x25,
|
||||
)
|
||||
is TangemPayDetailsBalanceBlockState.Content -> Text(
|
||||
modifier = Modifier.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_BALANCE),
|
||||
text = animatedState.fiatBalance.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography3.display.medium.applyBladeBrush(
|
||||
isEnabled = animatedState.isBalanceFlickering,
|
||||
textColor = TangemTheme.colors3.text.primary,
|
||||
),
|
||||
color = TangemTheme.colors3.text.primary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
autoSize = TextAutoSize.StepBased(
|
||||
minFontSize = TangemTheme.typography3.heading.medium.fontSize,
|
||||
maxFontSize = TangemTheme.typography3.display.medium.fontSize,
|
||||
),
|
||||
)
|
||||
is TangemPayDetailsBalanceBlockState.Content -> {
|
||||
val balanceColor = if (animatedState.isMuted) {
|
||||
TangemTheme.colors3.text.secondary
|
||||
} else {
|
||||
TangemTheme.colors3.text.primary
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_BALANCE),
|
||||
text = animatedState.fiatBalance.orMaskWithStars(isBalanceHidden).resolveAnnotatedReference(),
|
||||
style = TangemTheme.typography3.display.medium.applyBladeBrush(
|
||||
isEnabled = animatedState.isBalanceFlickering,
|
||||
textColor = balanceColor,
|
||||
),
|
||||
color = balanceColor,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
autoSize = TextAutoSize.StepBased(
|
||||
minFontSize = TangemTheme.typography3.heading.medium.fontSize,
|
||||
maxFontSize = TangemTheme.typography3.display.medium.fontSize,
|
||||
),
|
||||
)
|
||||
}
|
||||
is TangemPayDetailsBalanceBlockState.Error -> Text(
|
||||
modifier = Modifier.testTag(TangemPayTestTags.PAYMENT_ACCOUNT_BALANCE),
|
||||
text = DASH_SIGN.orMaskWithStars(isBalanceHidden),
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
|||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.features.tangempay.addFundsButton
|
||||
import com.tangem.features.tangempay.components.TangemPayDetailsContainerComponent
|
||||
import com.tangem.features.tangempay.entity.TangemPayDetailsBalanceBlockState
|
||||
import com.tangem.features.tangempay.tangemPayCard
|
||||
import com.tangem.features.tangempay.withdrawButton
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
|
|
@ -57,15 +58,36 @@ internal class TangemPayDetailsModelTest {
|
|||
model.onDestroy()
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideMutedCases")
|
||||
fun `GIVEN status source WHEN status loaded THEN balance is muted only when cached`(case: MutedCase) = runTest {
|
||||
// Arrange + Act
|
||||
val model = createModel(
|
||||
testScope = this,
|
||||
statusSource = case.statusSource,
|
||||
frozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
availableForWithdrawal = BigDecimal.ZERO,
|
||||
accountError = case.accountError,
|
||||
)
|
||||
advanceUntilIdle()
|
||||
|
||||
// Assert
|
||||
val balanceState = model.uiState.value.balanceBlockState
|
||||
assertThat(balanceState).isInstanceOf(TangemPayDetailsBalanceBlockState.Content::class.java)
|
||||
assertThat((balanceState as TangemPayDetailsBalanceBlockState.Content).isMuted).isEqualTo(case.expectedMuted)
|
||||
model.onDestroy()
|
||||
}
|
||||
|
||||
private fun createModel(
|
||||
testScope: TestScope,
|
||||
statusSource: StatusSource,
|
||||
frozenState: TangemPayCardFrozenState,
|
||||
availableForWithdrawal: BigDecimal,
|
||||
accountError: PaymentAccountStatusValue.Error? = null,
|
||||
): TangemPayDetailsModel {
|
||||
val loaded: PaymentAccountStatusValue.Loaded = mockk(relaxed = true) {
|
||||
every { source } returns statusSource
|
||||
every { error } returns null
|
||||
every { error } returns accountError
|
||||
every { cards } returns listOf(tangemPayCard())
|
||||
every { balance } returns PaymentAccountStatusValue.Balance(
|
||||
fiatBalance = PaymentAccountStatusValue.FiatBalance(
|
||||
|
|
@ -135,6 +157,12 @@ internal class TangemPayDetailsModelTest {
|
|||
val expectedWithdrawEnabled: Boolean,
|
||||
)
|
||||
|
||||
internal data class MutedCase(
|
||||
val statusSource: StatusSource,
|
||||
val expectedMuted: Boolean,
|
||||
val accountError: PaymentAccountStatusValue.Error? = null,
|
||||
)
|
||||
|
||||
private companion object {
|
||||
@JvmStatic
|
||||
fun provideFreezeCases() = listOf(
|
||||
|
|
@ -167,5 +195,18 @@ internal class TangemPayDetailsModelTest {
|
|||
expectedWithdrawEnabled = false,
|
||||
),
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun provideMutedCases() = listOf(
|
||||
MutedCase(statusSource = StatusSource.ACTUAL, expectedMuted = false),
|
||||
MutedCase(statusSource = StatusSource.CACHE, expectedMuted = true),
|
||||
MutedCase(statusSource = StatusSource.ONLY_CACHE, expectedMuted = true),
|
||||
// ACTUAL but errored is still not fresh -> muted (guards !isFresh, not just source != ACTUAL)
|
||||
MutedCase(
|
||||
statusSource = StatusSource.ACTUAL,
|
||||
accountError = PaymentAccountStatusValue.Error.Unavailable,
|
||||
expectedMuted = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue