Updated on 2026-08-14
This commit is contained in:
parent
2fd16863a7
commit
9b6de19ebe
25 changed files with 376 additions and 201 deletions
|
|
@ -52,6 +52,7 @@ dependencies {
|
|||
implementation(projects.domain.balanceHiding.models)
|
||||
implementation(projects.domain.transaction)
|
||||
implementation(projects.domain.analytics)
|
||||
implementation(projects.domain.visa)
|
||||
|
||||
implementation(projects.common)
|
||||
implementation(projects.core.analytics)
|
||||
|
|
@ -78,6 +79,7 @@ dependencies {
|
|||
implementation(projects.data.wallets)
|
||||
implementation(projects.data.analytics)
|
||||
implementation(projects.data.transaction)
|
||||
implementation(projects.data.visa)
|
||||
|
||||
/** Features */
|
||||
implementation(projects.features.onboarding)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.visa.GetVisaCurrencyUseCase
|
||||
import com.tangem.domain.visa.repository.VisaRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
internal object VisaDomainModule {
|
||||
|
||||
@Provides
|
||||
fun provideVisaCurrencyUseCase(visaRepository: VisaRepository): GetVisaCurrencyUseCase {
|
||||
return GetVisaCurrencyUseCase(visaRepository)
|
||||
}
|
||||
}
|
||||
1
data/visa/.gitignore
vendored
Normal file
1
data/visa/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
21
data/visa/build.gradle.kts
Normal file
21
data/visa/build.gradle.kts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.data.visa"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
/** Project - Domain */
|
||||
implementation(projects.domain.visa)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.core)
|
||||
kapt(deps.hilt.kapt)
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.data.visa
|
||||
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.domain.visa.repository.VisaRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
internal class DummyVisaRepository : VisaRepository {
|
||||
|
||||
override suspend fun getVisaCurrency(userWalletId: UserWalletId, isRefresh: Boolean): VisaCurrency {
|
||||
TODO(reason = "Implement in [REDACTED_JIRA]")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.data.visa.di
|
||||
|
||||
import com.tangem.data.visa.DummyVisaRepository
|
||||
import com.tangem.domain.visa.repository.VisaRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object VisaDataModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideVisaRepository(): VisaRepository {
|
||||
return DummyVisaRepository()
|
||||
}
|
||||
}
|
||||
|
|
@ -72,7 +72,10 @@ internal class TangemCardTypesResolver(
|
|||
override fun isSingleWalletWithToken(): Boolean = walletData?.token != null && !isMultiwalletAllowed()
|
||||
|
||||
override fun isMultiwalletAllowed(): Boolean {
|
||||
return !isTangemTwins() && !card.isStart2Coin && !isTangemNote() &&
|
||||
return !isTangemTwins() &&
|
||||
!card.isStart2Coin &&
|
||||
!isTangemNote() &&
|
||||
!isVisaWallet() &&
|
||||
(multiWalletAvailable() || card.wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1)
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +84,7 @@ internal class TangemCardTypesResolver(
|
|||
override fun getBlockchain(): Blockchain {
|
||||
return when (productType) {
|
||||
ProductType.Start2Coin -> if (card.isTestCard) Blockchain.BitcoinTestnet else Blockchain.Bitcoin
|
||||
ProductType.Visa -> Blockchain.PolygonTestnet
|
||||
else -> {
|
||||
val blockchainName: String = walletData?.blockchain
|
||||
?: if (productType == ProductType.Note) {
|
||||
|
|
|
|||
1
domain/visa/.gitignore
vendored
Normal file
1
domain/visa/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
22
domain/visa/build.gradle.kts
Normal file
22
domain/visa/build.gradle.kts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.domain.visa"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
/** Project - Domain */
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
|
||||
/** Libs - Other */
|
||||
implementation(deps.jodatime)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.domain.visa
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.domain.visa.repository.VisaRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
class GetVisaCurrencyUseCase(
|
||||
private val repository: VisaRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
isRefresh: Boolean = false,
|
||||
): Either<Throwable, VisaCurrency> {
|
||||
return Either.catch { repository.getVisaCurrency(userWalletId, isRefresh) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.domain.visa.model
|
||||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class VisaCurrency(
|
||||
val networkName: String,
|
||||
val symbol: String,
|
||||
val decimals: Int,
|
||||
val fiatRate: BigDecimal?,
|
||||
val fiatCurrency: AppCurrency,
|
||||
val balances: Balances,
|
||||
val limits: Limits,
|
||||
) {
|
||||
|
||||
data class Balances(
|
||||
val total: BigDecimal,
|
||||
val verified: BigDecimal,
|
||||
val available: BigDecimal,
|
||||
val blocked: BigDecimal,
|
||||
val debt: BigDecimal,
|
||||
val pendingRefund: BigDecimal,
|
||||
)
|
||||
|
||||
data class Limits(
|
||||
val remainingOtp: BigDecimal,
|
||||
val remainingNoOtp: BigDecimal,
|
||||
val singleTransaction: BigDecimal,
|
||||
val expirationDate: DateTime,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.domain.visa.repository
|
||||
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface VisaRepository {
|
||||
|
||||
suspend fun getVisaCurrency(userWalletId: UserWalletId, isRefresh: Boolean = false): VisaCurrency
|
||||
}
|
||||
|
|
@ -69,6 +69,7 @@ dependencies {
|
|||
implementation(projects.domain.balanceHiding)
|
||||
implementation(projects.domain.balanceHiding.models)
|
||||
implementation(projects.domain.analytics)
|
||||
implementation(projects.domain.visa)
|
||||
|
||||
//TODO: Create api/impl modules for onboarding [REDACTED_JIRA]
|
||||
implementation(projects.features.onboarding)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
||||
import com.tangem.domain.visa.GetVisaCurrencyUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.subscribers.PrimaryCurrencySubscriber
|
||||
import com.tangem.feature.wallet.presentation.wallet.subscribers.TxHistorySubscriber
|
||||
import com.tangem.feature.wallet.presentation.wallet.subscribers.VisaWalletBalancesAndLimitsSubscriber
|
||||
import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscriber
|
||||
|
|
@ -21,24 +18,20 @@ internal class VisaWalletContentLoader(
|
|||
private val isRefresh: Boolean,
|
||||
private val stateHolder: WalletStateController,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
|
||||
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
|
||||
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,
|
||||
) : WalletContentLoader(id = userWallet.walletId) {
|
||||
|
||||
override fun create(): List<WalletSubscriber> {
|
||||
return listOf(
|
||||
PrimaryCurrencySubscriber(
|
||||
VisaWalletBalancesAndLimitsSubscriber(
|
||||
userWallet = userWallet,
|
||||
stateHolder = stateHolder,
|
||||
getPrimaryCurrencyStatusUpdatesUseCase = getPrimaryCurrencyStatusUpdatesUseCase,
|
||||
setWalletWithFundsFoundUseCase = setWalletWithFundsFoundUseCase,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||
isRefresh = isRefresh,
|
||||
getVisaCurrencyUseCase = getVisaCurrencyUseCase,
|
||||
clickIntents = clickIntents,
|
||||
),
|
||||
VisaWalletBalancesAndLimitsSubscriber(userWallet, stateHolder, clickIntents),
|
||||
TxHistorySubscriber(
|
||||
userWallet = userWallet,
|
||||
isRefresh = isRefresh,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.settings.SetWalletWithFundsFoundUseCase
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
||||
import com.tangem.domain.visa.GetVisaCurrencyUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
|
|
@ -17,11 +15,9 @@ import javax.inject.Inject
|
|||
internal class VisaWalletContentLoaderFactory @Inject constructor(
|
||||
private val stateHolder: WalletStateController,
|
||||
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val setWalletWithFundsFoundUseCase: SetWalletWithFundsFoundUseCase,
|
||||
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
|
||||
private val txHistoryItemsUseCase: GetTxHistoryItemsUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,
|
||||
) {
|
||||
|
||||
fun create(userWallet: UserWallet, clickIntents: WalletClickIntentsV2, isRefresh: Boolean): WalletContentLoader {
|
||||
|
|
@ -31,11 +27,9 @@ internal class VisaWalletContentLoaderFactory @Inject constructor(
|
|||
isRefresh = isRefresh,
|
||||
stateHolder = stateHolder,
|
||||
getPrimaryCurrencyStatusUpdatesUseCase = getPrimaryCurrencyStatusUpdatesUseCase,
|
||||
setWalletWithFundsFoundUseCase = setWalletWithFundsFoundUseCase,
|
||||
txHistoryItemsCountUseCase = txHistoryItemsCountUseCase,
|
||||
txHistoryItemsUseCase = txHistoryItemsUseCase,
|
||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
getVisaCurrencyUseCase = getVisaCurrencyUseCase,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ internal sealed class BalancesAndLimitsBlockState {
|
|||
|
||||
data class Content(
|
||||
val availableBalance: String,
|
||||
val currencySymbol: String,
|
||||
val limitDays: Int,
|
||||
val isEnabled: Boolean,
|
||||
val onClick: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -1,32 +1,98 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state2.transformers
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletAdditionalInfo
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.model.BalancesAndLimitsBlockState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.Days
|
||||
|
||||
internal class SetBalancesAndLimitsTransformer(
|
||||
userWallet: UserWallet,
|
||||
private val userWallet: UserWallet,
|
||||
private val maybeVisaCurrency: Either<Throwable, VisaCurrency>,
|
||||
private val clickIntents: WalletClickIntentsV2,
|
||||
) : WalletStateTransformer(userWallet.walletId) {
|
||||
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return prevState.transformWhenInState<WalletState.Visa.Content> { state ->
|
||||
val visaCurrency = maybeVisaCurrency.getOrElse {
|
||||
return state.copy(
|
||||
walletCardState = getErrorWalletCardState(state.walletCardState),
|
||||
balancesAndLimitBlockState = BalancesAndLimitsBlockState.Error,
|
||||
)
|
||||
}
|
||||
|
||||
state.copy(
|
||||
balancesAndLimitBlockState = state.balancesAndLimitBlockState.toLoadedState(),
|
||||
walletCardState = getContentWalletCardState(state.walletCardState, visaCurrency),
|
||||
balancesAndLimitBlockState = getContentBlockState(visaCurrency),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement in [REDACTED_JIRA]
|
||||
@Suppress("UnusedReceiverParameter")
|
||||
private fun BalancesAndLimitsBlockState.toLoadedState(): BalancesAndLimitsBlockState {
|
||||
return BalancesAndLimitsBlockState.Content(
|
||||
availableBalance = "400.00",
|
||||
currencySymbol = "USDT",
|
||||
limitDays = 7,
|
||||
private fun getContentBlockState(visaCurrency: VisaCurrency) = BalancesAndLimitsBlockState.Content(
|
||||
availableBalance = BigDecimalFormatter.formatCryptoAmount(
|
||||
visaCurrency.limits.remainingOtp,
|
||||
visaCurrency.symbol,
|
||||
visaCurrency.decimals,
|
||||
),
|
||||
limitDays = Days.daysBetween(DateTime.now(), visaCurrency.limits.expirationDate).days.inc(),
|
||||
isEnabled = true,
|
||||
onClick = clickIntents::onBalancesAndLimitsClick,
|
||||
)
|
||||
|
||||
private fun getErrorWalletCardState(prevState: WalletCardState): WalletCardState {
|
||||
return with(prevState) {
|
||||
WalletCardState.Error(
|
||||
id = id,
|
||||
title = title,
|
||||
imageResId = imageResId,
|
||||
onRenameClick = onRenameClick,
|
||||
onDeleteClick = onDeleteClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getContentWalletCardState(prevState: WalletCardState, visaCurrency: VisaCurrency): WalletCardState {
|
||||
return with(prevState) {
|
||||
WalletCardState.Content(
|
||||
id = id,
|
||||
title = title,
|
||||
additionalInfo = createAdditionalInfo(visaCurrency),
|
||||
imageResId = imageResId,
|
||||
onRenameClick = onRenameClick,
|
||||
onDeleteClick = onDeleteClick,
|
||||
balance = BigDecimalFormatter.formatCryptoAmount(
|
||||
visaCurrency.balances.available,
|
||||
visaCurrency.symbol,
|
||||
visaCurrency.decimals,
|
||||
),
|
||||
cardCount = userWallet.getCardsCount(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAdditionalInfo(visaCurrency: VisaCurrency): WalletAdditionalInfo {
|
||||
val fiatAmount = BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = visaCurrency.fiatRate?.let { visaCurrency.balances.available.multiply(it) },
|
||||
fiatCurrencyCode = visaCurrency.fiatCurrency.code,
|
||||
fiatCurrencySymbol = visaCurrency.fiatCurrency.symbol,
|
||||
)
|
||||
val infoContent = stringReference(
|
||||
value = buildString {
|
||||
append(fiatAmount)
|
||||
append(" • ")
|
||||
append(visaCurrency.networkName)
|
||||
},
|
||||
)
|
||||
|
||||
return WalletAdditionalInfo(hideable = true, infoContent)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCard
|
|||
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.SingleWalletCardStateConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.SingleWalletMarketPriceConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.VisaWalletCardStateConverter
|
||||
import timber.log.Timber
|
||||
|
||||
internal class SetPrimaryCurrencyTransformer(
|
||||
|
|
@ -25,15 +24,11 @@ internal class SetPrimaryCurrencyTransformer(
|
|||
marketPriceBlockState = prevState.marketPriceBlockState.toLoadedState(),
|
||||
)
|
||||
}
|
||||
is WalletState.Visa.Content -> {
|
||||
prevState.copy(
|
||||
walletCardState = prevState.walletCardState.toLoadedVisaState(),
|
||||
depositButtonState = prevState.depositButtonState.copy(isEnabled = true),
|
||||
)
|
||||
is WalletState.Visa -> {
|
||||
Timber.w("Impossible to load primary currency status for VISA wallet")
|
||||
prevState
|
||||
}
|
||||
is WalletState.Visa.Locked,
|
||||
is WalletState.SingleCurrency.Locked,
|
||||
-> {
|
||||
is WalletState.SingleCurrency.Locked -> {
|
||||
Timber.w("Impossible to load primary currency status for locked wallet")
|
||||
prevState
|
||||
}
|
||||
|
|
@ -48,10 +43,6 @@ internal class SetPrimaryCurrencyTransformer(
|
|||
return SingleWalletCardStateConverter(status.value, userWallet, appCurrency).convert(value = this)
|
||||
}
|
||||
|
||||
private fun WalletCardState.toLoadedVisaState(): WalletCardState {
|
||||
return VisaWalletCardStateConverter(status, userWallet, appCurrency).convert(value = this)
|
||||
}
|
||||
|
||||
private fun MarketPriceBlockState.toLoadedState(): MarketPriceBlockState {
|
||||
return SingleWalletMarketPriceConverter(status.value, appCurrency).convert(value = this)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter
|
||||
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.model.BalancesAndLimitsBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletEventSender
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class BalancesAndLimitsBottomSheetConverter(
|
||||
private val eventSender: WalletEventSender,
|
||||
) : Converter<VisaCurrency, BalancesAndLimitsBottomSheetConfig> {
|
||||
|
||||
override fun convert(value: VisaCurrency): BalancesAndLimitsBottomSheetConfig {
|
||||
return BalancesAndLimitsBottomSheetConfig(
|
||||
currency = value.symbol,
|
||||
balance = BalancesAndLimitsBottomSheetConfig.Balance(
|
||||
totalBalance = value.balances.total.let(::formatAmount),
|
||||
availableBalance = value.balances.available.let(::formatAmount),
|
||||
blockedBalance = value.balances.blocked.let(::formatAmount),
|
||||
debit = value.balances.debt.let(::formatAmount),
|
||||
pending = value.balances.pendingRefund.let(::formatAmount),
|
||||
amlVerified = value.balances.verified.let(::formatAmount),
|
||||
),
|
||||
limit = BalancesAndLimitsBottomSheetConfig.Limit(
|
||||
availableBy = DateTimeFormatters.formatDate(date = value.limits.expirationDate),
|
||||
inStore = value.limits.remainingOtp.let(::formatAmount),
|
||||
other = value.limits.remainingNoOtp.let(::formatAmount),
|
||||
singleTransaction = value.limits.singleTransaction.let(::formatAmount),
|
||||
),
|
||||
onBalanceInfoClick = this::showBalanceInfo,
|
||||
onLimitInfoClick = this::showLimitInfo,
|
||||
)
|
||||
}
|
||||
|
||||
private fun formatAmount(amount: BigDecimal): String = BigDecimalFormatter.formatCryptoAmount(
|
||||
amount,
|
||||
cryptoCurrency = "",
|
||||
decimals = 2,
|
||||
)
|
||||
|
||||
private fun showBalanceInfo() {
|
||||
eventSender.send(WalletEvent.ShowAlert(WalletAlertState.VisaBalancesInfo))
|
||||
}
|
||||
|
||||
private fun showLimitInfo() {
|
||||
eventSender.send(WalletEvent.ShowAlert(WalletAlertState.VisaLimitsInfo))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter
|
||||
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.getCardsCount
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletAdditionalInfo
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.components.WalletCardState
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class VisaWalletCardStateConverter(
|
||||
private val status: CryptoCurrencyStatus,
|
||||
private val selectedWallet: UserWallet,
|
||||
private val appCurrency: AppCurrency,
|
||||
) : Converter<WalletCardState, WalletCardState> {
|
||||
|
||||
override fun convert(value: WalletCardState): WalletCardState {
|
||||
return when (status.value) {
|
||||
is CryptoCurrencyStatus.Loading -> value.toLoadingState()
|
||||
is CryptoCurrencyStatus.Custom,
|
||||
is CryptoCurrencyStatus.MissedDerivation,
|
||||
is CryptoCurrencyStatus.Unreachable,
|
||||
-> value.toErrorState()
|
||||
is CryptoCurrencyStatus.NoQuote,
|
||||
is CryptoCurrencyStatus.Loaded,
|
||||
is CryptoCurrencyStatus.NoAccount,
|
||||
is CryptoCurrencyStatus.NoAmount,
|
||||
-> value.toContentState(status)
|
||||
}
|
||||
}
|
||||
|
||||
private fun WalletCardState.toLoadingState(): WalletCardState {
|
||||
return WalletCardState.Loading(
|
||||
id = id,
|
||||
title = title,
|
||||
imageResId = imageResId,
|
||||
onRenameClick = onRenameClick,
|
||||
onDeleteClick = onDeleteClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun WalletCardState.toErrorState(): WalletCardState {
|
||||
return WalletCardState.Error(
|
||||
id = id,
|
||||
title = title,
|
||||
imageResId = imageResId,
|
||||
onRenameClick = onRenameClick,
|
||||
onDeleteClick = onDeleteClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun WalletCardState.toContentState(status: CryptoCurrencyStatus): WalletCardState {
|
||||
return WalletCardState.Content(
|
||||
id = id,
|
||||
title = title,
|
||||
additionalInfo = createAdditionalInfo(status),
|
||||
imageResId = imageResId,
|
||||
onRenameClick = onRenameClick,
|
||||
onDeleteClick = onDeleteClick,
|
||||
balance = formatAmount(status),
|
||||
cardCount = selectedWallet.getCardsCount(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createAdditionalInfo(status: CryptoCurrencyStatus): WalletAdditionalInfo {
|
||||
val fiatAmount = BigDecimalFormatter.formatFiatAmount(
|
||||
status.value.fiatAmount,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
val infoContent = stringReference(
|
||||
value = buildString {
|
||||
append(fiatAmount)
|
||||
append(" • ")
|
||||
append(status.currency.network.name)
|
||||
},
|
||||
)
|
||||
|
||||
return WalletAdditionalInfo(hideable = true, infoContent)
|
||||
}
|
||||
|
||||
private fun formatAmount(status: CryptoCurrencyStatus): String {
|
||||
val amount = status.value.amount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN
|
||||
|
||||
return BigDecimalFormatter.formatCryptoAmount(amount, status.currency)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers
|
|||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import arrow.core.Either
|
||||
import com.tangem.core.ui.components.transactions.state.TxHistoryState
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.txhistory.models.TxHistoryItem
|
||||
|
|
@ -13,10 +15,8 @@ import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
|||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryCountErrorTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryCountTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryItemsErrorTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetTxHistoryItemsTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.model.WalletState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.*
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -37,6 +37,24 @@ internal class TxHistorySubscriber(
|
|||
) : WalletSubscriber() {
|
||||
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<PagingData<TxHistoryItem>> {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
if (userWallet.scanResponse.cardTypesResolver.isVisaWallet()) {
|
||||
return flow {
|
||||
stateHolder.update(
|
||||
object : WalletStateTransformer(userWallet.walletId) {
|
||||
override fun transform(prevState: WalletState): WalletState {
|
||||
return when (prevState) {
|
||||
is WalletState.Visa.Content -> prevState.copy(
|
||||
txHistoryState = TxHistoryState.Empty(onExploreClick = {}),
|
||||
)
|
||||
else -> prevState
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return flow {
|
||||
getPrimaryCurrencyStatusUpdatesUseCase.collectLatest(userWalletId = userWallet.walletId) { status ->
|
||||
val maybeTxHistoryItemCount = txHistoryItemsCountUseCase(
|
||||
|
|
|
|||
|
|
@ -1,23 +1,32 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||
|
||||
import com.tangem.domain.visa.GetVisaCurrencyUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.SetBalancesAndLimitsTransformer
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntentsV2
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class VisaWalletBalancesAndLimitsSubscriber(
|
||||
private val userWallet: UserWallet,
|
||||
private val stateHolder: WalletStateController,
|
||||
private val isRefresh: Boolean,
|
||||
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,
|
||||
private val clickIntents: WalletClickIntentsV2,
|
||||
) : WalletSubscriber() {
|
||||
|
||||
// TODO: Implement in [REDACTED_JIRA]
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<*> = suspend {
|
||||
delay(timeMillis = 500)
|
||||
stateHolder.update(SetBalancesAndLimitsTransformer(userWallet, clickIntents))
|
||||
}.asFlow()
|
||||
override fun create(coroutineScope: CoroutineScope): Flow<*> {
|
||||
return flow<Any> {
|
||||
stateHolder.update(
|
||||
SetBalancesAndLimitsTransformer(
|
||||
userWallet = userWallet,
|
||||
maybeVisaCurrency = getVisaCurrencyUseCase(userWallet.walletId, isRefresh),
|
||||
clickIntents = clickIntents,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -113,7 +113,6 @@ private fun Content(state: BalancesAndLimitsBlockState, modifier: Modifier = Mod
|
|||
is BalancesAndLimitsBlockState.Content -> with(blockState) {
|
||||
AvailableLimit(
|
||||
availableBalance = availableBalance,
|
||||
currencySymbol = currencySymbol,
|
||||
limitDays = limitDays,
|
||||
)
|
||||
}
|
||||
|
|
@ -136,19 +135,14 @@ private fun Content(state: BalancesAndLimitsBlockState, modifier: Modifier = Mod
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AvailableLimit(
|
||||
availableBalance: String,
|
||||
currencySymbol: String,
|
||||
limitDays: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun AvailableLimit(availableBalance: String, limitDays: Int, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
Text(
|
||||
text = "$availableBalance $currencySymbol",
|
||||
text = availableBalance,
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
|
|
@ -186,8 +180,7 @@ private class BalancesAndLimitsBlockParameterProvider : CollectionPreviewParamet
|
|||
BalancesAndLimitsBlockState.Loading,
|
||||
BalancesAndLimitsBlockState.Error,
|
||||
BalancesAndLimitsBlockState.Content(
|
||||
availableBalance = "400.00",
|
||||
currencySymbol = "USDT",
|
||||
availableBalance = "400.00 USDT",
|
||||
limitDays = 7,
|
||||
isEnabled = true,
|
||||
onClick = {},
|
||||
|
|
|
|||
|
|
@ -4,18 +4,16 @@ import arrow.core.getOrElse
|
|||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.tokenreceive.mapToAddressModels
|
||||
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.visa.GetVisaCurrencyUseCase
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletAlertState
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletEvent
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.WalletStateController
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.model.BalancesAndLimitsBottomSheetConfig
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.transformers.converter.BalancesAndLimitsBottomSheetConverter
|
||||
import com.tangem.feature.wallet.presentation.wallet.state2.utils.WalletEventSender
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
|
@ -31,10 +29,15 @@ internal interface VisaWalletIntents {
|
|||
internal class VisaWalletIntentsImplementor @Inject constructor(
|
||||
private val stateController: WalletStateController,
|
||||
private val eventSender: WalletEventSender,
|
||||
private val getPrimaryCurrencyUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
|
||||
private val getCurrencyStatusUseCase: GetCryptoCurrencyStatusSyncUseCase,
|
||||
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : BaseWalletClickIntents(), VisaWalletIntents {
|
||||
|
||||
private val balancesAndLimitsBottomSheetConverter by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
BalancesAndLimitsBottomSheetConverter(eventSender)
|
||||
}
|
||||
|
||||
override fun onDepositClick() {
|
||||
val userWalletId = stateController.getSelectedWalletId()
|
||||
|
||||
|
|
@ -47,15 +50,6 @@ internal class VisaWalletIntentsImplementor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun getPrimaryCurrencyStatus(userWalletId: UserWalletId): CryptoCurrencyStatus? {
|
||||
return getPrimaryCurrencyUseCase(userWalletId)
|
||||
.firstOrNull()
|
||||
?.getOrElse {
|
||||
Timber.e("Failed to get primary currency $it")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun createReceiveBottomSheetContent(currencyStatus: CryptoCurrencyStatus): TangemBottomSheetConfigContent? {
|
||||
val currency = currencyStatus.currency
|
||||
val addresses = currencyStatus.value.networkAddress?.availableAddresses
|
||||
|
|
@ -76,35 +70,27 @@ internal class VisaWalletIntentsImplementor @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onBalancesAndLimitsClick() {
|
||||
stateController.showBottomSheet(getBalancesAndLimitsConfig())
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
val userWalletId = stateController.getSelectedWalletId()
|
||||
val balancesAndLimits = getVisaCurrencyUseCase(userWalletId)
|
||||
.getOrElse {
|
||||
Timber.e("Unable to get balances and limits: $it")
|
||||
return@launch
|
||||
}
|
||||
|
||||
// TODO: Implement
|
||||
private fun getBalancesAndLimitsConfig() = BalancesAndLimitsBottomSheetConfig(
|
||||
currency = "USDT",
|
||||
balance = BalancesAndLimitsBottomSheetConfig.Balance(
|
||||
totalBalance = "492.45",
|
||||
availableBalance = "392.45",
|
||||
blockedBalance = "36.00",
|
||||
debit = "00.00",
|
||||
pending = "20.99",
|
||||
amlVerified = "356.45",
|
||||
),
|
||||
limit = BalancesAndLimitsBottomSheetConfig.Limit(
|
||||
availableBy = "Nov, 11",
|
||||
inStore = "563.00",
|
||||
other = "100.00",
|
||||
singleTransaction = "100.00",
|
||||
),
|
||||
onBalanceInfoClick = this::showBalanceInfo,
|
||||
onLimitInfoClick = this::showLimitInfo,
|
||||
val bottomSheetContent = balancesAndLimitsBottomSheetConverter.convert(
|
||||
value = balancesAndLimits,
|
||||
)
|
||||
|
||||
private fun showBalanceInfo() {
|
||||
eventSender.send(WalletEvent.ShowAlert(WalletAlertState.VisaBalancesInfo))
|
||||
stateController.showBottomSheet(bottomSheetContent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLimitInfo() {
|
||||
eventSender.send(WalletEvent.ShowAlert(WalletAlertState.VisaLimitsInfo))
|
||||
private suspend fun getPrimaryCurrencyStatus(userWalletId: UserWalletId): CryptoCurrencyStatus? {
|
||||
return getCurrencyStatusUseCase(userWalletId)
|
||||
.getOrElse {
|
||||
Timber.e("Failed to get primary currency $it")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -135,6 +135,7 @@ include(":domain:balance-hiding")
|
|||
include(":domain:balance-hiding:models")
|
||||
include(":domain:transaction")
|
||||
include(":domain:analytics")
|
||||
include(":domain:visa")
|
||||
// endregion Domain modules
|
||||
|
||||
// region Data modules
|
||||
|
|
@ -150,4 +151,5 @@ include(":data:txhistory")
|
|||
include(":data:wallets")
|
||||
include(":data:analytics")
|
||||
include(":data:transaction")
|
||||
include(":data:visa")
|
||||
// endregion Data modules
|
||||
Loading…
Add table
Add a link
Reference in a new issue