Updated on 2026-08-14
This commit is contained in:
commit
d63de11663
126 changed files with 1456 additions and 506 deletions
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue