Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-27 16:59:33 +07:00
commit e95a61fa71
4 changed files with 78 additions and 36 deletions

View file

@ -0,0 +1,31 @@
package com.tangem.common
import com.tangem.utils.SupportedLanguages.CHINESE
import com.tangem.utils.SupportedLanguages.ENGLISH
import com.tangem.utils.SupportedLanguages.FRANCH
import com.tangem.utils.SupportedLanguages.GERMAN
import com.tangem.utils.SupportedLanguages.JAPANESE
import java.util.Locale
object TangemSiteShareUrlBuilder {
private const val BASE_URL = "https://tangem.com"
private const val CRYPTOCURRENCIES_PATH = "cryptocurrencies"
@Deprecated("Should use CHINESE from SupportedLanguages, but the site expects zh-Hans in the URL path")
private const val CHINESE_SITE_LOCALE = "zh-Hans"
@Deprecated("Should rely on SupportedLanguages instead of maintaining a separate list")
private val siteLocales = mapOf(
ENGLISH to ENGLISH,
FRANCH to FRANCH,
GERMAN to GERMAN,
JAPANESE to JAPANESE,
CHINESE to CHINESE_SITE_LOCALE,
)
fun shareUrl(tokenId: String): String {
val locale = siteLocales[Locale.getDefault().language] ?: ENGLISH
return "$BASE_URL/$locale/$CRYPTOCURRENCIES_PATH/$tokenId"
}
}

View file

@ -4,6 +4,8 @@ import arrow.core.none
import arrow.core.some
import arrow.core.toOption
import com.squareup.moshi.Moshi
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.toNetworkId
import com.tangem.data.common.api.safeApiCall
import com.tangem.data.swap.converter.SwapDataConverter
import com.tangem.data.swap.converter.SwapStatusConverter
@ -132,42 +134,43 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
swapTxType = swapTxType,
).associateBy(ExpressProvider::providerId)
allPairs.map { pair ->
async {
val statusFromDeferred = async {
cryptoCurrencyList
.firstOrNull { currency ->
currency.getContractAddress() == pair.from.contractAddress &&
currency.network.backendId == pair.from.network
}
}
val statusToDeferred = async {
cryptoCurrencyList
.firstOrNull { currency ->
currency.getContractAddress() == pair.to.contractAddress &&
currency.network.backendId == pair.to.network
}
}
allPairs.filter { it.to.network !in MEMO_RESTRICTED_NETWORKS }
.map { pair ->
async {
val statusFromDeferred = async {
cryptoCurrencyList
.firstOrNull { currency ->
currency.getContractAddress() == pair.from.contractAddress &&
currency.network.backendId == pair.from.network
}
}
val statusToDeferred = async {
cryptoCurrencyList
.firstOrNull { currency ->
currency.getContractAddress() == pair.to.contractAddress &&
currency.network.backendId == pair.to.network
}
}
val currencyStatusFrom = createSendWithSwapCryptoCurrencyStatus(statusFromDeferred.await())
val currencyStatusTo = createSendWithSwapCryptoCurrencyStatus(statusToDeferred.await())
val currencyStatusFrom = createSendWithSwapCryptoCurrencyStatus(statusFromDeferred.await())
val currencyStatusTo = createSendWithSwapCryptoCurrencyStatus(statusToDeferred.await())
val mappedProvider = pair.providers
.filterNot { it.hasOnlyFixedRateType() }
.mapNotNull { mappedProviders[it.providerId] }
.filterYieldSupplyProvider(currencyStatusFrom)
val mappedProvider = pair.providers
.filterNot { it.hasOnlyFixedRateType() }
.mapNotNull { mappedProviders[it.providerId] }
.filterYieldSupplyProvider(currencyStatusFrom)
if (currencyStatusFrom != null && currencyStatusTo != null && mappedProvider.isNotEmpty()) {
SwapPairModel(
from = currencyStatusFrom,
to = currencyStatusTo,
providers = mappedProvider,
)
} else {
null
if (currencyStatusFrom != null && currencyStatusTo != null && mappedProvider.isNotEmpty()) {
SwapPairModel(
from = currencyStatusFrom,
to = currencyStatusTo,
providers = mappedProvider,
)
} else {
null
}
}
}
}.awaitAll().filterNotNull()
}.awaitAll().filterNotNull()
}
override suspend fun getSwapQuote(
@ -440,6 +443,14 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
}
}
private val MEMO_RESTRICTED_NETWORKS = setOf(
Blockchain.XRP.toNetworkId(),
Blockchain.Stellar.toNetworkId(),
Blockchain.InternetComputer.toNetworkId(),
Blockchain.Casper.toNetworkId(),
Blockchain.Algorand.toNetworkId(),
)
private suspend fun ExpressRepository.getFilteredProviders(
userWallet: UserWallet,
filterProviderTypes: List<ExpressProviderType>,

View file

@ -2,7 +2,7 @@ package com.tangem.domain.wallets.usecase
import com.tangem.common.TangemSiteUrlBuilder
import com.tangem.domain.wallets.repository.WalletsPromoRepository
import java.util.Locale
import com.tangem.utils.SupportedLanguages
class GenerateBuyTangemCardLinkUseCase(
private val walletsPromoRepository: WalletsPromoRepository,
@ -15,7 +15,7 @@ class GenerateBuyTangemCardLinkUseCase(
suspend operator fun invoke(utmCampaign: String?): String {
val refCode = walletsPromoRepository.getReferralCodeIfExists()
val refCodeTag = TangemSiteUrlBuilder.getRefCodeTag(refCode)
val langCode = Locale.getDefault().language
val langCode = SupportedLanguages.getCurrentSupportedLanguageCode()
val utmTags = TangemSiteUrlBuilder.getUtmTags(utmCampaign)
return "https://buy.tangem.com/$langCode?$utmTags&$refCodeTag"
}

View file

@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.common.TangemSiteShareUrlBuilder
import com.tangem.common.ui.charts.state.MarketChartData
import com.tangem.common.ui.charts.state.MarketChartDataProducer
import com.tangem.common.ui.charts.state.sorted
@ -667,7 +668,7 @@ internal class MarketsTokenDetailsModel @Inject constructor(
private fun onShareClick() {
val tokenId = params.token.id.value
val shareUrl = "$CRYPTOCURRENCIES_BASE_URL$tokenId"
val shareUrl = TangemSiteShareUrlBuilder.shareUrl(tokenId)
shareManager.shareText(shareUrl)
analyticsEventHandler.send(analyticsEventBuilder.shareClicked())
}
@ -735,6 +736,5 @@ internal class MarketsTokenDetailsModel @Inject constructor(
private companion object {
const val QUOTES_UPDATE_INTERVAL_MILLIS = 60000L
const val RELATED_NEWS_LIMIT = 10
const val CRYPTOCURRENCIES_BASE_URL = "https://tangem.com/en/cryptocurrencies/"
}
}