Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-16 13:35:39 +03:00
parent 8541957ee3
commit 189ffd9927
73 changed files with 547 additions and 409 deletions

View file

@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@ModelScoped
@ -49,6 +50,8 @@ internal class CreateMobileWalletModel @Inject constructor(
)
router.push(AppRoute.Wallet)
}.onFailure {
Timber.e(it)
uiState.update {
it.copy(createButtonLoading = false)
}

View file

@ -7,30 +7,18 @@ import com.tangem.features.hotwallet.createmobilewallet.DefaultCreateMobileWalle
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.scopes.ActivityScoped
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@Module
@InstallIn(SingletonComponent::class)
internal object CreateMobileWalletModule
@Module
@InstallIn(ActivityComponent::class)
internal interface CreateMobileWalletModuleActivityBinds {
internal interface CreateMobileWalletModuleBinds {
@Binds
@ActivityScoped
fun bindCreateMobileWalletComponentFactory(
impl: DefaultCreateMobileWalletComponent.Factory,
): CreateMobileWalletComponent.Factory
}
@Module
@InstallIn(SingletonComponent::class)
internal interface CreateMobileWalletModuleBinds {
@Binds
@IntoMap

View file

@ -11,7 +11,6 @@ import com.tangem.datasource.api.tangemTech.models.StartReferralBody
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.referral.converters.ReferralConverter
import com.tangem.feature.referral.domain.ReferralRepository
import com.tangem.feature.referral.domain.models.ReferralData
@ -97,13 +96,13 @@ internal class ReferralRepositoryImpl @Inject constructor(
sdkToken = sdkToken,
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
)
} else {
cryptoCurrencyFactory.createCoin(
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
)
}
}

View file

@ -30,7 +30,6 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.swap.converters.*
import com.tangem.feature.swap.domain.api.SwapRepository
import com.tangem.feature.swap.domain.models.ExpressDataError
@ -404,12 +403,7 @@ internal class DefaultSwapRepository(
cryptoCurrencyFactory.createCoin(
blockchain = blockchain,
extraDerivationPath = null,
scanResponse = requireNotNull(
userWalletsListManager
.selectedUserWalletSync
?.requireColdWallet() // TODO [REDACTED_TASK_KEY]
?.scanResponse,
),
userWallet = requireNotNull(userWalletsListManager.selectedUserWalletSync),
),
)
}

View file

@ -10,7 +10,6 @@ import com.tangem.datasource.local.preferences.utils.getObjectMap
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.swap.converters.SavedSwapTransactionListConverter
import com.tangem.feature.swap.domain.SwapTransactionRepository
import com.tangem.feature.swap.domain.models.domain.*
@ -104,7 +103,7 @@ internal class DefaultSwapTransactionRepository(
currencyTxs?.mapNotNull {
converter.convertBack(
value = it,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY]
userWallet = userWallet,
txStatuses = txStatuses,
)
}

View file

@ -3,7 +3,7 @@ package com.tangem.feature.swap.converters
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
import com.tangem.data.common.currency.UserTokensResponseFactory
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel
@ -32,7 +32,7 @@ internal class SavedSwapTransactionListConverter(
fun convertBack(
value: SavedSwapTransactionListModelInner,
scanResponse: ScanResponse,
userWallet: UserWallet,
txStatuses: Map<String, ExchangeStatusModel>,
): SavedSwapTransactionListModel? {
val fromToken = value.fromTokensResponse
@ -42,11 +42,11 @@ internal class SavedSwapTransactionListConverter(
} else {
val fromCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = fromToken,
scanResponse = scanResponse,
userWallet = userWallet,
) ?: return null
val toCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = toToken,
scanResponse = scanResponse,
userWallet = userWallet,
) ?: return null
return SavedSwapTransactionListModel(
@ -55,7 +55,7 @@ internal class SavedSwapTransactionListConverter(
val refundCurrency = status?.refundTokensResponse?.let { id ->
responseCryptoCurrenciesFactory.createCurrency(
responseToken = id,
scanResponse = scanResponse,
userWallet = userWallet,
)
}
val statusWithRefundCurrency = status?.copy(refundCurrency = refundCurrency)

View file

@ -39,10 +39,22 @@ internal object WalletAdditionalInfoFactory {
wallet.resolveSingleCurrencyInfo(currencyAmount)
}
}
is UserWallet.Hot -> TODO("[REDACTED_TASK_KEY]")
is UserWallet.Hot -> wallet.resolveAdditionalInfo()
}
}
private fun UserWallet.Hot.resolveAdditionalInfo(): WalletAdditionalInfo {
return WalletAdditionalInfo(
hideable = false,
content = TextReference.Res(R.string.hw_mobile_wallet) +
when {
isLocked -> DIVIDER + TextReference.Res(R.string.common_locked)
backedUp.not() -> DIVIDER + TextReference.Res(R.string.hw_backup_no_backup)
else -> TextReference.Str("")
},
)
}
private fun UserWallet.Cold.resolveMultiCurrencyInfo(): WalletAdditionalInfo {
return if (isLocked) {
WalletAdditionalInfo(

View file

@ -24,7 +24,11 @@ internal class WalletImageResolver @Inject constructor(
/** Get a specified wallet [userWallet] image */
@Suppress("CyclomaticComplexMethod")
@DrawableRes
fun resolve(userWallet: UserWallet.Cold): Int? {
fun resolve(userWallet: UserWallet): Int? {
if (userWallet !is UserWallet.Cold) {
return null
}
val cardTypesResolver = userWallet.scanResponse.cardTypesResolver
val cobrandImage = Wallet2CobrandImage.entries.firstOrNull {

View file

@ -31,7 +31,7 @@ internal class WalletContentLoaderFactory @Inject constructor(
userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isVisaWallet() -> {
visaWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh)
}
!userWallet.isMultiCurrency -> {
userWallet is UserWallet.Cold && !userWallet.isMultiCurrency -> {
singleWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh)
}
else -> null

View file

@ -19,7 +19,7 @@ import com.tangem.feature.wallet.presentation.wallet.subscribers.*
@Suppress("LongParameterList")
internal class SingleWalletContentLoader(
private val userWallet: UserWallet,
private val userWallet: UserWallet.Cold,
private val clickIntents: WalletClickIntents,
private val isRefresh: Boolean,
private val stateHolder: WalletStateController,

View file

@ -36,7 +36,7 @@ internal class SingleWalletContentLoaderFactory @Inject constructor(
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader {
fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader {
return SingleWalletContentLoader(
userWallet = userWallet,
clickIntents = clickIntents,

View file

@ -17,7 +17,7 @@ import com.tangem.feature.wallet.presentation.wallet.subscribers.*
@Suppress("LongParameterList")
internal class SingleWalletWithTokenContentLoader(
private val userWallet: UserWallet,
private val userWallet: UserWallet.Cold,
private val clickIntents: WalletClickIntents,
private val stateHolder: WalletStateController,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,

View file

@ -33,7 +33,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
private val getStoryContentUseCase: GetStoryContentUseCase,
) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader {
fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader {
return SingleWalletWithTokenContentLoader(
userWallet = userWallet,
clickIntents = clickIntents,

View file

@ -9,7 +9,7 @@ import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscribe
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
internal class VisaWalletContentLoader(
private val userWallet: UserWallet,
private val userWallet: UserWallet.Cold,
private val clickIntents: WalletClickIntents,
private val isRefresh: Boolean,
private val stateController: WalletStateController,

View file

@ -15,7 +15,7 @@ internal class VisaWalletContentLoaderFactory @Inject constructor(
private val getVisaTxHistoryUseCase: GetVisaTxHistoryUseCase,
) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader {
fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader {
return VisaWalletContentLoader(
userWallet = userWallet,
clickIntents = clickIntents,

View file

@ -3,7 +3,6 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.isLocked
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.model.*
@ -55,8 +54,6 @@ internal class InitializeWalletsTransformer(
}
private fun createLockedState(userWallet: UserWallet): WalletState {
userWallet.requireColdWallet()
return userWallet.createStateByWalletType(
multiCurrencyCreator = {
WalletState.MultiCurrency.Locked(
@ -87,7 +84,7 @@ internal class InitializeWalletsTransformer(
)
}
private fun UserWallet.Cold.toLockedWalletCardState(): WalletCardState {
private fun UserWallet.toLockedWalletCardState(): WalletCardState {
return WalletCardState.LockedContent(
id = walletId,
title = name,

View file

@ -6,7 +6,6 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.util.getCardsCount
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
@ -57,8 +56,6 @@ internal class SetTokenListErrorTransformer(
}
private fun WalletCardState.toLoadedState(): WalletCardState {
selectedWallet.requireColdWallet() // TODO [REDACTED_TASK_KEY]
return WalletCardState.Content(
id = id,
title = title,
@ -68,7 +65,10 @@ internal class SetTokenListErrorTransformer(
balance = BigDecimal.ZERO.format {
fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol)
},
cardCount = selectedWallet.getCardsCount(),
cardCount = when (selectedWallet) {
is UserWallet.Cold -> selectedWallet.getCardsCount()
is UserWallet.Hot -> null
},
isZeroBalance = true,
isBalanceFlickering = false,
)

View file

@ -13,7 +13,6 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.visa.exception.RefreshTokenExpiredException
import com.tangem.domain.visa.model.VisaCurrency
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.state.model.BalancesAndLimitsBlockState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
@ -27,7 +26,7 @@ import org.joda.time.DateTime
import org.joda.time.Days
internal class SetVisaInfoTransformer(
private val userWallet: UserWallet,
private val userWallet: UserWallet.Cold,
private val maybeVisaCurrency: Either<Throwable, VisaCurrency>,
private val clickIntents: WalletClickIntents,
) : TypedWalletStateTransformer<WalletState.Visa.Content>(
@ -76,8 +75,6 @@ internal class SetVisaInfoTransformer(
}
private fun getContentWalletCardState(prevState: WalletCardState, visaCurrency: VisaCurrency): WalletCardState {
userWallet.requireColdWallet() // TODO [REDACTED_TASK_KEY]
return with(prevState) {
WalletCardState.Content(
id = id,

View file

@ -7,7 +7,6 @@ import com.tangem.domain.common.util.getCardsCount
import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.utils.converter.Converter
@ -48,8 +47,6 @@ internal class MultiWalletCardStateConverter(
}
private fun WalletCardState.toWalletCardState(fiatBalance: TotalFiatBalance.Loaded): WalletCardState {
selectedWallet.requireColdWallet()
return WalletCardState.Content(
id = id,
title = title,
@ -60,7 +57,10 @@ internal class MultiWalletCardStateConverter(
fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol)
},
isZeroBalance = fiatBalance.amount.isZero(),
cardCount = selectedWallet.getCardsCount(),
cardCount = when (selectedWallet) {
is UserWallet.Cold -> selectedWallet.getCardsCount()
is UserWallet.Hot -> null
},
isBalanceFlickering = fiatBalance.source == StatusSource.CACHE,
)
}

View file

@ -7,7 +7,6 @@ import com.tangem.domain.common.util.getCardsCount
import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.utils.StringsSigns.DASH_SIGN
@ -64,7 +63,10 @@ internal class SingleWalletCardStateConverter(
imageResId = imageResId,
dropDownItems = dropDownItems,
balance = formatFiatAmount(status = status, appCurrency = appCurrency),
cardCount = selectedWallet.requireColdWallet().getCardsCount(), // TODO [REDACTED_TASK_KEY]
cardCount = when (selectedWallet) {
is UserWallet.Cold -> selectedWallet.getCardsCount()
is UserWallet.Hot -> null
},
isZeroBalance = status.fiatAmount?.isZero(),
isBalanceFlickering = (status as? CryptoCurrencyStatus.Loaded)?.sources?.total == StatusSource.CACHE,
)

View file

@ -4,14 +4,17 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
internal inline fun UserWallet.Cold.createStateByWalletType(
internal inline fun UserWallet.createStateByWalletType(
multiCurrencyCreator: () -> WalletState.MultiCurrency,
singleCurrencyCreator: () -> WalletState.SingleCurrency,
visaWalletCreator: () -> WalletState.Visa,
): WalletState = when {
isVisaWallet() -> visaWalletCreator()
isWalletWithTokens() -> multiCurrencyCreator()
else -> singleCurrencyCreator()
): WalletState = when (this) {
is UserWallet.Cold -> when {
isVisaWallet() -> visaWalletCreator()
isWalletWithTokens() -> multiCurrencyCreator()
else -> singleCurrencyCreator()
}
is UserWallet.Hot -> multiCurrencyCreator()
}
private fun UserWallet.Cold.isWalletWithTokens(): Boolean {

View file

@ -16,7 +16,7 @@ import kotlinx.coroutines.CoroutineScope
@Suppress("LongParameterList")
internal class SingleWalletWithTokenListSubscriber(
private val userWallet: UserWallet,
private val userWallet: UserWallet.Cold,
private val tokenListStore: MultiWalletTokenListStore,
stateHolder: WalletStateController,
clickIntents: WalletClickIntents,

View file

@ -13,7 +13,6 @@ import com.tangem.domain.txhistory.models.TxHistoryStateError
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
@ -32,7 +31,7 @@ typealias MaybeTxHistoryItems = Either<TxHistoryListError, Flow<PagingData<TxInf
@Suppress("LongParameterList")
internal class TxHistorySubscriber(
private val userWallet: UserWallet,
private val userWallet: UserWallet.Cold,
private val isRefresh: Boolean,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntents,
@ -97,7 +96,7 @@ internal class TxHistorySubscriber(
)
},
ifRight = { itemsFlow ->
val blockchain = userWallet.requireColdWallet().scanResponse.cardTypesResolver.getBlockchain()
val blockchain = userWallet.scanResponse.cardTypesResolver.getBlockchain()
val itemConverter = TxHistoryItemStateConverter(
symbol = blockchain.currency,
decimals = blockchain.decimals(),

View file

@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.map
import timber.log.Timber
internal class VisaWalletSubscriber(
private val userWallet: UserWallet,
private val userWallet: UserWallet.Cold,
private val stateController: WalletStateController,
private val isRefresh: Boolean,
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,

View file

@ -22,7 +22,6 @@ import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.isMultiCurrency
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.domain.wallets.usecase.GetCardImageUseCase
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.feature.wallet.impl.R
@ -88,8 +87,7 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor(
private fun loadArtworks(wallets: List<UserWallet>): Flow<HashMap<UserWalletId, ArtworkModel>> {
return flow {
emit(hashMapOf()) // emits right away so the transform doesn't wait for the images' loading to finish
wallets.forEach { wallet ->
wallet.requireColdWallet()
wallets.filterIsInstance<UserWallet.Cold>().forEach { wallet ->
val artwork = getCardImageUseCase(
cardId = wallet.cardId,
manufacturerName = wallet.scanResponse.card.manufacturer.name,