Updated on 2026-08-14

This commit is contained in:
Tangem 2024-11-18 14:40:19 +02:00
parent 546bcc908f
commit 6ac5724e56
9 changed files with 63 additions and 37 deletions

View file

@ -114,12 +114,12 @@ internal object TokenMarketInfoConverter : Converter<TokenMarketInfoResponse, To
private fun TokenMarketInfoResponse.SecurityData.convert(): TokenMarketInfo.SecurityData { private fun TokenMarketInfoResponse.SecurityData.convert(): TokenMarketInfo.SecurityData {
return TokenMarketInfo.SecurityData( return TokenMarketInfo.SecurityData(
totalSecurityScore = totalSecurityScore, totalSecurityScore = totalSecurityScore,
providerData = providerData.map { it.convert() }, securityScoreProviderData = providerData.map { it.convert() },
) )
} }
private fun TokenMarketInfoResponse.ProviderData.convert(): TokenMarketInfo.ProviderData { private fun TokenMarketInfoResponse.ProviderData.convert(): TokenMarketInfo.SecurityScoreProvider {
return TokenMarketInfo.ProviderData( return TokenMarketInfo.SecurityScoreProvider(
providerId = providerId, providerId = providerId,
providerName = providerName, providerName = providerName,
urlData = link?.convertToUrlData(), urlData = link?.convertToUrlData(),
@ -129,8 +129,8 @@ internal object TokenMarketInfoConverter : Converter<TokenMarketInfoResponse, To
) )
} }
private fun String.convertToUrlData(): TokenMarketInfo.ProviderUrlData { private fun String.convertToUrlData(): TokenMarketInfo.SecurityScoreProvider.UrlData {
return TokenMarketInfo.ProviderUrlData( return TokenMarketInfo.SecurityScoreProvider.UrlData(
fullUrl = this, fullUrl = this,
rootHost = this.extractMainDomainOrNull(), rootHost = this.extractMainDomainOrNull(),
) )

View file

@ -55,22 +55,22 @@ data class TokenMarketInfo(
data class SecurityData( data class SecurityData(
val totalSecurityScore: Float, val totalSecurityScore: Float,
val providerData: List<ProviderData>, val securityScoreProviderData: List<SecurityScoreProvider>,
) )
data class ProviderData( data class SecurityScoreProvider(
val providerId: String, val providerId: String,
val providerName: String, val providerName: String,
val urlData: ProviderUrlData?, val urlData: UrlData?,
val iconUrl: String, val iconUrl: String,
val securityScore: Float, val securityScore: Float,
val lastAuditDate: DateTime?, val lastAuditDate: DateTime?,
) ) {
data class UrlData(
data class ProviderUrlData( val fullUrl: String,
val fullUrl: String, val rootHost: String?,
val rootHost: String?, )
) }
data class Links( data class Links(
val officialLinks: List<Link>?, val officialLinks: List<Link>?,

View file

@ -51,6 +51,19 @@ internal class MarketDetailsAnalyticsEvent(
"Token" to token.symbol, "Token" to token.symbol,
), ),
) )
fun securityScoreOpened() = MarketDetailsAnalyticsEvent(
event = "Security Score Info",
params = mapOf("Token" to token.symbol),
)
fun securityScoreProviderClicked(provider: String) = MarketDetailsAnalyticsEvent(
event = "Security Score Provider Clicked",
params = mapOf(
"Token" to token.symbol,
"Provider" to provider,
),
)
} }
enum class IntervalType(val source: String) { enum class IntervalType(val source: String) {

View file

@ -88,8 +88,19 @@ internal class MarketsTokenDetailsModel @Inject constructor(
// === Analytics === // === Analytics ===
analyticsEventHandler.send(analyticsEventBuilder.linkClicked(linkTitle = link.title)) analyticsEventHandler.send(analyticsEventBuilder.linkClicked(linkTitle = link.title))
}, },
onSecurityScoreInfoClick = {
showBottomSheet(it)
// === Analytics ===
analyticsEventHandler.send(analyticsEventBuilder.securityScoreOpened())
},
onSecurityScoreProviderLinkClick = { onSecurityScoreProviderLinkClick = {
urlOpener.openUrl(it) it.urlData?.fullUrl?.let { url ->
urlOpener.openUrl(url)
}
// === Analytics ===
analyticsEventHandler.send(analyticsEventBuilder.securityScoreProviderClicked(it.name))
}, },
// === Analytics === // === Analytics ===
onPricePerformanceIntervalChanged = { onPricePerformanceIntervalChanged = {

View file

@ -13,12 +13,12 @@ import com.tangem.utils.converter.Converter
@Stable @Stable
internal class SecurityScoreConverter( internal class SecurityScoreConverter(
private val onInfoClick: (SecurityScoreBottomSheetContent) -> Unit, private val onSecurityScoreInfoClick: (SecurityScoreBottomSheetContent) -> Unit,
private val onSecurityScoreProviderLinkClick: (String) -> Unit, private val onSecurityScoreProviderLinkClick: (SecurityScoreBottomSheetContent.SecurityScoreProviderUM) -> Unit,
) : Converter<TokenMarketInfo.SecurityData, SecurityScoreUM> { ) : Converter<TokenMarketInfo.SecurityData, SecurityScoreUM> {
override fun convert(value: TokenMarketInfo.SecurityData): SecurityScoreUM { override fun convert(value: TokenMarketInfo.SecurityData): SecurityScoreUM {
val ratingsCount = value.providerData.size val ratingsCount = value.securityScoreProviderData.size
return SecurityScoreUM( return SecurityScoreUM(
score = value.totalSecurityScore, score = value.totalSecurityScore,
description = pluralReference( description = pluralReference(
@ -27,11 +27,11 @@ internal class SecurityScoreConverter(
formatArgs = wrappedList(ratingsCount), formatArgs = wrappedList(ratingsCount),
), ),
onInfoClick = { onInfoClick = {
onInfoClick( onSecurityScoreInfoClick(
SecurityScoreBottomSheetContent( SecurityScoreBottomSheetContent(
title = resourceReference(R.string.markets_token_details_security_score), title = resourceReference(R.string.markets_token_details_security_score),
description = resourceReference(R.string.markets_token_details_security_score_description), description = resourceReference(R.string.markets_token_details_security_score_description),
providers = value.providerData.map { providers = value.securityScoreProviderData.map {
SecurityScoreBottomSheetContent.SecurityScoreProviderUM( SecurityScoreBottomSheetContent.SecurityScoreProviderUM(
name = it.providerName, name = it.providerName,
lastAuditDate = it.lastAuditDate?.let { date -> lastAuditDate = it.lastAuditDate?.let { date ->
@ -40,7 +40,7 @@ internal class SecurityScoreConverter(
score = it.securityScore, score = it.securityScore,
urlData = it.urlData?.let { urlData = it.urlData?.let {
urlData -> urlData ->
SecurityScoreBottomSheetContent.SecurityScoreProviderUrlData( SecurityScoreBottomSheetContent.SecurityScoreProviderUM.UrlData(
fullUrl = urlData.fullUrl, fullUrl = urlData.fullUrl,
rootHost = urlData.rootHost, rootHost = urlData.rootHost,
) )

View file

@ -8,6 +8,7 @@ import com.tangem.domain.markets.TokenMarketInfo
import com.tangem.features.markets.details.impl.ui.state.LinksUM import com.tangem.features.markets.details.impl.ui.state.LinksUM
import com.tangem.features.markets.details.impl.ui.state.ListedOnUM import com.tangem.features.markets.details.impl.ui.state.ListedOnUM
import com.tangem.features.markets.details.impl.ui.state.MarketsTokenDetailsUM import com.tangem.features.markets.details.impl.ui.state.MarketsTokenDetailsUM
import com.tangem.features.markets.details.impl.ui.state.SecurityScoreBottomSheetContent
import com.tangem.utils.Provider import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
@ -17,8 +18,9 @@ internal class TokenMarketInfoConverter(
private val appCurrency: Provider<AppCurrency>, private val appCurrency: Provider<AppCurrency>,
private val onInfoClick: (TangemBottomSheetConfigContent) -> Unit, private val onInfoClick: (TangemBottomSheetConfigContent) -> Unit,
private val onListedOnClick: (Int) -> Unit, private val onListedOnClick: (Int) -> Unit,
onSecurityScoreInfoClick: (SecurityScoreBottomSheetContent) -> Unit,
onLinkClick: (LinksUM.Link) -> Unit, onLinkClick: (LinksUM.Link) -> Unit,
onSecurityScoreProviderLinkClick: (String) -> Unit, onSecurityScoreProviderLinkClick: (SecurityScoreBottomSheetContent.SecurityScoreProviderUM) -> Unit,
onPricePerformanceIntervalChanged: (PriceChangeInterval) -> Unit, onPricePerformanceIntervalChanged: (PriceChangeInterval) -> Unit,
onInsightsIntervalChanged: (PriceChangeInterval) -> Unit, onInsightsIntervalChanged: (PriceChangeInterval) -> Unit,
) : Converter<TokenMarketInfo, MarketsTokenDetailsUM.InformationBlocks> { ) : Converter<TokenMarketInfo, MarketsTokenDetailsUM.InformationBlocks> {
@ -30,7 +32,7 @@ internal class TokenMarketInfoConverter(
) )
private val securityScoreConverter = SecurityScoreConverter( private val securityScoreConverter = SecurityScoreConverter(
onInfoClick = onInfoClick, onSecurityScoreInfoClick = onSecurityScoreInfoClick,
onSecurityScoreProviderLinkClick = onSecurityScoreProviderLinkClick, onSecurityScoreProviderLinkClick = onSecurityScoreProviderLinkClick,
) )
private val pricePerformanceConverter = PricePerformanceConverter( private val pricePerformanceConverter = PricePerformanceConverter(

View file

@ -86,7 +86,7 @@ internal fun SecurityScoreBottomSheet(config: TangemBottomSheetConfig) {
@Composable @Composable
private fun SecurityScoreProviderRow( private fun SecurityScoreProviderRow(
providerUM: SecurityScoreBottomSheetContent.SecurityScoreProviderUM, providerUM: SecurityScoreBottomSheetContent.SecurityScoreProviderUM,
onLinkClick: (String) -> Unit, onLinkClick: (SecurityScoreBottomSheetContent.SecurityScoreProviderUM) -> Unit,
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@ -137,7 +137,7 @@ private fun SecurityScoreProviderRow(
enabled = providerUM.urlData != null, enabled = providerUM.urlData != null,
indication = ripple(bounded = false), indication = ripple(bounded = false),
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
onClick = { providerUM.urlData?.let { onLinkClick(it.fullUrl) } }, onClick = { onLinkClick(providerUM) },
), ),
) { ) {
ScoreStarsBlock( ScoreStarsBlock(

View file

@ -17,7 +17,7 @@ internal object SecurityScorePreviewData {
name = "Moralis", name = "Moralis",
lastAuditDate = "21.10.2024", lastAuditDate = "21.10.2024",
score = 4.9F, score = 4.9F,
urlData = SecurityScoreBottomSheetContent.SecurityScoreProviderUrlData( urlData = SecurityScoreBottomSheetContent.SecurityScoreProviderUM.UrlData(
fullUrl = "https://moralis.com/", fullUrl = "https://moralis.com/",
rootHost = "moralis.com", rootHost = "moralis.com",
), ),
@ -27,7 +27,7 @@ internal object SecurityScorePreviewData {
name = "Certik", name = "Certik",
lastAuditDate = "10.07.2024", lastAuditDate = "10.07.2024",
score = 4.6F, score = 4.6F,
urlData = SecurityScoreBottomSheetContent.SecurityScoreProviderUrlData( urlData = SecurityScoreBottomSheetContent.SecurityScoreProviderUM.UrlData(
fullUrl = "https://certik.com/", fullUrl = "https://certik.com/",
rootHost = "certik.com", rootHost = "certik.com",
), ),
@ -37,7 +37,7 @@ internal object SecurityScorePreviewData {
name = "Cyberscope", name = "Cyberscope",
lastAuditDate = "25.06.2023", lastAuditDate = "25.06.2023",
score = 4.5F, score = 4.5F,
urlData = SecurityScoreBottomSheetContent.SecurityScoreProviderUrlData( urlData = SecurityScoreBottomSheetContent.SecurityScoreProviderUM.UrlData(
fullUrl = "https://cyberscope.com/", fullUrl = "https://cyberscope.com/",
rootHost = "cyberscope.com", rootHost = "cyberscope.com",
), ),
@ -47,7 +47,7 @@ internal object SecurityScorePreviewData {
name = "TokenInsight", name = "TokenInsight",
lastAuditDate = "17.01.2022", lastAuditDate = "17.01.2022",
score = 4.0F, score = 4.0F,
urlData = SecurityScoreBottomSheetContent.SecurityScoreProviderUrlData( urlData = SecurityScoreBottomSheetContent.SecurityScoreProviderUM.UrlData(
fullUrl = "https://tokeninsight.com/", fullUrl = "https://tokeninsight.com/",
rootHost = "tokeninsight.com", rootHost = "tokeninsight.com",
), ),

View file

@ -7,19 +7,19 @@ internal data class SecurityScoreBottomSheetContent(
val title: TextReference, val title: TextReference,
val description: TextReference, val description: TextReference,
val providers: List<SecurityScoreProviderUM>, val providers: List<SecurityScoreProviderUM>,
val onProviderLinkClick: (String) -> Unit, val onProviderLinkClick: (SecurityScoreProviderUM) -> Unit,
) : TangemBottomSheetConfigContent { ) : TangemBottomSheetConfigContent {
data class SecurityScoreProviderUM( data class SecurityScoreProviderUM(
val name: String, val name: String,
val lastAuditDate: String?, val lastAuditDate: String?,
val score: Float, val score: Float,
val urlData: SecurityScoreProviderUrlData?, val urlData: UrlData?,
val iconUrl: String?, val iconUrl: String?,
) ) {
data class UrlData(
data class SecurityScoreProviderUrlData( val fullUrl: String,
val fullUrl: String, val rootHost: String?,
val rootHost: String?, )
) }
} }