Updated on 2026-08-14
This commit is contained in:
commit
e4754fed3b
483 changed files with 9315 additions and 4084 deletions
|
|
@ -7,6 +7,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
|
|
@ -77,6 +78,7 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
params = PushNotificationsParams(
|
||||
isBottomSheet = true,
|
||||
modelCallbacks = model.askForPushNotificationsModelCallbacks,
|
||||
source = AppRoute.PushNotification.Source.Main,
|
||||
),
|
||||
)
|
||||
is WalletDialogConfig.TokenReceive -> {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
|||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.models.wallet.isLocked
|
||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.domain.nft.ObserveAndClearNFTCacheIfNeedUseCase
|
||||
import com.tangem.domain.notifications.GetIsHuaweiDeviceWithoutGoogleServicesUseCase
|
||||
|
|
@ -84,7 +85,7 @@ internal class WalletModel @Inject constructor(
|
|||
private val getWalletsListForEnablingUseCase: GetWalletsForAutomaticallyPushEnablingUseCase,
|
||||
private val setNotificationsEnabledUseCase: SetNotificationsEnabledUseCase,
|
||||
private val notificationsFeatureToggles: NotificationsFeatureToggles,
|
||||
private val getIsBiometryIsEnabledUseCase: GetIsBiometricsEnabledUseCase,
|
||||
private val shouldSaveUserWalletsSyncUseCase: ShouldSaveUserWalletsSyncUseCase,
|
||||
private val getIsHuaweiDeviceWithoutGoogleServicesUseCase: GetIsHuaweiDeviceWithoutGoogleServicesUseCase,
|
||||
val screenLifecycleProvider: ScreenLifecycleProvider,
|
||||
val innerWalletRouter: InnerWalletRouter,
|
||||
|
|
@ -212,9 +213,15 @@ internal class WalletModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
val shouldAskPermission = shouldAskPermissionUseCase(PUSH_PERMISSION)
|
||||
val afterUpdate = notificationsRepository.shouldShowSubscribeOnNotificationsAfterUpdate()
|
||||
val isBiometricsEnabled = getIsBiometryIsEnabledUseCase()
|
||||
val isBiometricsEnabled = shouldSaveUserWalletsSyncUseCase()
|
||||
val isHuaweiDevice = getIsHuaweiDeviceWithoutGoogleServicesUseCase()
|
||||
val shouldShowBottomSheet = shouldAskPermission || afterUpdate
|
||||
Timber.d(
|
||||
"push BS afterUpdate: $afterUpdate," +
|
||||
"shouldAskPermission $shouldAskPermission," +
|
||||
"isBiometricsEnabled $isBiometricsEnabled," +
|
||||
"isHuaweiDevice $isHuaweiDevice",
|
||||
)
|
||||
if (!isBiometricsEnabled) return@launch
|
||||
if (isHuaweiDevice) return@launch
|
||||
if (!shouldShowBottomSheet) return@launch
|
||||
|
|
@ -383,9 +390,11 @@ internal class WalletModel @Inject constructor(
|
|||
val otherWallets = action.wallets.minus(action.selectedWallet)
|
||||
|
||||
if (tokensFeatureToggles.isWalletBalanceFetcherEnabled) {
|
||||
otherWallets.onEach { userWallet ->
|
||||
modelScope.launch { walletContentFetcher(userWalletId = userWallet.walletId) }
|
||||
}
|
||||
otherWallets
|
||||
.filterNot(UserWallet::isLocked)
|
||||
.onEach { userWallet ->
|
||||
modelScope.launch { walletContentFetcher(userWalletId = userWallet.walletId) }
|
||||
}
|
||||
}
|
||||
|
||||
if (action.wallets.size > 1 && isWalletsScrollPreviewEnabled()) {
|
||||
|
|
@ -500,6 +509,10 @@ internal class WalletModel @Inject constructor(
|
|||
clickIntents = clickIntents,
|
||||
coroutineScope = modelScope,
|
||||
)
|
||||
|
||||
action.unlockedWallets.onEach { userWallet ->
|
||||
modelScope.launch { fetchWalletContent(userWallet = userWallet) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun demonstrateWalletsScrollPreview(direction: Direction) {
|
||||
|
|
@ -541,6 +554,8 @@ internal class WalletModel @Inject constructor(
|
|||
|
||||
private suspend fun fetchWalletContent(userWallet: UserWallet) {
|
||||
if (tokensFeatureToggles.isWalletBalanceFetcherEnabled) {
|
||||
if (userWallet.isLocked) return
|
||||
|
||||
/*
|
||||
* Updating the balance of the current wallet is an essential part of InitializationWallets,
|
||||
* so the coroutine is launched in the current context
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.appcurrency.extenstions.unwrap
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.exchange.RampStateManager
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.isLocked
|
||||
import com.tangem.domain.onramp.FetchHotCryptoUseCase
|
||||
import com.tangem.domain.settings.NeverToShowWalletsScrollPreview
|
||||
import com.tangem.domain.tokens.FetchCardTokenListUseCase
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.FetchTokenListUseCase
|
||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.domain.wallets.usecase.SelectWalletUseCase
|
||||
import com.tangem.feature.wallet.presentation.router.InnerWalletRouter
|
||||
|
|
@ -87,7 +88,7 @@ internal class WalletClickIntents @Inject constructor(
|
|||
stateHolder.update { it.copy(selectedWalletIndex = index) }
|
||||
|
||||
maybeUserWallet.onRight {
|
||||
if (tokensFeatureToggles.isWalletBalanceFetcherEnabled) {
|
||||
if (tokensFeatureToggles.isWalletBalanceFetcherEnabled && !it.isLocked) {
|
||||
launch { walletContentFetcher(userWalletId = it.walletId) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,29 +2,44 @@ package com.tangem.feature.wallet.presentation.wallet.domain
|
|||
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.models.wallet.copy
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository
|
||||
import timber.log.Timber
|
||||
|
||||
class WalletNameMigrationUseCase(
|
||||
private val userWalletsListManager: UserWalletsListManager,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val useNewListRepository: Boolean,
|
||||
private val walletNamesMigrationRepository: WalletNamesMigrationRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke() {
|
||||
val wallets = userWalletsListManager.userWalletsSync
|
||||
|
||||
if (walletNamesMigrationRepository.isMigrationDone()) {
|
||||
return
|
||||
}
|
||||
|
||||
val existingNames: MutableSet<String> = mutableSetOf()
|
||||
wallets.indices.forEach { i ->
|
||||
val defaultName = wallets[i].name
|
||||
val suggestedWalletName = suggestedWalletName(defaultName, existingNames)
|
||||
if (defaultName != suggestedWalletName) {
|
||||
userWalletsListManager.update(wallets[i].walletId) { it.copy(name = suggestedWalletName) }
|
||||
if (useNewListRepository) {
|
||||
val wallets = userWalletsListRepository.userWalletsSync()
|
||||
val existingNames: MutableSet<String> = mutableSetOf()
|
||||
wallets.forEach {
|
||||
val defaultName = it.name
|
||||
val suggestedWalletName = suggestedWalletName(defaultName, existingNames)
|
||||
if (defaultName != suggestedWalletName) {
|
||||
userWalletsListRepository.saveWithoutLock(it.copy(name = suggestedWalletName), canOverride = true)
|
||||
}
|
||||
Timber.tag("Migrated names").e(it.walletId.toString() + " " + suggestedWalletName)
|
||||
}
|
||||
} else {
|
||||
val wallets = userWalletsListManager.userWalletsSync
|
||||
val existingNames: MutableSet<String> = mutableSetOf()
|
||||
wallets.indices.forEach { i ->
|
||||
val defaultName = wallets[i].name
|
||||
val suggestedWalletName = suggestedWalletName(defaultName, existingNames)
|
||||
if (defaultName != suggestedWalletName) {
|
||||
userWalletsListManager.update(wallets[i].walletId) { it.copy(name = suggestedWalletName) }
|
||||
}
|
||||
Timber.tag("Migrated names").e(i.toString() + " " + suggestedWalletName)
|
||||
}
|
||||
Timber.tag("Migrated names").e(i.toString() + " " + suggestedWalletName)
|
||||
}
|
||||
|
||||
walletNamesMigrationRepository.setMigrationDone()
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ import com.tangem.core.ui.components.marketprice.MarketPriceBlockState
|
|||
import com.tangem.core.ui.components.marketprice.PriceChangeState
|
||||
import com.tangem.core.ui.components.marketprice.PriceChangeType
|
||||
import com.tangem.core.ui.components.marketprice.utils.PriceChangeConverter
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.format.bigdecimal.percent
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.format.bigdecimal.uncapped
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class SingleWalletMarketPriceConverter(
|
||||
|
|
@ -47,17 +49,18 @@ internal class SingleWalletMarketPriceConverter(
|
|||
}
|
||||
|
||||
private fun formatPrice(status: CryptoCurrencyStatus.Value, appCurrency: AppCurrency): String {
|
||||
val fiatRate = status.fiatRate ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN
|
||||
val fiatRate = status.fiatRate ?: return DASH_SIGN
|
||||
|
||||
return BigDecimalFormatter.formatFiatAmountUncapped(
|
||||
fiatAmount = fiatRate,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
return fiatRate.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
).uncapped()
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatPriceChange(status: CryptoCurrencyStatus.Value): String {
|
||||
val priceChange = status.priceChange ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN
|
||||
val priceChange = status.priceChange ?: return DASH_SIGN
|
||||
|
||||
return priceChange.format { percent() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers.convert
|
|||
|
||||
import com.tangem.core.ui.extensions.capitalize
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.domain.visa.model.VisaTxDetails
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.VisaTxDetailsBottomSheetConfig
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.VisaWalletIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.VisaTxDetailsBottomSheetConfig
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import org.joda.time.DateTimeZone
|
||||
|
|
@ -71,11 +71,12 @@ internal class VisaTxDetailsBottomSheetConverter(
|
|||
}
|
||||
|
||||
private fun formatFiatAmount(amount: BigDecimal, fiatCurrency: Currency): String {
|
||||
return BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = amount,
|
||||
fiatCurrencyCode = fiatCurrency.currencyCode,
|
||||
fiatCurrencySymbol = fiatCurrency.symbol,
|
||||
)
|
||||
return amount.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = fiatCurrency.currencyCode,
|
||||
fiatCurrencySymbol = fiatCurrency.symbol,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import com.tangem.core.ui.components.transactions.state.TransactionState
|
|||
import com.tangem.core.ui.extensions.capitalize
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||
import com.tangem.domain.visa.model.VisaCurrency
|
||||
import com.tangem.domain.visa.model.VisaTxHistoryItem
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.VisaWalletIntents
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.utils.StringsSigns
|
||||
import com.tangem.utils.converter.Converter
|
||||
import org.joda.time.DateTimeZone
|
||||
|
|
@ -29,11 +29,12 @@ internal class VisaTxHistoryItemStateConverter(
|
|||
txHash = value.id,
|
||||
amount = value.amount.format { crypto(visaCurrency.symbol, visaCurrency.decimals) },
|
||||
// Show tx fiat amount instead of tx time
|
||||
time = BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = value.fiatAmount,
|
||||
fiatCurrencyCode = value.fiatCurrency.currencyCode,
|
||||
fiatCurrencySymbol = value.fiatCurrency.symbol,
|
||||
),
|
||||
time = value.fiatAmount.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = value.fiatCurrency.currencyCode,
|
||||
fiatCurrencySymbol = value.fiatCurrency.symbol,
|
||||
)
|
||||
},
|
||||
status = TransactionState.Content.Status.Confirmed,
|
||||
direction = TransactionState.Content.Direction.INCOMING,
|
||||
iconRes = R.drawable.ic_arrow_up_24,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor(
|
|||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
@Assisted private val onWalletClick: (UserWalletId) -> Unit,
|
||||
@Assisted private val messageSender: UiMessageSender,
|
||||
@Assisted private val onlyMultiCurrency: Boolean,
|
||||
@Assisted("onlyMultiCurrency") private val onlyMultiCurrency: Boolean,
|
||||
@Assisted("authMode") private val authMode: Boolean,
|
||||
private val getCardImageUseCase: GetCardImageUseCase,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
) : UserWalletsFetcher {
|
||||
|
|
@ -54,7 +55,10 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor(
|
|||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override val userWallets: Flow<ImmutableList<UserWalletItemUM>> = walletsFlow.transformLatest { wallets ->
|
||||
val uiModels = UserWalletItemUMConverter(onClick = onWalletClick).convertList(wallets)
|
||||
val uiModels = UserWalletItemUMConverter(
|
||||
onClick = onWalletClick,
|
||||
authMode = authMode,
|
||||
).convertList(wallets)
|
||||
.toImmutableList()
|
||||
|
||||
emit(uiModels)
|
||||
|
|
@ -132,6 +136,7 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor(
|
|||
balance = balance,
|
||||
isBalanceHidden = balanceHidingSettings.isBalanceHidden,
|
||||
artwork = artworks[userWallet.walletId],
|
||||
authMode = authMode,
|
||||
)
|
||||
.convert(userWallet)
|
||||
}
|
||||
|
|
@ -149,7 +154,8 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor(
|
|||
interface Factory : UserWalletsFetcher.Factory {
|
||||
override fun create(
|
||||
messageSender: UiMessageSender,
|
||||
onlyMultiCurrency: Boolean,
|
||||
@Assisted("onlyMultiCurrency") onlyMultiCurrency: Boolean,
|
||||
@Assisted("authMode") authMode: Boolean,
|
||||
onWalletClick: (UserWalletId) -> Unit,
|
||||
): DefaultUserWalletsFetcher
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue