Updated on 2026-08-14
This commit is contained in:
commit
149ea786e9
8 changed files with 112 additions and 78 deletions
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.common.feedback
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.tap.common.extensions.breakLine
|
||||
|
||||
class FeedbackDataBuilder(
|
||||
|
|
@ -33,9 +32,10 @@ class FeedbackDataBuilder(
|
|||
builder.appendKeyValue("Blockchain", walletInfo.blockchain.fullName)
|
||||
builder.appendKeyValue("Derivation path", walletInfo.derivationPath)
|
||||
|
||||
if (walletInfo.blockchain == Blockchain.Bitcoin) {
|
||||
builder.appendKeyValue("XPUB", infoHolder.extendedPublicKey)
|
||||
}
|
||||
// enable later
|
||||
// if (walletInfo.blockchain == Blockchain.Bitcoin) {
|
||||
// builder.appendKeyValue("XPUB", infoHolder.extendedPublicKey)
|
||||
// }
|
||||
|
||||
builder.appendKeyValue("Outputs count", walletInfo.outputsCount)
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.tangem.domain.common.TwinsHelper
|
|||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_IDS
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.ScanTask
|
||||
|
|
@ -239,7 +240,7 @@ private class ScanWalletProcessor(
|
|||
}
|
||||
|
||||
private fun getWalletProductType(card: CardDTO): ProductType {
|
||||
if (card.batchId == CardDTO.RING_BATCH_ID) {
|
||||
if (RING_BATCH_IDS.contains(card.batchId)) {
|
||||
return ProductType.Ring
|
||||
}
|
||||
return if (card.firmwareVersion >= FirmwareVersion.Ed25519Slip0010Available &&
|
||||
|
|
|
|||
|
|
@ -14,12 +14,18 @@ object BigDecimalFormatter {
|
|||
|
||||
private const val TEMP_CURRENCY_CODE = "USD"
|
||||
|
||||
fun formatCryptoAmount(cryptoAmount: BigDecimal?, cryptoCurrency: String, decimals: Int): String {
|
||||
fun formatCryptoAmount(
|
||||
cryptoAmount: BigDecimal?,
|
||||
cryptoCurrency: String,
|
||||
decimals: Int,
|
||||
locale: Locale = Locale.getDefault(),
|
||||
): String {
|
||||
if (cryptoAmount == null) return EMPTY_BALANCE_SIGN
|
||||
|
||||
val formatter = NumberFormat.getNumberInstance().apply {
|
||||
val formatter = NumberFormat.getNumberInstance(locale).apply {
|
||||
maximumFractionDigits = decimals.coerceAtMost(maximumValue = 8)
|
||||
minimumFractionDigits = 2
|
||||
isGroupingUsed = true
|
||||
roundingMode = RoundingMode.DOWN
|
||||
}
|
||||
|
||||
|
|
@ -32,8 +38,12 @@ object BigDecimalFormatter {
|
|||
}
|
||||
}
|
||||
|
||||
fun formatCryptoAmount(cryptoAmount: BigDecimal?, cryptoCurrency: CryptoCurrency): String {
|
||||
return formatCryptoAmount(cryptoAmount, cryptoCurrency.symbol, cryptoCurrency.decimals)
|
||||
fun formatCryptoAmount(
|
||||
cryptoAmount: BigDecimal?,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
locale: Locale = Locale.getDefault(),
|
||||
): String {
|
||||
return formatCryptoAmount(cryptoAmount, cryptoCurrency.symbol, cryptoCurrency.decimals, locale)
|
||||
}
|
||||
|
||||
fun formatFiatAmount(
|
||||
|
|
|
|||
|
|
@ -321,6 +321,6 @@ data class CardDTO(
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val RING_BATCH_ID = "AC17"
|
||||
val RING_BATCH_IDS = listOf("AC17", "BA01")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.feature.swap.models.states
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
@Immutable
|
||||
sealed class ProviderState {
|
||||
|
||||
abstract val onProviderClick: ((String) -> Unit)?
|
||||
|
|
@ -25,6 +27,7 @@ sealed class ProviderState {
|
|||
val subtitle: TextReference,
|
||||
val selectionType: SelectionType,
|
||||
val additionalBadge: AdditionalBadge,
|
||||
val namePrefix: PrefixType,
|
||||
val percentLowerThenBest: PercentLowerThanBest = PercentLowerThanBest.Empty,
|
||||
override val onProviderClick: (String) -> Unit,
|
||||
) : ProviderState()
|
||||
|
|
@ -39,17 +42,25 @@ sealed class ProviderState {
|
|||
override val onProviderClick: ((String) -> Unit)? = null,
|
||||
) : ProviderState()
|
||||
|
||||
@Immutable
|
||||
sealed class AdditionalBadge {
|
||||
object BestTrade : AdditionalBadge()
|
||||
object Empty : AdditionalBadge()
|
||||
object PermissionRequired : AdditionalBadge()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
enum class SelectionType {
|
||||
NONE, CLICK, SELECT
|
||||
}
|
||||
|
||||
@Immutable
|
||||
enum class PrefixType {
|
||||
NONE, PROVIDED_BY
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
sealed class PercentLowerThanBest {
|
||||
data class Value(val value: Float) : PercentLowerThanBest()
|
||||
object Empty : PercentLowerThanBest()
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ private fun ChooseProviderBottomSheet_Preview() {
|
|||
additionalBadge = ProviderState.AdditionalBadge.BestTrade,
|
||||
percentLowerThenBest = PercentLowerThanBest.Value(-1.0f),
|
||||
selectionType = ProviderState.SelectionType.SELECT,
|
||||
namePrefix = ProviderState.PrefixType.NONE,
|
||||
onProviderClick = {},
|
||||
),
|
||||
ProviderState.Unavailable(
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@ import androidx.compose.ui.res.painterResource
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.RectangleShimmer
|
||||
import com.tangem.core.ui.components.SpacerH24
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -113,12 +114,14 @@ private fun ProviderContentState(
|
|||
modifier = Modifier.padding(start = TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
Row {
|
||||
Text(
|
||||
text = stringResource(id = R.string.express_by_provider),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier.padding(end = TangemTheme.dimens.spacing4),
|
||||
)
|
||||
if (state.namePrefix == ProviderState.PrefixType.PROVIDED_BY) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.express_by_provider),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
modifier = Modifier.padding(end = TangemTheme.dimens.spacing4),
|
||||
)
|
||||
}
|
||||
AnimatedContent(targetState = state.name, label = "") {
|
||||
Text(
|
||||
text = it,
|
||||
|
|
@ -391,75 +394,76 @@ private fun PermissionBadgeItem(modifier: Modifier = Modifier) {
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun ProviderItem_Loading_Preview() {
|
||||
Column {
|
||||
TangemTheme(isDark = false) {
|
||||
ProviderItemBlock(state = ProviderState.Loading())
|
||||
}
|
||||
|
||||
SpacerH24()
|
||||
|
||||
TangemTheme(isDark = true) {
|
||||
ProviderItemBlock(state = ProviderState.Loading())
|
||||
}
|
||||
private fun ProviderItemPreview_Light(
|
||||
@PreviewParameter(ProviderItemParameterProvider::class) state: Pair<ProviderState, Boolean>,
|
||||
) {
|
||||
TangemTheme {
|
||||
ProviderItem(
|
||||
modifier = Modifier.background(TangemTheme.colors.background.action),
|
||||
state = state.first,
|
||||
isSelected = state.second,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Composable
|
||||
private fun ProviderItem_Content_Preview() {
|
||||
val state = ProviderState.Content(
|
||||
id = "1",
|
||||
name = "1inch",
|
||||
type = "DEX",
|
||||
iconUrl = "",
|
||||
subtitle = stringReference("1 000 000"),
|
||||
additionalBadge = ProviderState.AdditionalBadge.PermissionRequired,
|
||||
percentLowerThenBest = PercentLowerThanBest.Value(-1.0f),
|
||||
selectionType = ProviderState.SelectionType.SELECT,
|
||||
onProviderClick = {},
|
||||
)
|
||||
Column {
|
||||
TangemTheme(isDark = false) {
|
||||
ProviderItemBlock(state = state)
|
||||
}
|
||||
|
||||
SpacerH24()
|
||||
|
||||
TangemTheme(isDark = true) {
|
||||
ProviderItemBlock(state = state)
|
||||
}
|
||||
private fun ProviderItemPreview_Dark(
|
||||
@PreviewParameter(ProviderItemParameterProvider::class) state: Pair<ProviderState, Boolean>,
|
||||
) {
|
||||
TangemTheme(isDark = true) {
|
||||
ProviderItem(
|
||||
modifier = Modifier.background(TangemTheme.colors.background.action),
|
||||
state = state.first,
|
||||
isSelected = state.second,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ProviderItem_Unavailable_Preview() {
|
||||
val state = ProviderState.Unavailable(
|
||||
id = "1",
|
||||
name = "1inch",
|
||||
type = "DEX",
|
||||
iconUrl = "",
|
||||
selectionType = ProviderState.SelectionType.SELECT,
|
||||
alertText = stringReference("Unavailable"),
|
||||
)
|
||||
Column {
|
||||
TangemTheme(isDark = false) {
|
||||
ProviderItemBlock(state = state)
|
||||
}
|
||||
private class ProviderItemParameterProvider : CollectionPreviewParameterProvider<Pair<ProviderState, Boolean>>(
|
||||
collection = buildList {
|
||||
val contentState = ProviderState.Content(
|
||||
id = "1",
|
||||
name = "1inch",
|
||||
type = "DEX",
|
||||
iconUrl = "",
|
||||
subtitle = stringReference(value = "0,64554846 DAI ≈ 1 MATIC"),
|
||||
additionalBadge = ProviderState.AdditionalBadge.Empty,
|
||||
percentLowerThenBest = PercentLowerThanBest.Empty,
|
||||
selectionType = ProviderState.SelectionType.SELECT,
|
||||
namePrefix = ProviderState.PrefixType.PROVIDED_BY,
|
||||
onProviderClick = {},
|
||||
)
|
||||
val contentState2 = contentState.copy(
|
||||
subtitle = stringReference(value = "1 132,46 MATIC"),
|
||||
additionalBadge = ProviderState.AdditionalBadge.PermissionRequired,
|
||||
percentLowerThenBest = PercentLowerThanBest.Value(value = 5f),
|
||||
)
|
||||
val unavailableState = ProviderState.Unavailable(
|
||||
id = "1",
|
||||
name = "1inch",
|
||||
type = "DEX",
|
||||
iconUrl = "",
|
||||
alertText = stringReference(value = "Not available"),
|
||||
selectionType = ProviderState.SelectionType.SELECT,
|
||||
onProviderClick = {},
|
||||
)
|
||||
val loadingState = ProviderState.Loading()
|
||||
|
||||
SpacerH24()
|
||||
add(contentState to true)
|
||||
add(contentState to false)
|
||||
|
||||
TangemTheme(isDark = true) {
|
||||
ProviderItemBlock(state = state)
|
||||
}
|
||||
add(contentState2 to true)
|
||||
add(contentState2 to false)
|
||||
|
||||
SpacerH24()
|
||||
add(unavailableState to true)
|
||||
add(unavailableState to false)
|
||||
|
||||
TangemTheme(isDark = true) {
|
||||
ProviderItem(state = state, isSelected = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
add(loadingState to true)
|
||||
add(loadingState to false)
|
||||
},
|
||||
)
|
||||
// endregion Preview
|
||||
|
|
@ -1257,6 +1257,7 @@ internal class StateBuilder(
|
|||
additionalBadge = badge,
|
||||
selectionType = selectionType,
|
||||
percentLowerThenBest = PercentLowerThanBest.Empty,
|
||||
namePrefix = ProviderState.PrefixType.PROVIDED_BY,
|
||||
onProviderClick = onProviderClick,
|
||||
)
|
||||
}
|
||||
|
|
@ -1288,6 +1289,7 @@ internal class StateBuilder(
|
|||
percentLowerThenBest = pricesLowerBest[this.providerId]?.let { percent ->
|
||||
PercentLowerThanBest.Value(percent)
|
||||
} ?: PercentLowerThanBest.Value(0f),
|
||||
namePrefix = ProviderState.PrefixType.NONE,
|
||||
onProviderClick = onProviderClick,
|
||||
)
|
||||
}
|
||||
|
|
@ -1322,6 +1324,11 @@ internal class StateBuilder(
|
|||
subtitle = alertText,
|
||||
additionalBadge = ProviderState.AdditionalBadge.Empty,
|
||||
percentLowerThenBest = PercentLowerThanBest.Empty,
|
||||
namePrefix = if (selectionType != ProviderState.SelectionType.SELECT) {
|
||||
ProviderState.PrefixType.PROVIDED_BY
|
||||
} else {
|
||||
ProviderState.PrefixType.NONE
|
||||
},
|
||||
onProviderClick = onProviderClick,
|
||||
)
|
||||
}
|
||||
|
|
@ -1347,7 +1354,7 @@ internal class StateBuilder(
|
|||
}
|
||||
|
||||
private fun SwapAmount.getFormattedCryptoAmount(token: CryptoCurrency): String {
|
||||
return "${this.formatToUIRepresentation()} ${token.symbol}"
|
||||
return BigDecimalFormatter.formatCryptoAmount(value, token.symbol, token.decimals)
|
||||
}
|
||||
|
||||
private fun BigDecimal.calculateRate(to: BigDecimal, decimals: Int): BigDecimal {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue