Updated on 2026-08-14

This commit is contained in:
Tangem 2023-06-26 11:52:43 +03:00
commit d63de11663
126 changed files with 1456 additions and 506 deletions

View file

@ -1,12 +1,16 @@
package com.tangem.tap.features.tokens.impl.presentation.states
import androidx.compose.runtime.Immutable
import kotlinx.collections.immutable.ImmutableList
/**
* Network item state
* Token item state.
* All subclasses is stable, but @Immutable annotation is required to use this sealed class like as
* field of TokensListStateHolder.
*
[REDACTED_AUTHOR]
*/
@Immutable
sealed interface TokenItemState {
/** Token id */

View file

@ -1,5 +1,6 @@
package com.tangem.tap.features.tokens.impl.presentation.states
import androidx.compose.runtime.Immutable
import androidx.paging.LoadState
import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
@ -9,6 +10,7 @@ import kotlinx.coroutines.flow.Flow
*
[REDACTED_AUTHOR]
*/
@Immutable
internal sealed interface TokensListStateHolder {
/** Toolbar state */

View file

@ -1,6 +1,13 @@
package com.tangem.tap.features.tokens.impl.presentation.states
/** Toolbar state */
import androidx.compose.runtime.Immutable
/**
* Toolbar state.
* All subclasses is stable, but @Immutable annotation is required to use this sealed class like as
* field of TokensListStateHolder.
*/
@Immutable
sealed interface TokensListToolbarState {
/** Callback to be invoked when BackButton is being clicked */

View file

@ -22,14 +22,22 @@ object MultipleAddressUiHelper {
return when (id) {
R.id.chip_default -> {
when (blockchain) {
Blockchain.Bitcoin, Blockchain.BitcoinTestnet, Blockchain.Litecoin -> BitcoinAddressType.Segwit
Blockchain.Bitcoin,
Blockchain.BitcoinTestnet,
Blockchain.Litecoin,
Blockchain.BitcoinCash,
-> BitcoinAddressType.Segwit
Blockchain.CardanoShelley -> CardanoAddressType.Shelley
else -> null
}
}
R.id.chip_legacy -> {
when (blockchain) {
Blockchain.Bitcoin, Blockchain.BitcoinTestnet, Blockchain.Litecoin -> BitcoinAddressType.Legacy
Blockchain.Bitcoin,
Blockchain.BitcoinTestnet,
Blockchain.Litecoin,
Blockchain.BitcoinCash,
-> BitcoinAddressType.Legacy
Blockchain.CardanoShelley -> CardanoAddressType.Byron
else -> null
}

View file

@ -12,6 +12,7 @@ import com.tangem.tap.common.extensions.toFormattedCurrencyString
import com.tangem.tap.common.extensions.toFormattedFiatValue
import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.domain.model.WalletStoreModel
import com.tangem.tap.features.wallet.models.PendingTransactionType
import com.tangem.tap.features.wallet.models.WalletWarning
import com.tangem.tap.features.wallet.redux.WalletMainButton
import com.tangem.tap.features.wallet.redux.utils.UNKNOWN_AMOUNT_SIGN
@ -19,9 +20,24 @@ import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
import java.math.BigDecimal
internal fun WalletDataModel.mainButton(blockchainAmount: BigDecimal): WalletMainButton = WalletMainButton.SendButton(
enabled = !isEmptyAmount && status.pendingTransactions.isEmpty() && !blockchainAmount.isZero(),
enabled = !isEmptyAmount &&
hasPendingTransactions() &&
!blockchainAmount.isZero(),
)
internal fun WalletDataModel.hasPendingTransactions(): Boolean {
// for now check pending ongoing only just for BTC, later test and add other utxo networks
val isBitcoinBlockchain =
currency.blockchain == Blockchain.Bitcoin || currency.blockchain == Blockchain.BitcoinTestnet
if (currency.isBlockchain() && isBitcoinBlockchain) {
val outgoingTransactions = status.pendingTransactions.filter {
it.type == PendingTransactionType.Outgoing
}
return outgoingTransactions.isEmpty()
}
return status.pendingTransactions.isEmpty()
}
internal fun WalletDataModel.getFormattedAmount(): String {
return status.amount.toFormattedCurrencyString(
decimals = currency.decimals,

View file

@ -4,14 +4,7 @@ import android.content.Context
import android.util.AttributeSet
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.*
import androidx.compose.material.Divider
import androidx.compose.material.Surface
import androidx.compose.material.Text
@ -27,11 +20,7 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.SelectorButton
import com.tangem.core.ui.components.SpacerH12
import com.tangem.core.ui.components.SpacerH4
import com.tangem.core.ui.components.SpacerW16
import com.tangem.core.ui.components.SpacerW4
import com.tangem.core.ui.components.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.domain.model.TotalFiatBalance
@ -42,7 +31,8 @@ import java.math.BigDecimal
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.NumberFormat
import java.util.*
import java.util.Currency
import java.util.Locale
internal class TotalBalanceCard @JvmOverloads constructor(
context: Context,
@ -125,7 +115,7 @@ private fun TotalBalanceCardContent(state: TotalBalanceCardState, modifier: Modi
-> LoadedAmount(
amount = buildAmountString(
amount = state.amount,
fiatCurrencySymbol = state.fiatCurrency.symbol,
fiatCurrency = state.fiatCurrency,
),
)
}
@ -228,30 +218,45 @@ private fun LoadedAmount(amount: AnnotatedString, modifier: Modifier = Modifier)
}
@Composable
private fun buildAmountString(amount: BigDecimal?, fiatCurrencySymbol: String): AnnotatedString {
private fun buildAmountString(amount: BigDecimal?, fiatCurrency: FiatCurrency): AnnotatedString {
if (amount == null) return AnnotatedString(text = UNKNOWN_AMOUNT_SIGN)
val formatter = NumberFormat.getInstance(Locale.getDefault()) as? DecimalFormat
?: return AnnotatedString("${amount.toPlainString()} $fiatCurrencySymbol")
val decimalFormat = formatter.apply {
maximumFractionDigits = 2
minimumFractionDigits = 2
isGroupingUsed = true
this.roundingMode = RoundingMode.HALF_UP
val locale = Locale.getDefault()
val fractionDigits = 2
val formatter = NumberFormat.getCurrencyInstance(locale) as? DecimalFormat
?: return AnnotatedString("${amount.toPlainString()} ${fiatCurrency.symbol}")
val currencyToShow = "${fiatCurrency.symbol}"
val scaledAmount = Currency.getInstance(fiatCurrency.code)?.let { currency ->
formatter.currency = currency
formatter.maximumFractionDigits = fractionDigits
formatter.minimumFractionDigits = fractionDigits
formatter.isGroupingUsed = true
formatter.roundingMode = RoundingMode.HALF_UP
formatter.format(amount).replace(currency.symbol, currencyToShow)
} ?: formatter.format(amount)
val integer = scaledAmount.substringBefore(formatter.decimalFormatSymbols.decimalSeparator)
var reminder = scaledAmount.substringAfter(formatter.decimalFormatSymbols.decimalSeparator)
// if locale formatted currency at the end, remember it and place out of AnnotatedString
val currency = if (reminder.endsWith(currencyToShow)) {
reminder = reminder.dropLast(currencyToShow.length)
currencyToShow
} else {
""
}
val scaledAmount = decimalFormat.format(amount)
val integer = scaledAmount.substringBefore(decimalFormat.decimalFormatSymbols.decimalSeparator)
val reminder = scaledAmount.substringAfter(decimalFormat.decimalFormatSymbols.decimalSeparator)
return buildAnnotatedString {
append(integer)
append(decimalFormat.decimalFormatSymbols.decimalSeparator)
append(formatter.decimalFormatSymbols.decimalSeparator)
append(
AnnotatedString(
text = "$reminder $fiatCurrencySymbol",
text = reminder,
spanStyle = TangemTheme.typography.h3.toSpanStyle(),
),
)
append(currency) // it is not empty if was placed at the end after locale formatting
}
}