From af8aa449f670704a7d32951f1a4797de12939020 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Feb 2023 18:49:22 +0300 Subject: [PATCH 01/29] Updated on 2026-08-14 --- .../com/tangem/tap/domain/TangemSigner.kt | 22 +++++++++++-------- .../feature/swap/domain/SwapInteractorImpl.kt | 6 ++--- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt index 1979b1df8a..d9e3f1aa97 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt @@ -7,8 +7,8 @@ import com.tangem.blockchain.common.Wallet import com.tangem.common.CompletionResult import com.tangem.domain.common.CardDTO import com.tangem.tap.domain.tasks.SignHashesTask +import kotlinx.coroutines.suspendCancellableCoroutine import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine class TangemSigner( private val card: CardDTO, @@ -20,9 +20,9 @@ class TangemSigner( override suspend fun sign( hashes: List, - publicKey: Wallet.PublicKey + publicKey: Wallet.PublicKey, ): CompletionResult> { - return suspendCoroutine { continuation -> + return suspendCancellableCoroutine { continuation -> val cardId = if (card.backupStatus?.isActive == true) null else card.cardId val task = SignHashesTask(hashes, publicKey) @@ -37,13 +37,17 @@ class TangemSigner( signerCallback( TangemSignerResponse( result.data.totalSignedHashes, - result.data.remainingSignatures - ) + result.data.remainingSignatures, + ), ) - continuation.resume(CompletionResult.Success(result.data.signatures)) + if (continuation.isActive) { + continuation.resume(CompletionResult.Success(result.data.signatures)) + } } is CompletionResult.Failure -> - continuation.resume(CompletionResult.Failure(result.error)) + if (continuation.isActive) { + continuation.resume(CompletionResult.Failure(result.error)) + } } } } @@ -51,11 +55,11 @@ class TangemSigner( override suspend fun sign( hash: ByteArray, - publicKey: Wallet.PublicKey + publicKey: Wallet.PublicKey, ): CompletionResult { val result = sign( hashes = listOf(hash), - publicKey = publicKey + publicKey = publicKey, ) return when (result) { diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 9f042170b7..ada2f49f4d 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -618,9 +618,9 @@ internal class SwapInteractorImpl @Inject constructor( toTokenAmount: BigDecimal, toRate: Double, ): Float { - val toTokenFiatValue = toTokenAmount.multiply(toRate.toBigDecimal()).setScale(2, RoundingMode.HALF_UP) - val fromTokenFiatValue = fromTokenAmount.multiply(fromRate.toBigDecimal()).setScale(2, RoundingMode.HALF_UP) - return (BigDecimal.ONE - toTokenFiatValue / fromTokenFiatValue).toFloat() + val toTokenFiatValue = toTokenAmount.multiply(toRate.toBigDecimal()) + val fromTokenFiatValue = fromTokenAmount.multiply(fromRate.toBigDecimal()) + return (BigDecimal.ONE - toTokenFiatValue.divide(fromTokenFiatValue, 2, RoundingMode.HALF_UP)).toFloat() } companion object { From 90001a221128aede72898d734632eb1fd2bee7df Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Feb 2023 19:34:57 +0300 Subject: [PATCH 02/29] Updated on 2026-08-14 --- core/utils/src/main/java/com/tangem/utils/FormatExtensions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/utils/src/main/java/com/tangem/utils/FormatExtensions.kt b/core/utils/src/main/java/com/tangem/utils/FormatExtensions.kt index 8621eb2521..1e266be497 100644 --- a/core/utils/src/main/java/com/tangem/utils/FormatExtensions.kt +++ b/core/utils/src/main/java/com/tangem/utils/FormatExtensions.kt @@ -50,7 +50,7 @@ fun BigDecimal.toFiatString( val formatter = NumberFormat.getInstance(Locale.getDefault()) as? DecimalFormat val df = formatter?.apply { maximumFractionDigits = 2 - minimumFractionDigits = 0 + minimumFractionDigits = 2 isGroupingUsed = true this.roundingMode = roundingMode } From 99244e87a6cb2bbbe179ff99394ae0af8a8ef3b9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Feb 2023 19:52:23 +0300 Subject: [PATCH 03/29] Updated on 2026-08-14 --- .../java/com/tangem/tap/proxy/TransactionManagerImpl.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt index dd7ecf0d49..fec31ea24a 100644 --- a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt @@ -26,7 +26,7 @@ import com.tangem.lib.crypto.models.transactions.SendTxResult import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TangemSigner import com.tangem.tap.domain.tokens.models.BlockchainNetwork -import com.tangem.tap.store +import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.tangemSdk import java.math.BigDecimal @@ -109,6 +109,8 @@ class TransactionManagerImpl( FirebaseCrashlytics.getInstance().recordException(ex) return SendTxResult.UnknownError(ex) } + // workaround, should update wallet after transaction + appStateHolder.mainStore?.dispatch(WalletAction.LoadData.Refresh) return handleSendResult(sendResult) } @@ -191,7 +193,7 @@ class TransactionManagerImpl( tangemSdk = tangemSdk, initialMessage = Message(), ) { signResponse -> - store.dispatch( + appStateHolder.mainStore?.dispatch( GlobalAction.UpdateWalletSignedHashes( walletSignedHashes = signResponse.totalSignedHashes, walletPublicKey = walletManager.wallet.publicKey.seedKey, From 2f936ad2f36d3a8e6f873a259202d5f3e805654f Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Feb 2023 22:34:10 +0300 Subject: [PATCH 04/29] Updated on 2026-08-14 --- .../java/com/tangem/tap/proxy/TransactionManagerImpl.kt | 3 --- .../main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt | 6 ++++++ .../com/tangem/feature/swap/domain/SwapInteractorImpl.kt | 1 + .../main/java/com/tangem/lib/crypto/UserWalletManager.kt | 2 ++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt index fec31ea24a..0607b9caaa 100644 --- a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt @@ -26,7 +26,6 @@ import com.tangem.lib.crypto.models.transactions.SendTxResult import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TangemSigner import com.tangem.tap.domain.tokens.models.BlockchainNetwork -import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.tangemSdk import java.math.BigDecimal @@ -109,8 +108,6 @@ class TransactionManagerImpl( FirebaseCrashlytics.getInstance().recordException(ex) return SendTxResult.UnknownError(ex) } - // workaround, should update wallet after transaction - appStateHolder.mainStore?.dispatch(WalletAction.LoadData.Refresh) return handleSendResult(sendResult) } diff --git a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt index d0f604b74f..715f99415a 100644 --- a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt @@ -113,6 +113,7 @@ class UserWalletManagerImpl( val action = addNonNativeTokenToWalletAction(currency, card, blockchain) val mainStore = requireNotNull(appStateHolder.mainStore) { "mainStore is null" } mainStore.dispatchOnMain(action) + delay(DELAY_UPDATE_WALLET) } } @@ -238,6 +239,11 @@ class UserWalletManagerImpl( ) } + override fun refreshWallet() { + // workaround, should update wallet after transaction + appStateHolder.mainStore?.dispatchOnMain(WalletAction.LoadData.Refresh) + } + private fun createDerivationParams(derivationStyle: DerivationStyle?): DerivationParams? { // todo clarify if its need to add Custom return derivationStyle?.let { DerivationParams.Default(derivationStyle) } diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index ada2f49f4d..2307af3c90 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -218,6 +218,7 @@ internal class SwapInteractorImpl @Inject constructor( return when (result) { is SendTxResult.Success -> { userWalletManager.addToken(cryptoCurrencyConverter.convert(currencyToGet)) + userWalletManager.refreshWallet() TxState.TxSent( fromAmount = amountFormatter.formatSwapAmountToUI(swapData.fromTokenAmount, currencyToSend.symbol), toAmount = amountFormatter.formatSwapAmountToUI(swapData.toTokenAmount, currencyToGet.symbol), diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt index 65ee146a74..258148f3ca 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt @@ -39,6 +39,8 @@ interface UserWalletManager { @Throws(IllegalStateException::class) suspend fun addToken(currency: Currency) + fun refreshWallet() + /** * Returns wallet public address for token * From a6cff6210bd89cca1142ced70cf6ea72d1934840 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 21 Feb 2023 11:31:47 +0300 Subject: [PATCH 05/29] Updated on 2026-08-14 --- app/src/main/res/layout/dialog_wallet_trade.xml | 2 +- app/src/main/res/layout/view_wallet_details_buttons_row.xml | 2 +- core/res/src/main/res/values-de/strings.xml | 1 + core/res/src/main/res/values-fr/strings.xml | 1 + core/res/src/main/res/values-it/strings.xml | 1 + core/res/src/main/res/values-ru/strings.xml | 1 + core/res/src/main/res/values-zh-rTW/strings.xml | 1 + core/res/src/main/res/values/strings.xml | 1 + 8 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/dialog_wallet_trade.xml b/app/src/main/res/layout/dialog_wallet_trade.xml index cc9299027f..b2e6a5e45b 100644 --- a/app/src/main/res/layout/dialog_wallet_trade.xml +++ b/app/src/main/res/layout/dialog_wallet_trade.xml @@ -53,7 +53,7 @@ android:focusable="true" android:gravity="center_vertical" android:padding="16dp" - android:text="@string/swapping_swap" + android:text="@string/swapping_swap_action" android:textColor="@color/darkGray3" android:textSize="14sp" android:textStyle="bold" diff --git a/app/src/main/res/layout/view_wallet_details_buttons_row.xml b/app/src/main/res/layout/view_wallet_details_buttons_row.xml index 82365317fe..3a46e5177a 100644 --- a/app/src/main/res/layout/view_wallet_details_buttons_row.xml +++ b/app/src/main/res/layout/view_wallet_details_buttons_row.xml @@ -39,7 +39,7 @@ diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index ab179ea317..c7204aedc5 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -351,6 +351,7 @@ View in Explorer In progress Swap + Swap Swap of %s to Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. Other tokens diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 76d8e32bc5..309fd73c0e 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -351,6 +351,7 @@ View in Explorer In progress Swap + Swap Swap of %s to Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. Other tokens diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index 751cf170b2..aa56c83847 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -351,6 +351,7 @@ View in Explorer In progress Swap + Swap Swap of %s to Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. Other tokens diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 4772adc1cc..20bc6c313d 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -351,6 +351,7 @@ Открыть в обозревателе В процессе Обмен + Обменять Обмен %s на Кроме того, котировки включают комиссию Tangem в размере %s. Это помогает нам предоставлять первоклассный продукт. Другие токены diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml index 6b98188598..e74a4bab51 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -351,6 +351,7 @@ 在瀏覽器中查看 進行中 交換 + Swap 交易 %s 至 Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. 其他代幣 diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index c3a6b51606..59a3b2dcb3 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -351,6 +351,7 @@ View in Explorer In progress Swap + Swap Swap of %s to Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. Other tokens From 4c3312186d44105c31dab8a6f1eba053f4c309d1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Feb 2023 20:29:01 +0300 Subject: [PATCH 06/29] Updated on 2026-08-14 --- .../wallet/ui/view/TotalBalanceCard.kt | 337 ++++++++++++++++++ .../wallet/ui/wallet/MultiWalletView.kt | 56 +-- .../wallet/ui/wallet/SingleWalletView.kt | 2 +- app/src/main/res/layout/fragment_wallet.xml | 4 +- .../res/layout/layout_card_total_balance.xml | 84 ----- .../com/tangem/core/ui/components/Buttons.kt | 74 +++- 6 files changed, 413 insertions(+), 144 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt delete mode 100644 app/src/main/res/layout/layout_card_total_balance.xml diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt new file mode 100644 index 0000000000..5a39cf2b28 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt @@ -0,0 +1,337 @@ +package com.tangem.tap.features.wallet.ui.view + +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.material.Divider +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.AbstractComposeView +import androidx.compose.ui.res.stringResource +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.res.TangemTheme +import com.tangem.tap.common.entities.FiatCurrency +import com.tangem.tap.common.extensions.formatWithSpaces +import com.tangem.tap.features.wallet.models.TotalBalance +import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.wallet.R +import com.valentinilk.shimmer.shimmer +import java.math.BigDecimal +import java.math.RoundingMode +import java.text.DecimalFormat +import java.util.* + +internal class TotalBalanceCard @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, +) : AbstractComposeView(context, attrs, defStyleAttr) { + private var state by mutableStateOf(TotalBalanceCardState.Empty) + + var status: TotalBalance? = null + set(value) { + if (field == value) return + field = value + updateState(value, onChangeFiatCurrencyClick) + } + + var onChangeFiatCurrencyClick: () -> Unit = { /* no-op */ } + set(value) { + if (field == value) return + field = value + updateState(status, value) + } + + @Composable + override fun Content() { + TangemTheme { + TotalBalanceCardContent(state = state) + } + } + + override fun getAccessibilityClassName(): CharSequence { + return javaClass.name + } + + private fun updateState(status: TotalBalance?, onChangeCurrencyClick: () -> Unit) { + state = when (status?.state) { + null -> TotalBalanceCardState.Empty + ProgressState.Loading -> TotalBalanceCardState.Loading( + fiatCurrency = status.fiatCurrency, + onChangeFiatCurrencyClick = onChangeCurrencyClick, + ) + ProgressState.Error -> TotalBalanceCardState.Failure( + amount = status.fiatAmount, + fiatCurrency = status.fiatCurrency, + onChangeFiatCurrencyClick = onChangeCurrencyClick, + ) + ProgressState.Refreshing, + ProgressState.Done, + -> TotalBalanceCardState.Success( + amount = status.fiatAmount, + fiatCurrency = status.fiatCurrency, + onChangeFiatCurrencyClick = onChangeCurrencyClick, + ) + } + } +} + +@Composable +private fun TotalBalanceCardContent( + state: TotalBalanceCardState, + modifier: Modifier = Modifier, +) { + TotalBalanceCardScaffold( + modifier = modifier, + title = { + Text( + text = stringResource(id = R.string.main_page_balance), + style = TangemTheme.typography.subtitle2, + color = TangemTheme.colors.text.tertiary, + ) + }, + amount = { + when (state) { + is TotalBalanceCardState.Empty, + is TotalBalanceCardState.Loading, + -> LoadingAmount() + is TotalBalanceCardState.Failure, + is TotalBalanceCardState.Success, + -> LoadedAmount( + amount = buildAmountString( + amount = state.amount, + fiatCurrencySymbol = state.fiatCurrency.symbol, + ), + ) + } + }, + currencySelector = { + if (state !is TotalBalanceCardState.Empty) { + SelectorButton( + text = state.fiatCurrency.code, + onClick = state.onChangeFiatCurrencyClick, + ) + } + }, + failureText = { + AnimatedVisibility(visible = state is TotalBalanceCardState.Failure) { + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.main_processing_full_amount), + style = TangemTheme.typography.caption, + color = TangemTheme.colors.text.attention, + ) + } + }, + ) +} + +@Composable +private fun TotalBalanceCardScaffold( + title: @Composable () -> Unit, + amount: @Composable () -> Unit, + currencySelector: @Composable () -> Unit, + failureText: @Composable () -> Unit, + modifier: Modifier = Modifier, + amountWeight: Float = 0.8f, +) { + Surface( + modifier = modifier, + shape = TangemTheme.shapes.roundedCornersMedium, + color = TangemTheme.colors.background.plain, + elevation = TangemTheme.dimens.elevation1, + ) { + Column( + modifier = Modifier.fillMaxWidth(), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.Top, + ) { + SpacerW16() + Column( + modifier = Modifier.weight(amountWeight), + ) { + SpacerH12() + title() + SpacerH4() + amount() + } + currencySelector() + SpacerW4() + } + SpacerH4() + Box( + modifier = Modifier.padding( + horizontal = TangemTheme.dimens.spacing16, + ), + ) { + failureText() + } + SpacerH12() + } + } +} + +@Composable +private fun LoadingAmount( + modifier: Modifier = Modifier, +) { + Box(modifier = modifier.shimmer()) { + Box( + modifier = Modifier + .width(TangemTheme.dimens.size116) + .height(TangemTheme.dimens.size32) + .background( + color = TangemTheme.colors.stroke.primary, + shape = TangemTheme.shapes.roundedCornersSmall2, + ), + ) + } +} + +@Composable +private fun LoadedAmount( + amount: AnnotatedString, + modifier: Modifier = Modifier, +) { + Box(modifier = modifier) { + Text( + text = amount, + style = TangemTheme.typography.h2, + color = TangemTheme.colors.text.primary1, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + ) + } +} + +@Composable +private fun buildAmountString( + amount: BigDecimal, + fiatCurrencySymbol: String, +): AnnotatedString { + val format = DecimalFormat.getInstance(Locale.getDefault()) as DecimalFormat + val scaledAmount = amount + .setScale(2, RoundingMode.HALF_UP) + .formatWithSpaces() + val integer = scaledAmount.substringBefore('.') + val reminder = scaledAmount.substringAfter('.') + + return buildAnnotatedString { + append(integer) + append(format.decimalFormatSymbols.decimalSeparator) + append( + AnnotatedString( + text = "$reminder $fiatCurrencySymbol", + spanStyle = TangemTheme.typography.h3.toSpanStyle(), + ), + ) + } +} + +private sealed interface TotalBalanceCardState { + val amount: BigDecimal + val onChangeFiatCurrencyClick: () -> Unit + val fiatCurrency: FiatCurrency + + object Empty : TotalBalanceCardState { + override val amount: BigDecimal = BigDecimal.ZERO + override val fiatCurrency: FiatCurrency = FiatCurrency.Default + override val onChangeFiatCurrencyClick: () -> Unit = { /* no-op */ } + } + + data class Loading( + override val fiatCurrency: FiatCurrency, + override val onChangeFiatCurrencyClick: () -> Unit, + ) : TotalBalanceCardState { + override val amount: BigDecimal = BigDecimal.ZERO + } + + data class Failure( + override val amount: BigDecimal, + override val fiatCurrency: FiatCurrency, + override val onChangeFiatCurrencyClick: () -> Unit, + ) : TotalBalanceCardState + + data class Success( + override val amount: BigDecimal, + override val fiatCurrency: FiatCurrency, + override val onChangeFiatCurrencyClick: () -> Unit, + ) : TotalBalanceCardState +} + +// region Preview +@Composable +private fun TotalBalanceCardContentSample( + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .background(TangemTheme.colors.background.primary) + .padding(all = TangemTheme.dimens.spacing16), + ) { + TotalBalanceCardContent(state = TotalBalanceCardState.Empty) + Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) + TotalBalanceCardContent( + state = TotalBalanceCardState.Loading(FiatCurrency("USD", "USD", "$")) {}, + ) + Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) + TotalBalanceCardContent( + state = TotalBalanceCardState.Failure( + amount = BigDecimal("9917.72"), + onChangeFiatCurrencyClick = {}, + fiatCurrency = FiatCurrency("USD", "USD", "$"), + ), + ) + Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) + TotalBalanceCardContent( + state = TotalBalanceCardState.Success( + amount = BigDecimal("9917.72"), + onChangeFiatCurrencyClick = {}, + fiatCurrency = FiatCurrency("USD", "USD", "$"), + ), + ) + } +} + +@Preview(showBackground = true, widthDp = 360) +@Composable +private fun TotalBalanceCardContentPreview_Light() { + TangemTheme { + TotalBalanceCardContentSample() + } +} + +@Preview(showBackground = true, widthDp = 360) +@Composable +private fun TotalBalanceCardContentPreview_Dark() { + TangemTheme(isDark = true) { + TotalBalanceCardContentSample() + } +} +// endregion Preview \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index 2e9f1b426f..c77e2446d8 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -3,7 +3,6 @@ package com.tangem.tap.features.wallet.ui.wallet import android.widget.Button import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager -import com.badoo.mvicore.DiffStrategy import com.badoo.mvicore.modelWatcher import com.tangem.core.analytics.Analytics import com.tangem.domain.common.TapWorkarounds.derivationStyle @@ -11,8 +10,6 @@ import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.analytics.events.Portfolio -import com.tangem.tap.common.extensions.animateVisibility -import com.tangem.tap.common.extensions.formatAmountAsSpannedString import com.tangem.tap.common.extensions.getQuantityString import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.show @@ -21,7 +18,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.tokens.CurrenciesRepository import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.features.wallet.models.TotalBalance -import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.ui.BalanceStatus @@ -36,14 +32,7 @@ class MultiWalletView : WalletView() { private lateinit var walletsAdapter: WalletAdapter - private val watcher = modelWatcher { - val totalBalanceStrategy: DiffStrategy = { old, new -> - old.cardId != new.cardId || - old.totalBalance != new.totalBalance || - old.state != new.state || - old.walletsStores.size != new.walletsStores.size - } - + private val watcher = modelWatcher { // !!! Workaround !!! // Checking state properties instead of state params can reduce application performance, // but here it is necessary because the WalletStore has an unsuitable equals method @@ -68,13 +57,11 @@ class MultiWalletView : WalletView() { handleBackupWarning(it, showBackupWarnings) } } - watch({ it }, totalBalanceStrategy) { walletState -> + WalletState::totalBalance { totalBalance -> binding?.let { handleTotalBalance( binding = it, - totalBalance = walletState.totalBalance, - progressState = walletState.state, - walletsCount = walletState.walletsDataFromStores.size, + totalBalance = totalBalance, ) } } @@ -95,7 +82,7 @@ class MultiWalletView : WalletView() { lAddress.root.hide() rowButtons.hide() lSingleWalletBalance.root.hide() - lCardTotalBalance.root.show() + lCardTotalBalance.show() rvMultiwallet.show() btnAddToken.show() } @@ -180,40 +167,11 @@ class MultiWalletView : WalletView() { private fun handleTotalBalance( binding: FragmentWalletBinding, totalBalance: TotalBalance?, - progressState: ProgressState, - walletsCount: Int, ) = with(binding.lCardTotalBalance) { - if (walletsCount == 0) { - root.isVisible = false - } else { - if (totalBalance == null) { - if (progressState != ProgressState.Loading) { - root.isVisible = false - } - } else { - root.isVisible = true - // Skip changes when on refreshing state - if (totalBalance.state == ProgressState.Refreshing || progressState == ProgressState.Refreshing) { - return@with - } - - if (totalBalance.state == ProgressState.Loading) { - veilBalance.veil() - } else { - veilBalance.unVeil() - } - tvProcessing.animateVisibility(show = totalBalance.state == ProgressState.Error) - - tvBalance.text = totalBalance.fiatAmount.formatAmountAsSpannedString( - currencySymbol = totalBalance.fiatCurrency.symbol, - ) - tvCurrencyName.text = totalBalance.fiatCurrency.code - - tvCurrencyName.setOnClickListener { - store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) - } - } + onChangeFiatCurrencyClick = { + store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) } + status = totalBalance } private fun handleErrorStates( diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt index 61c7b614b6..aa2ce84691 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt @@ -41,7 +41,7 @@ class SingleWalletView : WalletView() { btnAddToken.hide() rvPendingTransaction.hide() pbLoadingUserTokens.hide() - lCardTotalBalance.root.hide() + lCardTotalBalance.hide() lSingleWalletBalance.root.hide() lWalletRescanWarning.root.hide() lWalletBackupWarning.root.hide() diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index cc67090da2..f2324b80c3 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -47,6 +47,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:clipToPadding="false" + android:clipChildren="false" android:paddingBottom="92dp"> - - - - - - - - - - - - - - - - - - diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt index 7a262835b6..c720130f16 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt @@ -1,13 +1,12 @@ package com.tangem.core.ui.components 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.IntrinsicSize import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -31,11 +30,14 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import com.tangem.core.ui.R import com.tangem.core.ui.res.TangemTheme +// region TextButton /** * [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?node-id=97%3A103&t=TmfD6UBHPg9uYfev-4) * */ @@ -99,7 +101,9 @@ fun WarningTextButton( size = TangemButtonSize.Text, ) } +// endregion TextButton +// region PrimaryButton @Composable fun PrimaryButton( text: String, @@ -164,7 +168,9 @@ fun PrimaryButtonIconLeft( showProgress = showProgress, ) } +// endregion PrimaryButton +// region SecondaryButton @Composable fun SecondaryButton( text: String, @@ -229,6 +235,29 @@ fun SecondaryButtonIconLeft( showProgress = showProgress, ) } +// endregion SecondaryButton + +// region Other +@Composable +fun SelectorButton( + text: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, +) { + TangemButton( + modifier = modifier, + text = text, + textStyle = TangemTheme.typography.subtitle2, + icon = TangemButtonIcon.Right(painterResource(id = R.drawable.ic_chevron_24)), + onClick = onClick, + colors = TangemButtonsDefaults.selectorButtonColors, + showProgress = false, + enabled = enabled, + size = TangemButtonSize.Selector, + ) +} +// endregion Other // region Defaults @Suppress("LongParameterList") @@ -243,12 +272,12 @@ private fun TangemButton( modifier: Modifier = Modifier, size: TangemButtonSize = TangemButtonSize.Default, elevation: ButtonElevation = TangemButtonsDefaults.elevation, + textStyle: TextStyle = TangemTheme.typography.button, ) { Button( modifier = modifier .width(IntrinsicSize.Min) - .height(IntrinsicSize.Min) - .heightIn(size.toHeightDp()), + .heightIn(min = size.toHeightDp()), onClick = { if (!showProgress) { onClick() @@ -261,19 +290,24 @@ private fun TangemButton( ) { ButtonContent( text = text, + textStyle = textStyle, buttonIcon = icon, colors = colors, showProgress = showProgress, enabled = enabled, + size = size, ) } } +@Suppress("LongParameterList") @Composable private fun ButtonContent( text: String, + textStyle: TextStyle, buttonIcon: TangemButtonIcon, colors: ButtonColors, + size: TangemButtonSize, enabled: Boolean, showProgress: Boolean, ) { @@ -297,18 +331,19 @@ private fun ButtonContent( ) } } else { - Row { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(size.toIconPadding()), + ) { if (buttonIcon is TangemButtonIcon.Left) { icon(buttonIcon.painter) - Spacer(modifier = Modifier.width(TangemTheme.dimens.size8)) } Text( text = text, - style = TangemTheme.typography.button, + style = textStyle, color = colors.contentColor(enabled = enabled).value, ) if (buttonIcon is TangemButtonIcon.Right) { - Spacer(modifier = Modifier.width(TangemTheme.dimens.size8)) icon(buttonIcon.painter) } } @@ -332,18 +367,28 @@ sealed interface TangemButtonIcon { enum class TangemButtonSize { Default, Text, + Selector, } @Composable private fun TangemButtonSize.toHeightDp(): Dp = when (this) { TangemButtonSize.Default -> TangemTheme.dimens.size48 TangemButtonSize.Text -> TangemTheme.dimens.size40 + TangemButtonSize.Selector -> TangemTheme.dimens.size24 } @Composable private fun TangemButtonSize.toShape(): Shape = when (this) { TangemButtonSize.Default -> TangemTheme.shapes.roundedCornersMedium TangemButtonSize.Text -> TangemTheme.shapes.roundedCornersSmall + TangemButtonSize.Selector -> TangemTheme.shapes.roundedCornersSmall +} + +@Composable +private fun TangemButtonSize.toIconPadding(): Dp = when (this) { + TangemButtonSize.Default -> TangemTheme.dimens.spacing8 + TangemButtonSize.Text -> TangemTheme.dimens.spacing8 + TangemButtonSize.Selector -> 0.dp } object TangemButtonsDefaults { @@ -385,6 +430,14 @@ object TangemButtonsDefaults { disabledBackgroundColor = Color.Transparent, disabledContentColor = TangemTheme.colors.text.disabled, ) + + val selectorButtonColors: ButtonColors + @Composable get() = TangemButtonColors( + backgroundColor = Color.Transparent, + contentColor = TangemTheme.colors.text.tertiary, + disabledBackgroundColor = Color.Transparent, + disabledContentColor = TangemTheme.colors.text.disabled, + ) } @Immutable @@ -595,6 +648,11 @@ private fun TextButtonSample( text = "Delete", onClick = { /* no-op */ }, ) + Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) + SelectorButton( + text = "USD", + onClick = { /* no-op */ }, + ) } } From 2b5fcdf0f978e133c0b2635c68f3023e164b9e7b Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 21 Feb 2023 15:20:36 +0300 Subject: [PATCH 07/29] Updated on 2026-08-14 --- .../com/tangem/feature/swap/presentation/SwapFragment.kt | 2 -- .../src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt | 2 ++ .../java/com/tangem/feature/swap/ui/SwapScreenContent.kt | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt index 2f4911d75a..fbece11798 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt @@ -7,7 +7,6 @@ import android.view.ViewGroup import androidx.compose.animation.Crossfade import androidx.compose.runtime.Composable import androidx.compose.ui.platform.ComposeView -import androidx.core.view.WindowCompat import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import com.tangem.feature.swap.router.CustomTabsManager @@ -26,7 +25,6 @@ class SwapFragment : Fragment() { private val viewModel by viewModels() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) } viewModel.setRouter( SwapRouter( fragmentManager = WeakReference(parentFragmentManager), diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt index 2d83679867..9c43985c64 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt @@ -3,6 +3,7 @@ package com.tangem.feature.swap.ui import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ModalBottomSheetLayout @@ -39,6 +40,7 @@ internal fun SwapScreen(stateHolder: SwapStateHolder) { TangemTheme { ModalBottomSheetLayout( + modifier = Modifier.systemBarsPadding(), sheetContent = { if (stateHolder.permissionState is SwapPermissionState.ReadyForRequest) { SwapPermissionBottomSheetContent( diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt index 6a14863ede..d48b0d3e5a 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState @@ -120,7 +121,9 @@ internal fun SwapScreenContent(state: SwapStateHolder, onPermissionWarningClick: AnimatedVisibility( visible = keyboard is Keyboard.Opened, - modifier = Modifier.align(Alignment.BottomCenter), + modifier = Modifier + .imePadding() + .align(Alignment.BottomCenter), ) { Text( text = stringResource(id = R.string.send_max_amount_label), From db93629493d54d00e37913a74f567bdbaa57da2d Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Feb 2023 21:04:44 +0300 Subject: [PATCH 08/29] Updated on 2026-08-14 --- .../tap/domain/model/TotalFiatBalance.kt | 14 +++-- .../tap/domain/model/WalletDataModel.kt | 6 +- .../model/builders/WalletStoreBuilder.kt | 59 ++++++++++++------- .../DefaultTotalFiatBalanceCalculator.kt | 20 ++++--- .../DefaultWalletCurrenciesManager.kt | 2 +- .../DefaultWalletStoresManager.kt | 4 +- .../features/wallet/models/TotalBalance.kt | 2 +- .../wallet/ui/view/TotalBalanceCard.kt | 13 ++-- .../tap/features/walletSelector/ui/Mapper.kt | 13 ++-- 9 files changed, 79 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt b/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt index dd9a0b27a1..9fa5b24fd8 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt @@ -6,16 +6,18 @@ import java.math.BigDecimal * Represents fiat balance of [WalletStoreModel] list * @property amount Amount of the total balance * */ -sealed class TotalFiatBalance { - open val amount: BigDecimal = BigDecimal.ZERO +sealed interface TotalFiatBalance { + val amount: BigDecimal? - object Loading : TotalFiatBalance() + object Loading : TotalFiatBalance { + override val amount: BigDecimal? = null + } data class Error( - override val amount: BigDecimal, - ) : TotalFiatBalance() + override val amount: BigDecimal?, + ) : TotalFiatBalance data class Loaded( override val amount: BigDecimal, - ) : TotalFiatBalance() + ) : TotalFiatBalance } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt b/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt index b9e83390a0..5f2e67153b 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt @@ -16,6 +16,7 @@ import java.math.BigDecimal * founds will be destroyed. Null if currency don't have existential deposit * @param fiatRate Wallet's fiat rate, used to calculate fiat balance. Null if not provided * @param isCardSingleToken shows that [Currency] is a card token + * @param isCustom shows that currency is a custom * */ data class WalletDataModel( val currency: Currency, @@ -24,6 +25,7 @@ data class WalletDataModel( val existentialDeposit: BigDecimal?, val fiatRate: BigDecimal?, val isCardSingleToken: Boolean, + val isCustom: Boolean, val historyTransactions: List?, ) { @@ -59,9 +61,7 @@ data class WalletDataModel( data class NoAccount( val amountToCreateAccount: BigDecimal?, - ) : Status() { - override val isErrorStatus: Boolean = true - } + ) : Status() data class Unreachable( override val errorMessage: String?, diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index aef5c1ea76..f5d0d3b6fd 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -2,12 +2,14 @@ package com.tangem.tap.domain.model.builders import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.DerivationStyle import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.WalletManager import com.tangem.common.hdWallet.DerivationPath -import com.tangem.domain.common.util.UserWalletId +import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.tap.common.extensions.getBlockchainTxHistory import com.tangem.tap.common.extensions.getTokenTxHistory +import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.tokens.models.BlockchainNetwork @@ -26,23 +28,23 @@ interface WalletStoreBuilder { companion object { operator fun invoke( - userWalletId: UserWalletId, + userWallet: UserWallet, blockchainNetwork: BlockchainNetwork, ): BlockchainNetworkWalletStoreBuilder { - return BlockchainNetworkWalletStoreBuilderImpl(userWalletId, blockchainNetwork) + return BlockchainNetworkWalletStoreBuilderImpl(userWallet, blockchainNetwork) } operator fun invoke( - userWalletId: UserWalletId, + userWallet: UserWallet, walletManager: WalletManager, ): WalletMangerWalletStoreBuilder { - return WalletMangerWalletStoreBuilderImpl(userWalletId, walletManager) + return WalletMangerWalletStoreBuilderImpl(userWallet, walletManager) } } } private class BlockchainNetworkWalletStoreBuilderImpl( - private val userWalletId: UserWalletId, + private val userWallet: UserWallet, private val blockchainNetwork: BlockchainNetwork, ) : WalletStoreBuilder.BlockchainNetworkWalletStoreBuilder { private var walletManager: WalletManager? = null @@ -52,11 +54,12 @@ private class BlockchainNetworkWalletStoreBuilderImpl( } override fun build(): WalletStoreModel { - val blockchainWalletData = blockchainNetwork.getBlockchainWalletData(walletManager) - val tokensWalletsData = blockchainNetwork.getTokensWalletsData(walletManager) + val cardDerivationStyle = userWallet.scanResponse.card.derivationStyle + val blockchainWalletData = blockchainNetwork.getBlockchainWalletData(walletManager, cardDerivationStyle) + val tokensWalletsData = blockchainNetwork.getTokensWalletsData(walletManager, cardDerivationStyle) return WalletStoreModel( - userWalletId = userWalletId, + userWalletId = userWallet.walletId, blockchain = blockchainNetwork.blockchain, derivationPath = blockchainNetwork.derivationPath?.let { DerivationPath(it) }, walletsData = listOf(blockchainWalletData) + tokensWalletsData, @@ -68,7 +71,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl( } private class WalletMangerWalletStoreBuilderImpl( - private val userWalletId: UserWalletId, + private val userWallet: UserWallet, private val walletManager: WalletManager, ) : WalletStoreBuilder.WalletMangerWalletStoreBuilder { @@ -78,7 +81,7 @@ private class WalletMangerWalletStoreBuilderImpl( val tokenWalletsData = wallet.getTokens().firstOrNull()?.toTokenWalletData(walletManager) return WalletStoreModel( - userWalletId = userWalletId, + userWalletId = userWallet.walletId, blockchain = wallet.blockchain, derivationPath = wallet.publicKey.derivationPath, walletsData = listOf(blockchainWalletData) + listOfNotNull(tokenWalletsData), @@ -89,35 +92,45 @@ private class WalletMangerWalletStoreBuilderImpl( } } -private fun BlockchainNetwork.getBlockchainWalletData(walletManager: WalletManager?): WalletDataModel { +private fun BlockchainNetwork.getBlockchainWalletData( + walletManager: WalletManager?, + cardDerivationStyle: DerivationStyle?, +): WalletDataModel { + val currency = Currency.Blockchain( + blockchain = blockchain, + derivationPath = derivationPath, + ) return WalletDataModel( - currency = Currency.Blockchain( - blockchain = blockchain, - derivationPath = derivationPath, - ), + currency = currency, status = WalletDataModel.Loading, walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = false, + isCustom = currency.isCustomCurrency(cardDerivationStyle), historyTransactions = walletManager?.getBlockchainTxHistory(), ) } -private fun BlockchainNetwork.getTokensWalletsData(walletManager: WalletManager?): List { +private fun BlockchainNetwork.getTokensWalletsData( + walletManager: WalletManager?, + cardDerivationStyle: DerivationStyle?, +): List { return this.tokens .map { token -> + val currency = Currency.Token( + token = token, + blockchain = blockchain, + derivationPath = derivationPath, + ) WalletDataModel( - currency = Currency.Token( - token = token, - blockchain = blockchain, - derivationPath = derivationPath, - ), + currency = currency, status = WalletDataModel.Loading, walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = walletManager?.cardTokens?.contains(token) ?: false, + isCustom = currency.isCustomCurrency(cardDerivationStyle), historyTransactions = walletManager?.getTokenTxHistory(token), ) } @@ -135,6 +148,7 @@ private fun Blockchain.toBlockchainWalletData(walletManager: WalletManager): Wal existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = false, + isCustom = false, historyTransactions = walletManager.getBlockchainTxHistory(), ) } @@ -152,6 +166,7 @@ private fun Token.toTokenWalletData(walletManager: WalletManager): WalletDataMod existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = walletManager.cardTokens.contains(this), + isCustom = false, historyTransactions = walletManager.getTokenTxHistory(this), ) } diff --git a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt index b0224afdac..9136094e8b 100644 --- a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt +++ b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt @@ -27,7 +27,9 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { when (walletsData.findStatus()) { TotalFiatBalanceStatus.Loading -> TotalFiatBalance.Loading TotalFiatBalanceStatus.Error -> TotalFiatBalance.Error(calculateAmount()) - TotalFiatBalanceStatus.Loaded -> TotalFiatBalance.Loaded(calculateAmount()) + TotalFiatBalanceStatus.Loaded -> TotalFiatBalance.Loaded( + amount = calculateAmount() ?: BigDecimal.ZERO, + ) } } } @@ -47,7 +49,8 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { is WalletDataModel.VerifiedOnline, is WalletDataModel.SameCurrencyTransactionInProgress, is WalletDataModel.TransactionInProgress, - is WalletDataModel.NoAccount -> if (walletData.fiatRate == null) { + is WalletDataModel.NoAccount, + -> if (walletData.isCustom || walletData.fiatRate == null) { TotalFiatBalanceStatus.Error } else { TotalFiatBalanceStatus.Loaded @@ -60,14 +63,17 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { } } - private fun Sequence.calculateTotalFiatAmount(): BigDecimal { + private fun Sequence.calculateTotalFiatAmount(): BigDecimal? { return this + .filterNot { it.isCustom } .map { walletData -> walletData.fiatRate + ?.takeUnless { walletData.status.isErrorStatus } ?.let { walletData.status.amount.toFiatValue(it) } - ?: BigDecimal.ZERO } - .reduce(BigDecimal::plus) + .reduce { acc, value -> + value?.let { acc?.plus(it) } + } } private fun getCurrentStatus( @@ -88,8 +94,6 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { } private enum class TotalFiatBalanceStatus { - Loading, - Error, - Loaded, + Loading, Error, Loaded, } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt index aff78739f8..2c74eba8ba 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt @@ -175,7 +175,7 @@ internal class DefaultWalletCurrenciesManager( .flatMap { walletManager -> walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder(userWalletId, blockchainNetwork) + walletStore = WalletStoreBuilder(userWallet, blockchainNetwork) .walletManager(walletManager) .build(), ) diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt index 58ee4e72e0..06b2f358ae 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt @@ -137,7 +137,7 @@ internal class DefaultWalletStoresManager( { walletManager -> walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder(userWalletId, blockchainNetwork) + walletStore = WalletStoreBuilder(userWallet, blockchainNetwork) .walletManager(walletManager) .build(), ) @@ -171,7 +171,7 @@ internal class DefaultWalletStoresManager( val userWalletId = userWallet.walletId walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder(userWalletId, walletManager) + walletStore = WalletStoreBuilder(userWallet, walletManager) .build(), ) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt index 5d63e8b816..a57bf4e6da 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt @@ -6,6 +6,6 @@ import java.math.BigDecimal data class TotalBalance( val state: ProgressState, - val fiatAmount: BigDecimal, + val fiatAmount: BigDecimal?, val fiatCurrency: FiatCurrency, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt index 5a39cf2b28..f17f324571 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt @@ -37,6 +37,7 @@ import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.formatWithSpaces import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN import com.tangem.wallet.R import com.valentinilk.shimmer.shimmer import java.math.BigDecimal @@ -91,7 +92,7 @@ internal class TotalBalanceCard @JvmOverloads constructor( ProgressState.Refreshing, ProgressState.Done, -> TotalBalanceCardState.Success( - amount = status.fiatAmount, + amount = status.fiatAmount ?: BigDecimal.ZERO, fiatCurrency = status.fiatCurrency, onChangeFiatCurrencyClick = onChangeCurrencyClick, ) @@ -232,9 +233,11 @@ private fun LoadedAmount( @Composable private fun buildAmountString( - amount: BigDecimal, + amount: BigDecimal?, fiatCurrencySymbol: String, ): AnnotatedString { + if (amount == null) return AnnotatedString(text = UNKNOWN_AMOUNT_SIGN) + val format = DecimalFormat.getInstance(Locale.getDefault()) as DecimalFormat val scaledAmount = amount .setScale(2, RoundingMode.HALF_UP) @@ -255,12 +258,12 @@ private fun buildAmountString( } private sealed interface TotalBalanceCardState { - val amount: BigDecimal + val amount: BigDecimal? val onChangeFiatCurrencyClick: () -> Unit val fiatCurrency: FiatCurrency object Empty : TotalBalanceCardState { - override val amount: BigDecimal = BigDecimal.ZERO + override val amount: BigDecimal? = null override val fiatCurrency: FiatCurrency = FiatCurrency.Default override val onChangeFiatCurrencyClick: () -> Unit = { /* no-op */ } } @@ -273,7 +276,7 @@ private sealed interface TotalBalanceCardState { } data class Failure( - override val amount: BigDecimal, + override val amount: BigDecimal?, override val fiatCurrency: FiatCurrency, override val onChangeFiatCurrencyClick: () -> Unit, ) : TotalBalanceCardState diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt index 626857097f..d22d12d85c 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt @@ -3,23 +3,24 @@ package com.tangem.tap.features.walletSelector.ui import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.toFormattedFiatValue import com.tangem.tap.domain.model.TotalFiatBalance +import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN import com.tangem.tap.features.walletSelector.redux.UserWalletModel import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem -import java.math.BigDecimal internal fun List.toUiModels( appCurrency: FiatCurrency, ): Sequence { return this.asSequence().map { userWalletModel -> with(userWalletModel) { - val formatAmount = { amount: BigDecimal -> - amount.toFormattedFiatValue(appCurrency.symbol) - } val balance = when (fiatBalance) { - is TotalFiatBalance.Error -> UserWalletItem.Balance.Error(formatAmount(fiatBalance.amount)) - is TotalFiatBalance.Loaded -> UserWalletItem.Balance.Loaded(formatAmount(fiatBalance.amount)) + is TotalFiatBalance.Error -> UserWalletItem.Balance.Error( + amount = fiatBalance.amount?.toFormattedFiatValue(appCurrency.symbol) ?: UNKNOWN_AMOUNT_SIGN, + ) + is TotalFiatBalance.Loaded -> UserWalletItem.Balance.Loaded( + amount = fiatBalance.amount.toFormattedFiatValue(appCurrency.symbol), + ) is TotalFiatBalance.Loading -> UserWalletItem.Balance.Loading } when (type) { From 7b01e6638316293025ec61327822d2d85edfc1ef Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 21 Feb 2023 16:37:03 +0300 Subject: [PATCH 09/29] Updated on 2026-08-14 --- .../com/tangem/tap/domain/tasks/product/ScanProductTask.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 6cbd5923e6..524924875a 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -186,6 +186,11 @@ private class ScanWalletProcessor( session: CardSession, callback: (result: CompletionResult) -> Unit, ) { + if (card.wallets.isNotEmpty() && card.backupStatus?.isActive == true) { + startLinkingForBackupIfNeeded(card, session, callback) + return + } + if (card.wallets.isEmpty() || !card.isFirmwareMultiwalletAllowed) { startLinkingForBackupIfNeeded(card, session, callback) return From 300dc35bdb25a93f6e7f6766aacbc740e7ae24aa Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 21 Feb 2023 22:06:36 +0800 Subject: [PATCH 10/29] Updated on 2026-08-14 --- .../twins/redux/TwinCardsMiddleware.kt | 2 +- .../middlewares/MultiWalletMiddleware.kt | 53 +++++++++---------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index de2c204c65..1e1d7fac47 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -74,7 +74,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { fun updateScanResponse(response: ScanResponse) { when (twinCardsState.mode) { CreateTwinWalletMode.CreateWallet -> onboardingManager?.scanResponse = response - CreateTwinWalletMode.RecreateWallet -> store.dispatch(GlobalAction.SaveScanResponse(response)) + CreateTwinWalletMode.RecreateWallet -> store.dispatchOnMain(GlobalAction.SaveScanResponse(response)) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index b3743b0360..557e187c0a 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -6,7 +6,6 @@ import com.tangem.blockchain.common.WalletManager import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics -import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken import com.tangem.tap.common.extensions.addContext @@ -38,7 +37,6 @@ import com.tangem.tap.userWalletsListManager import com.tangem.tap.walletCurrenciesManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import java.math.BigDecimal class MultiWalletMiddleware { @@ -251,10 +249,16 @@ class MultiWalletMiddleware { scope.launch { userTokensRepository.saveUserTokens(scanResponse.card, currencies) } } } ?: wmFactory.makeWalletManagerForApp(scanResponse, blockchainNetwork)?.also { - store.dispatch(WalletAction.MultiWallet.AddBlockchain(blockchainNetwork.updateTokens(tokens), it, save)) + store.dispatchOnMain( + WalletAction.MultiWallet.AddBlockchain( + blockchain = blockchainNetwork.updateTokens(tokens), + walletManager = it, + save = save, + ), + ) } - store.dispatch( + store.dispatchOnMain( WalletAction.LoadFiatRate( coinsList = tokens.map { token -> Currency.Token( @@ -268,30 +272,25 @@ class MultiWalletMiddleware { if (tokens.isNotEmpty()) walletManager?.addTokens(tokens) scope.launch { - val result = walletManager?.safeUpdate() - withMainContext { - when (result) { - is com.tangem.common.services.Result.Success -> { - val wallet = result.data - wallet.getTokens() - .filter { tokens.contains(it) } - .mapNotNull { token -> - wallet.getTokenAmount(token)?.let { Pair(token, it) } - } - .forEach { - withContext(Dispatchers.Main) { - store.dispatch( - WalletAction.MultiWallet.TokenLoaded( - it.second, - it.first, - blockchainNetwork, - ), - ) - } - } - } - else -> {} + when (val result = walletManager?.safeUpdate()) { + is com.tangem.common.services.Result.Success -> { + val wallet = result.data + wallet.getTokens() + .filter { tokens.contains(it) } + .mapNotNull { token -> + wallet.getTokenAmount(token)?.let { amount -> Pair(token, amount) } + } + .forEach { (token, tokenAmount) -> + store.dispatchOnMain( + WalletAction.MultiWallet.TokenLoaded( + amount = tokenAmount, + token = token, + blockchain = blockchainNetwork, + ), + ) + } } + else -> Unit } } } From 85c11a5b80805426a9aabdabe250c59ec8f6e799 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 21 Feb 2023 18:15:57 +0300 Subject: [PATCH 11/29] Updated on 2026-08-14 --- .../BiometricUserWalletsListManager.kt | 19 ++++++++++++------- .../twins/redux/TwinCardsMiddleware.kt | 15 ++++++++++++++- .../products/twins/ui/TwinsCardsFragment.kt | 2 +- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt index 748665ccea..5c5be22e1f 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/implementation/BiometricUserWalletsListManager.kt @@ -110,21 +110,26 @@ internal class BiometricUserWalletsListManager( } override suspend fun delete(userWalletIds: List): CompletionResult { - if (userWalletIds.isEmpty()) { + val idsToRemove = state.value.userWallets + .takeIf { it.isNotEmpty() } + ?.filter { it.walletId in userWalletIds } + ?.map { it.walletId } + + if (idsToRemove.isNullOrEmpty()) { return CompletionResult.Success(Unit) } - changeSelectedUserWalletIdIfNeeded(userWalletIds) + changeSelectedUserWalletIdIfNeeded(idsToRemove) - return sensitiveInformationRepository.delete(userWalletIds) - .flatMap { publicInformationRepository.delete(userWalletIds) } - .flatMap { keysRepository.delete(userWalletIds) } + return sensitiveInformationRepository.delete(idsToRemove) + .flatMap { publicInformationRepository.delete(idsToRemove) } + .flatMap { keysRepository.delete(idsToRemove) } .map { state.update { prevState -> - val newUserWallets = prevState.userWallets.filter { it.walletId !in userWalletIds } + val newUserWallets = prevState.userWallets.filter { it.walletId !in idsToRemove } prevState.copy( - encryptionKeys = prevState.encryptionKeys.filter { it.walletId !in userWalletIds }, + encryptionKeys = prevState.encryptionKeys.filter { it.walletId !in idsToRemove }, userWallets = newUserWallets, isLocked = newUserWallets.any { it.isLocked }, ) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 1e1d7fac47..1f77d2ae6f 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -322,8 +322,9 @@ private fun handle(action: Action, dispatch: DispatchFunction) { OnboardingHelper.onInterrupted() store.dispatch(TwinCardsAction.CardsManager.Release) + action.shouldResetTwinCardsWidget(shouldReturnCardBack) { - store.dispatch(NavigationAction.PopBackTo(AppScreen.Home)) + store.dispatchOnMain(NavigationAction.PopBackTo(getPopBackScreen())) } } store.dispatchDialogShow(OnboardingDialog.InterruptOnboarding(onOkCallback)) @@ -331,4 +332,16 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } else -> Unit } +} + +private fun getPopBackScreen(): AppScreen { + return if (userWalletsListManager.hasSavedUserWallets) { + if (userWalletsListManager.isLockedSync) { + AppScreen.Welcome + } else { + AppScreen.Wallet + } + } else { + AppScreen.Home + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt index dbc7e3672d..f471878c85 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt @@ -15,10 +15,10 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.VoidCallback import com.tangem.core.analytics.Analytics import com.tangem.core.ui.fragments.setStatusBarColor +import com.tangem.datasource.utils.AndroidAssetReader import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TwinCardNumber import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget -import com.tangem.datasource.utils.AndroidAssetReader import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.beginDelayedTransition import com.tangem.tap.common.extensions.getDrawableCompat From 9395c2086806c8c2b273fef180a33312750feb55 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 21 Feb 2023 18:56:32 +0300 Subject: [PATCH 12/29] Updated on 2026-08-14 --- app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt | 2 +- .../com/tangem/tap/features/tokens/redux/TokensMiddleware.kt | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 288d399817..8b33c12085 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -111,7 +111,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co } suspend fun derivePublicKeys( - cardId: String, + cardId: String?, derivations: Map>, ): CompletionResult { return runTaskAsyncReturnOnMain(DeriveMultipleWalletPublicKeysTask(derivations), cardId) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index 606ee227cc..27aa168f02 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -207,9 +207,8 @@ class TokensMiddleware { } scope.launch { - val card = scanResponse.card val result = tangemSdkManager.derivePublicKeys( - cardId = card.cardId, + cardId = null, derivations = derivations, ) when (result) { @@ -232,7 +231,6 @@ class TokensMiddleware { onSuccess(updatedScanResponse) } - is CompletionResult.Failure -> { store.dispatchDebugErrorNotification(TapError.CustomError("Error adding tokens")) } From 0dffb81f892f18f1a07c147bbe019872f214d31d Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 21 Feb 2023 19:12:36 +0300 Subject: [PATCH 13/29] Updated on 2026-08-14 --- .../wallet/ui/wallet/MultiWalletView.kt | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index c77e2446d8..d1eab75515 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -1,8 +1,10 @@ package com.tangem.tap.features.wallet.ui.wallet import android.widget.Button +import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager +import com.badoo.mvicore.DiffStrategy import com.badoo.mvicore.modelWatcher import com.tangem.core.analytics.Analytics import com.tangem.domain.common.TapWorkarounds.derivationStyle @@ -18,6 +20,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.tokens.CurrenciesRepository import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.features.wallet.models.TotalBalance +import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.ui.BalanceStatus @@ -32,7 +35,14 @@ class MultiWalletView : WalletView() { private lateinit var walletsAdapter: WalletAdapter - private val watcher = modelWatcher { + private val watcher = modelWatcher { + val totalBalanceStrategy: DiffStrategy = { old, new -> + old.cardId != new.cardId || + old.totalBalance != new.totalBalance || + old.state != new.state || + old.walletsStores.size != new.walletsStores.size + } + // !!! Workaround !!! // Checking state properties instead of state params can reduce application performance, // but here it is necessary because the WalletStore has an unsuitable equals method @@ -57,11 +67,13 @@ class MultiWalletView : WalletView() { handleBackupWarning(it, showBackupWarnings) } } - WalletState::totalBalance { totalBalance -> + watch({ it }, totalBalanceStrategy) { walletState -> binding?.let { handleTotalBalance( binding = it, - totalBalance = totalBalance, + totalBalance = walletState.totalBalance, + progressState = walletState.state, + walletsCount = walletState.walletsDataFromStores.size, ) } } @@ -167,7 +179,11 @@ class MultiWalletView : WalletView() { private fun handleTotalBalance( binding: FragmentWalletBinding, totalBalance: TotalBalance?, + progressState: ProgressState, + walletsCount: Int, ) = with(binding.lCardTotalBalance) { + isGone = progressState == ProgressState.Done && walletsCount == 0 + onChangeFiatCurrencyClick = { store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) } From e2f71618a0328653d820baf1de53d9350aa0f745 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 09:14:59 +0800 Subject: [PATCH 14/29] Updated on 2026-08-14 --- .../tap/features/details/redux/DetailsReducer.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index cd51367536..5adbc797e0 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -2,9 +2,7 @@ package com.tangem.tap.features.details.redux import com.tangem.domain.common.CardDTO import com.tangem.domain.common.CardTypesResolver -import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.tap.common.redux.AppState -import com.tangem.tap.domain.extensions.isWalletDataSupported import com.tangem.tap.domain.extensions.signedHashesCount import com.tangem.tap.preferencesStorage import com.tangem.tap.store @@ -109,11 +107,9 @@ private fun prepareSecurityOptions(card: CardDTO, cardTypesResolver: CardTypesRe } private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypesResolver: CardTypesResolver): Boolean { - val notAllowedByAnyWallet = card.wallets.any { it.settings.isPermanent } - val notAllowedByCard = notAllowedByAnyWallet || - card.isWalletDataSupported && !cardTypesResolver.isTangemNote() && !card.settings.isBackupAllowed || - card.isSaltPay - return !notAllowedByCard + val hasPermanentWallet = card.wallets.any { it.settings.isPermanent } + val isNotAllowed = hasPermanentWallet || cardTypesResolver.isSaltPay() || cardTypesResolver.isStart2Coin() + return !isNotAllowed } private fun handleEraseWallet( From 211d6c801757226c82e81b5407829ea1680191e5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 12:38:11 +0300 Subject: [PATCH 15/29] Updated on 2026-08-14 --- .../com/tangem/tap/domain/TangemSdkManager.kt | 9 +++-- .../tap/domain/scanCard/ScanCardProcessor.kt | 3 -- .../domain/tasks/product/ScanProductTask.kt | 4 +- .../details/redux/DetailsMiddleware.kt | 5 ++- .../middlewares/MultiWalletMiddleware.kt | 37 ++++++++++--------- .../redux/reducers/MultiWalletReducer.kt | 10 +++-- 6 files changed, 37 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 8b33c12085..3b13e7243e 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -40,10 +40,9 @@ import com.tangem.tap.domain.tasks.product.ScanProductTask import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.isActive +import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Context) { @@ -68,6 +67,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co cardId: String? = null, additionalBlockchainsToDerive: Collection? = null, messageRes: Int? = null, + allowsRequestAccessCodeFromRepository: Boolean = false, ): CompletionResult { val message = Message(context.getString(messageRes ?: R.string.initial_message_scan_header)) return runTaskAsyncReturnOnMain( @@ -75,6 +75,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co card = null, userTokensRepository = userTokensRepository, additionalBlockchainsToDerive = additionalBlockchainsToDerive, + allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository, ), cardId = cardId, initialMessage = message, @@ -195,9 +196,9 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co accessCode: String? = null, ): CompletionResult = withContext(Dispatchers.Main) { - suspendCoroutine { continuation -> + suspendCancellableCoroutine { continuation -> tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode) { result -> - if (continuation.context.isActive) continuation.resume(result) + if (continuation.isActive) continuation.resume(result) } } } diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt index f7c823369f..56e9beaf22 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt @@ -1,6 +1,5 @@ package com.tangem.tap.domain.scanCard -import com.tangem.blockchain.common.Blockchain import com.tangem.common.core.TangemError import com.tangem.common.core.TangemSdkError import com.tangem.common.doOnFailure @@ -46,7 +45,6 @@ import kotlinx.coroutines.launch object ScanCardProcessor { suspend fun scan( analyticsEvent: AnalyticsEvent? = null, - additionalBlockchainsToDerive: Collection? = null, cardId: String? = null, onProgressStateChange: suspend (showProgress: Boolean) -> Unit = {}, onScanStateChange: suspend (scanInProgress: Boolean) -> Unit = {}, @@ -63,7 +61,6 @@ object ScanCardProcessor { val result = tangemSdkManager.scanProduct( userTokensRepository = userTokensRepository, cardId = cardId, - additionalBlockchainsToDerive = additionalBlockchainsToDerive, ) store.dispatchOnMain(GlobalAction.ScanFailsCounter.ChooseBehavior(result)) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 524924875a..8dde976a16 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -49,11 +49,9 @@ class ScanProductTask( val card: Card? = null, private val userTokensRepository: UserTokensRepository?, private val additionalBlockchainsToDerive: Collection? = null, + override val allowsRequestAccessCodeFromRepository: Boolean = false, ) : CardSessionRunnable { - override val allowsRequestAccessCodeFromRepository: Boolean - get() = !additionalBlockchainsToDerive.isNullOrEmpty() - override fun run( session: CardSession, callback: (result: CompletionResult) -> Unit, diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index f8626aa139..983be0f335 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -68,7 +68,10 @@ class DetailsMiddleware { } DetailsAction.ScanCard -> { scope.launch { - tangemSdkManager.scanProduct(userTokensRepository) + tangemSdkManager.scanProduct( + userTokensRepository = userTokensRepository, + allowsRequestAccessCodeFromRepository = true, + ) .doOnSuccess { scanResponse -> val currentUserWalletId = state.scanResponse ?.let { UserWalletIdBuilder.scanResponse(it).build() } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 557e187c0a..2749e3db13 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -5,6 +5,7 @@ import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.WalletManager import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard +import com.tangem.common.flatMap import com.tangem.core.analytics.Analytics import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken @@ -20,7 +21,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.TapError import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.model.UserWallet -import com.tangem.tap.domain.scanCard.ScanCardProcessor import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.demo.isDemoCard @@ -32,6 +32,7 @@ import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.features.wallet.redux.reducers.toWallet import com.tangem.tap.scope import com.tangem.tap.store +import com.tangem.tap.tangemSdkManager import com.tangem.tap.userTokensRepository import com.tangem.tap.userWalletsListManager import com.tangem.tap.walletCurrenciesManager @@ -193,24 +194,26 @@ class MultiWalletMiddleware { state: WalletState?, ) = scope.launch(Dispatchers.Default) { dispatchOnMain(WalletAction.MultiWallet.ScheduleCheckForMissingDerivation) - ScanCardProcessor.scan( - analyticsEvent = null, + tangemSdkManager.scanProduct( cardId = selectedUserWallet.cardId, + userTokensRepository = userTokensRepository, additionalBlockchainsToDerive = state?.missingDerivations?.map { it.blockchain }, - ) { scanResponse -> - userWalletsListManager.update( - userWalletId = selectedUserWallet.walletId, - update = { userWallet -> - userWallet.copy( - scanResponse = scanResponse, - ) - }, - ) - .doOnSuccess { updatedUserWallet -> - store.dispatchOnMain(WalletAction.MultiWallet.AddMissingDerivations(emptyList())) - store.state.globalState.tapWalletManager.loadData(updatedUserWallet, refresh = true) - } - } + allowsRequestAccessCodeFromRepository = true, + ) + .flatMap { scanResponse -> + userWalletsListManager.update( + userWalletId = selectedUserWallet.walletId, + update = { userWallet -> + userWallet.copy( + scanResponse = scanResponse, + ) + }, + ) + } + .doOnSuccess { updatedUserWallet -> + store.dispatchOnMain(WalletAction.MultiWallet.AddMissingDerivations(emptyList())) + store.state.globalState.tapWalletManager.loadData(updatedUserWallet, refresh = true) + } } private fun addDummyBalances(walletManagers: List) { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt index 7cb9f0b6a6..1acc7600fd 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/MultiWalletReducer.kt @@ -5,6 +5,7 @@ import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.WalletManager +import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchToastNotification import com.tangem.tap.common.extensions.getBlockchainTxHistory import com.tangem.tap.common.extensions.getTokenTxHistory @@ -113,14 +114,17 @@ class MultiWalletReducer { val currency = Currency.fromBlockchainNetwork(action.blockchain, action.token) val walletManager = state.getWalletManager(currency) if (walletManager == null) { - if (userWalletsListManager.hasSavedUserWallets) { - store.dispatch(NavigationAction.PopBackTo(screen = AppScreen.Welcome)) + val screen = if (userWalletsListManager.hasSavedUserWallets) { + AppScreen.Welcome } else { - store.dispatch(NavigationAction.PopBackTo(screen = AppScreen.Home)) + AppScreen.Home } + store.dispatchOnMain(NavigationAction.PopBackTo(screen)) + FirebaseCrashlytics.getInstance().recordException( IllegalStateException("MultiWallet.TokenLoaded: walletManager is null"), ) + store.dispatchToastNotification(R.string.internal_error_wallet_manager_not_found) return state } From bad5c0ed637236e0c7423d620de1fa71f3b5e0d1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 13:17:16 +0300 Subject: [PATCH 16/29] Updated on 2026-08-14 --- .../java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt | 5 ++++- .../java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt index 04ece1204a..c5f9ded2ff 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.CircleShape @@ -51,6 +52,9 @@ fun SwapSelectTokenScreen( ) { TangemTheme { Scaffold( + modifier = Modifier + .systemBarsPadding() + .background(color = TangemTheme.colors.background.secondary), content = { padding -> ListOfTokens(state = state, Modifier.padding(padding)) }, @@ -66,7 +70,6 @@ fun SwapSelectTokenScreen( icon = painterResource(id = getActiveIconRes(state.network.blockchainId)), ) }, - modifier = Modifier.background(color = TangemTheme.colors.background.secondary), ) } } diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt index a1c9b8c17f..d8ad3e646a 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt @@ -1,6 +1,7 @@ package com.tangem.feature.swap.ui import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.material.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -19,6 +20,7 @@ import com.tangem.feature.swap.presentation.R fun SwapSuccessScreen(state: SwapSuccessStateHolder, onBack: () -> Unit) { TangemTheme { Scaffold( + modifier = Modifier.systemBarsPadding(), content = { padding -> ResultScreenContent( resultMessage = makeSuccessMessage( From 7257feb12d226582ee557b83bcf7f818bc95ee3a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 13:38:56 +0300 Subject: [PATCH 17/29] Updated on 2026-08-14 --- .../java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt | 4 +++- .../java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 2307af3c90..e759fd412c 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -284,7 +284,9 @@ internal class SwapInteractorImpl @Inject constructor( TokenWithBalance( token = it, tokenBalanceData = TokenBalanceData( - amount = balance?.let { amount -> amountFormatter.formatSwapAmountToUI(amount, "") }, + amount = balance?.let { amount -> + amountFormatter.formatSwapAmountToUI(amount, it.symbol) + }, amountEquivalent = balance?.value?.toFiatString( rates[it.id]?.toBigDecimal() ?: BigDecimal.ZERO, appCurrency.symbol, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt index c5f9ded2ff..382986835c 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSelectTokenScreen.kt @@ -181,13 +181,13 @@ private fun TokenItem(token: TokenToSelect, network: Network, onTokenClick: () - modifier = Modifier.padding(start = TangemTheme.dimens.spacing8), ) { Text( - text = token.addedTokenBalanceData.amount ?: "", + text = token.addedTokenBalanceData.amountEquivalent.orEmpty(), style = TangemTheme.typography.subtitle1, color = TangemTheme.colors.text.primary1, ) SpacerW2() Text( - text = token.addedTokenBalanceData.amountEquivalent ?: "", + text = token.addedTokenBalanceData.amount.orEmpty(), style = TangemTheme.typography.caption, color = TangemTheme.colors.text.tertiary, ) From b9c1c9405641772877685b0b6c528ba9c4808c0e Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 17:47:19 +0300 Subject: [PATCH 18/29] Updated on 2026-08-14 --- .../tap/features/wallet/ui/WalletDetailsFragment.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 45b6f7140a..fcabcee21b 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -42,6 +42,7 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction +import com.tangem.tap.features.wallet.models.PendingTransactionType import com.tangem.tap.features.wallet.models.WalletWarning import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.ErrorType @@ -333,8 +334,11 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), } private fun showPendingTransactionsIfPresent(pendingTransactions: List) { - pendingTransactionAdapter.submitList(pendingTransactions) - binding.rvPendingTransaction.show(pendingTransactions.isNotEmpty()) + val knownTransactions = pendingTransactions.filterNot { + it.type == PendingTransactionType.Unknown + } + pendingTransactionAdapter.submitList(knownTransactions) + binding.rvPendingTransaction.show(knownTransactions.isNotEmpty()) } private fun setupAddressCard( From e7c625ef5bf837cb0e4ca2537541b595bd024b6a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 22:00:47 +0800 Subject: [PATCH 19/29] Updated on 2026-08-14 --- .../java/com/tangem/feature/swap/ui/SwapScreenContent.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt index d48b0d3e5a..1b52c30bb6 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt @@ -38,6 +38,7 @@ import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.components.PrimaryButtonIconRight import com.tangem.core.ui.components.RefreshableWaringCard import com.tangem.core.ui.components.SimpleOkDialog +import com.tangem.core.ui.components.SmallInfoCard import com.tangem.core.ui.components.SmallInfoCardWithDisclaimer import com.tangem.core.ui.components.SmallInfoCardWithWarning import com.tangem.core.ui.components.WarningCard @@ -280,7 +281,9 @@ private fun FeeItem(feeState: FeeState, currency: String) { ), ) } - is FeeState.Empty -> {} + is FeeState.Empty -> { + SmallInfoCard(startText = titleString, endText = "") + } } } From fc977e76637eb2c760d80227ebb66769b0fe2b54 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 19:18:58 +0800 Subject: [PATCH 20/29] Updated on 2026-08-14 --- .../ui/components/WalletItem.kt | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt index 6364b47f85..93df00409d 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt @@ -31,6 +31,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest @@ -38,6 +40,7 @@ import com.tangem.core.ui.components.SpacerH2 import com.tangem.core.ui.components.SpacerW6 import com.tangem.core.ui.components.SpacerW8 import com.tangem.core.ui.res.TangemTheme +import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.common.compose.TangemTypography import com.tangem.tap.common.extensions.cardImageData import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem @@ -137,23 +140,21 @@ private fun WalletCardImage( @OptIn(ExperimentalComposeUiApi::class) @Composable -private fun RowScope.WalletInfo( - wallet: UserWalletItem, - isSelected: Boolean, -) { +private fun RowScope.WalletInfo(wallet: UserWalletItem, isSelected: Boolean) { Column( - modifier = Modifier.weight(weight = .6f), + modifier = Modifier.weight(weight = 2f), verticalArrangement = Arrangement.SpaceAround, + horizontalAlignment = Alignment.Start, ) { Text( - modifier = Modifier.fillMaxWidth(), text = wallet.name, color = if (isSelected) TangemTheme.colors.text.accent else TangemTheme.colors.text.primary1, + overflow = TextOverflow.Ellipsis, + maxLines = 1, style = TangemTypography.subtitle1, ) SpacerH2() Text( - modifier = Modifier.fillMaxWidth(), text = when (wallet) { is MultiCurrencyUserWalletItem -> pluralStringResource( id = R.plurals.card_label_card_count, @@ -162,22 +163,19 @@ private fun RowScope.WalletInfo( ) is SingleCurrencyUserWalletItem -> wallet.tokenName }, - style = TangemTheme.typography.caption, color = TangemTheme.colors.text.tertiary, + maxLines = 1, + style = TangemTheme.typography.caption, ) } } @Composable -private fun RowScope.TokensInfo( - isLocked: Boolean, - balance: UserWalletItem.Balance, - tokensCount: Int?, -) { +private fun RowScope.TokensInfo(isLocked: Boolean, balance: UserWalletItem.Balance, tokensCount: Int?) { Column( - modifier = Modifier.weight(weight = .4f), + modifier = Modifier.weight(weight = 3f), verticalArrangement = Arrangement.SpaceAround, - horizontalAlignment = Alignment.End, + horizontalAlignment = Alignment.End ) { if (isLocked) { LockedPlaceholder() @@ -254,9 +252,11 @@ private fun LoadedTokensInfo( ) { Text( text = balanceAmount, - style = TangemTheme.typography.subtitle1, color = TangemTheme.colors.text.primary1, textAlign = TextAlign.End, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + style = TangemTheme.typography.subtitle1, ) if (showWarning) { Icon( @@ -371,4 +371,26 @@ private fun CheckedWalletMark( contentDescription = null, ) } +} + +@Preview(widthDp = 360, heightDp = 72, showBackground = true) +@Composable +private fun PreviewWalletItem() { + TangemTheme { + WalletItem( + wallet = MultiCurrencyUserWalletItem( + id = UserWalletId(value = null), + name = "Tangem Card", + imageUrl = "", + balance = UserWalletItem.Balance.Loaded("141212121888 BTC"), + isLocked = false, + tokensCount = 2, + cardsInWallet = 1, + ), + isSelected = false, + isChecked = false, + onWalletClick = {}, + onWalletLongClick = {}, + ) + } } \ No newline at end of file From 19d32d5f623ca44af690ed9095ff7292f3d6b4e4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 16:49:05 +0300 Subject: [PATCH 21/29] Updated on 2026-08-14 --- .../DefaultWalletCurrenciesManager.kt | 48 ++++++++++++++++--- .../DefaultWalletAmountsRepository.kt | 2 +- .../DefaultWalletManagersRepository.kt | 29 +++++------ .../tangem/tap/proxy/UserWalletManagerImpl.kt | 40 ++++++++++++---- 4 files changed, 89 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt index 2c74eba8ba..b9292c096c 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt @@ -55,12 +55,16 @@ internal class DefaultWalletCurrenciesManager( currenciesToAdd: List, ): CompletionResult = withContext(Dispatchers.Default) { val card = userWallet.scanResponse.card - val newCurrencies = (getSavedCurrencies(userWallet.walletId) + currenciesToAdd) - .addMissingBlockchains(card) + val currenciesToAddWithMissingBlockchains = currenciesToAdd.addMissingBlockchainsIfNeeded(card) - updateWalletStores(userWallet, newCurrencies.toBlockchainNetworks()) + updateWalletStores( + userWallet = userWallet, + blockchainNetworks = currenciesToAddWithMissingBlockchains + .toBlockchainNetworks() + .addSameBlockchainTokens(userWallet.walletId), + ) .map { - saveUserCurrencies(card, newCurrencies) + saveUserCurrencies(card, getSavedCurrencies(userWallet.walletId)) } .flatMap { updateWalletStoresAmounts( @@ -114,7 +118,38 @@ internal class DefaultWalletCurrenciesManager( } } - private fun List.addMissingBlockchains(card: CardDTO): List { + // TODO: Need refactoring + private suspend fun List.addSameBlockchainTokens( + userWalletId: UserWalletId, + ): List { + val networks = arrayListOf() + val savedWalletStores = withContext(Dispatchers.Default) { + walletStoresRepository.getSync(userWalletId) + } + + this.forEach { network -> + val walletStore = savedWalletStores.firstOrNull { + it.blockchain == network.blockchain && it.derivationPath?.rawPath == network.derivationPath + } + + if (walletStore != null) { + val tokens = walletStore.walletsData + .asSequence() + .map { it.currency } + .filterIsInstance() + .map { it.token } + .toList() + + networks.add(network.copy(tokens = tokens + network.tokens.toSet())) + } else { + networks.add(network) + } + } + + return networks + } + + private fun List.addMissingBlockchainsIfNeeded(card: CardDTO): List { if (this.isEmpty()) return this val currencies = this.asSequence() @@ -165,7 +200,6 @@ internal class DefaultWalletCurrenciesManager( userWallet: UserWallet, blockchainNetworks: List, ): CompletionResult { - val userWalletId = userWallet.walletId return blockchainNetworks .map { blockchainNetwork -> walletManagersRepository.findOrMakeMultiCurrencyWalletManager( @@ -174,7 +208,7 @@ internal class DefaultWalletCurrenciesManager( ) .flatMap { walletManager -> walletStoresRepository.storeOrUpdate( - userWalletId = userWalletId, + userWalletId = userWallet.walletId, walletStore = WalletStoreBuilder(userWallet, blockchainNetwork) .walletManager(walletManager) .build(), diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt index c6519653d2..1080f7529f 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt @@ -442,7 +442,7 @@ internal class DefaultWalletAmountsRepository( .toMutableList() .apply { replaceByOrAdd(walletManager) { - it.wallet.blockchain == it.wallet.blockchain + it.wallet.blockchain == walletManager.wallet.blockchain } } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt index 1758c2fbf9..d9579349d6 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt @@ -7,8 +7,8 @@ import com.tangem.blockchain.common.WalletManager import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.common.CompletionResult import com.tangem.common.catching +import com.tangem.common.doOnSuccess import com.tangem.common.hdWallet.DerivationPath -import com.tangem.common.map import com.tangem.common.mapFailure import com.tangem.domain.common.CardDTO import com.tangem.domain.common.ScanResponse @@ -22,7 +22,7 @@ import com.tangem.tap.domain.walletStores.WalletStoresError import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository import com.tangem.tap.domain.walletStores.storage.WalletManagerStorage import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.withContext import timber.log.Timber @@ -93,10 +93,7 @@ internal class DefaultWalletManagersRepository( scanResponse = scanResponse, blockchainNetwork = blockchainNetwork, ) - .map { updatedWalletManager -> - store(userWallet.walletId, updatedWalletManager) - updatedWalletManager - } + .doOnSuccess { store(userWallet.walletId, it) } } else -> { val error = WalletStoresError.WalletManagerNotCreated(blockchain) @@ -158,8 +155,9 @@ internal class DefaultWalletManagersRepository( return catching { val tokens = blockchainNetwork?.tokens ?: listOfNotNull(scanResponse.cardTypesResolver.getPrimaryToken()) - if (tokens != cardTokens) { - cardTokens.clear() + if (tokens != walletManager.cardTokens) { + walletManager.cardTokens.clear() + walletManager.wallet.removeAllTokens() if (tokens.isNotEmpty()) { walletManager.cardTokens.addAll(tokens) } @@ -181,13 +179,16 @@ internal class DefaultWalletManagersRepository( userWalletId: UserWalletId, blockchain: Blockchain?, ): WalletManager? { - return walletManagersStorage.getAll().first()[userWalletId]?.let { userWalletManagers -> - if (blockchain == null) { - userWalletManagers.firstOrNull() - } else { - userWalletManagers.find { it.wallet.blockchain == blockchain } + return walletManagersStorage.getAll() + .firstOrNull() + ?.get(userWalletId) + ?.let { userWalletManagers -> + if (blockchain == null) { + userWalletManagers.firstOrNull() + } else { + userWalletManagers.firstOrNull { it.wallet.blockchain == blockchain } + } } - } } private fun getDerivationParams(derivationPath: String?, card: CardDTO): DerivationParams? { diff --git a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt index 715f99415a..250bf73562 100644 --- a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt @@ -23,9 +23,12 @@ import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.userWalletsListManager +import com.tangem.tap.walletCurrenciesManager import kotlinx.coroutines.delay import org.rekotlin.Action import java.math.BigDecimal +import com.tangem.tap.features.wallet.models.Currency as WalletCurrency class UserWalletManagerImpl( private val appStateHolder: AppStateHolder, @@ -106,14 +109,21 @@ class UserWalletManagerImpl( val card = requireNotNull(appStateHolder.getActualCard()) { "card not found" } val blockchain = requireNotNull(Blockchain.fromNetworkId(currency.networkId)) { "blockchain not found" } val blockchainNetwork = BlockchainNetwork(blockchain, card) - val walletManager = getOrCreateBlockchain(blockchainNetwork, blockchain) - if (currency is NonNativeToken && - !walletManager.cardTokens.contains(currency.toSdkToken()) - ) { - val action = addNonNativeTokenToWalletAction(currency, card, blockchain) - val mainStore = requireNotNull(appStateHolder.mainStore) { "mainStore is null" } - mainStore.dispatchOnMain(action) - delay(DELAY_UPDATE_WALLET) + + val selectedUserWallet = userWalletsListManager.selectedUserWalletSync + if (selectedUserWallet != null) { + walletCurrenciesManager.addCurrencies( + userWallet = selectedUserWallet, + currenciesToAdd = listOf(currency.toWalletCurrency(blockchainNetwork)), + ) + } else { + val walletManager = getOrCreateBlockchain(blockchainNetwork, blockchain) + if (currency is NonNativeToken && !walletManager.cardTokens.contains(currency.toSdkToken())) { + val action = addNonNativeTokenToWalletAction(currency, card, blockchain) + val mainStore = requireNotNull(appStateHolder.mainStore) { "mainStore is null" } + mainStore.dispatchOnMain(action) + delay(DELAY_UPDATE_WALLET) + } } } @@ -271,4 +281,18 @@ private fun NonNativeToken.toSdkToken(): Token { contractAddress = this.contractAddress, decimals = this.decimalCount, ) +} + +private fun Currency.toWalletCurrency(network: BlockchainNetwork): WalletCurrency { + return when (this) { + is NativeToken -> WalletCurrency.Blockchain( + blockchain = network.blockchain, + derivationPath = network.derivationPath, + ) + is NonNativeToken -> WalletCurrency.Token( + token = this.toSdkToken(), + blockchain = network.blockchain, + derivationPath = network.derivationPath, + ) + } } \ No newline at end of file From f170659a35acc9321df32ac62a8ff9cfe703560f Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 14:48:16 +0300 Subject: [PATCH 22/29] Updated on 2026-08-14 --- .../feature/swap/domain/SwapInteractorImpl.kt | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index e759fd412c..5d5e32dc6e 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -52,7 +52,7 @@ internal class SwapInteractorImpl @Inject constructor( // replace tokens in wallet tokens list with loaded same val loadedOnWalletsMap = mutableSetOf() - val tokensInWallet = userWalletManager.getUserTokens(networkId, false) + val tokensInWallet = userWalletManager.getUserTokens(networkId, true) .filter { it.symbol != initialCurrency.symbol } .map { token -> allLoadedTokens.firstOrNull { it.symbol == token.symbol }?.let { @@ -288,8 +288,9 @@ internal class SwapInteractorImpl @Inject constructor( amountFormatter.formatSwapAmountToUI(amount, it.symbol) }, amountEquivalent = balance?.value?.toFiatString( - rates[it.id]?.toBigDecimal() ?: BigDecimal.ZERO, - appCurrency.symbol, + rateValue = rates[it.id]?.toBigDecimal() ?: BigDecimal.ZERO, + fiatCurrencyName = appCurrency.symbol, + formatWithSpaces = true, ), ), ) @@ -334,7 +335,11 @@ internal class SwapInteractorImpl @Inject constructor( return SwapState.EmptyAmountState( fromTokenWalletBalance = fromTokenBalance?.let { amountFormatter.formatSwapAmountToUI(it, "") }.orEmpty(), toTokenWalletBalance = toTokenBalance?.let { amountFormatter.formatSwapAmountToUI(it, "") }.orEmpty(), - zeroAmountEquivalent = BigDecimal.ZERO.toFiatString(BigDecimal.ONE, appCurrency.symbol), + zeroAmountEquivalent = BigDecimal.ZERO.toFiatString( + rateValue = BigDecimal.ONE, + fiatCurrencyName = appCurrency.symbol, + formatWithSpaces = true, + ), ) } @@ -405,7 +410,7 @@ internal class SwapInteractorImpl @Inject constructor( val nativeToken = userWalletManager.getNativeTokenForNetwork(networkId) val rates = repository.getRates(appCurrency.code, listOf(fromTokenId, toTokenId, nativeToken.id)) return rates[nativeToken.id]?.toBigDecimal()?.let { rate -> - " (${fee.toFiatString(rate, appCurrency.symbol)})" + " (${fee.toFiatString(rate, appCurrency.symbol, true)})" }.orEmpty() } @@ -485,8 +490,9 @@ internal class SwapInteractorImpl @Inject constructor( tokenWalletBalance = fromTokenBalance?.let { amountFormatter.formatSwapAmountToUI(it, "") } ?: ZERO_BALANCE, tokenFiatBalance = fromTokenAmount.value.toFiatString( - rates[fromToken.id]?.toBigDecimal() ?: BigDecimal.ZERO, - appCurrency.symbol, + rateValue = rates[fromToken.id]?.toBigDecimal() ?: BigDecimal.ZERO, + fiatCurrencyName = appCurrency.symbol, + formatWithSpaces = true, ), ), toTokenInfo = TokenSwapInfo( @@ -495,8 +501,9 @@ internal class SwapInteractorImpl @Inject constructor( tokenWalletBalance = toTokenBalance?.let { amountFormatter.formatSwapAmountToUI(it, "") } ?: ZERO_BALANCE, tokenFiatBalance = toTokenAmount.value.toFiatString( - rates[toToken.id]?.toBigDecimal() ?: BigDecimal.ZERO, - appCurrency.symbol, + rateValue = rates[toToken.id]?.toBigDecimal() ?: BigDecimal.ZERO, + fiatCurrencyName = appCurrency.symbol, + formatWithSpaces = true, ), ), fee = formattedFee, From 9331a5736ef0c476bd4bf0694f4937443158e972 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 15:17:41 +0300 Subject: [PATCH 23/29] Updated on 2026-08-14 --- core/res/src/main/res/values-de/strings.xml | 2 +- core/res/src/main/res/values-fr/strings.xml | 2 +- core/res/src/main/res/values-it/strings.xml | 2 +- core/res/src/main/res/values-ru/strings.xml | 2 +- core/res/src/main/res/values-zh-rTW/strings.xml | 2 +- core/res/src/main/res/values/strings.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index c7204aedc5..ffa90384f5 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -353,7 +353,7 @@ Swap Swap Swap of %s to - Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. + Quotes include an additional Tangem commission of %s. This helps us deliver a top-of-the-line product. Other tokens Choose token Your tokens diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 309fd73c0e..a9c847c30f 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -353,7 +353,7 @@ Swap Swap Swap of %s to - Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. + Quotes include an additional Tangem commission of %s. This helps us deliver a top-of-the-line product. Other tokens Choose token Your tokens diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index aa56c83847..4ae4f65caf 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -353,7 +353,7 @@ Swap Swap Swap of %s to - Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. + Quotes include an additional Tangem commission of %s. This helps us deliver a top-of-the-line product. Other tokens Choose token Your tokens diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 20bc6c313d..86620877b5 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -353,7 +353,7 @@ Обмен Обменять Обмен %s на - Кроме того, котировки включают комиссию Tangem в размере %s. Это помогает нам предоставлять первоклассный продукт. + Котировки включают дополнительную комиссию Tangem в размере %s. Это помогает нам предоставлять первоклассный продукт. Другие токены Выберите токен Ваши токены diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml index e74a4bab51..96b180a83f 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -353,7 +353,7 @@ 交換 Swap 交易 %s 至 - Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. + Quotes include an additional Tangem commission of %s. This helps us deliver a top-of-the-line product. 其他代幣 選擇代幣 您的代幣 diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 59a3b2dcb3..afa7b78109 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -353,7 +353,7 @@ Swap Swap Swap of %s to - Additionally, quotes include Tangem fee of %s. This helps us deliver a top-of-the-line product. + Quotes include an additional Tangem commission of %s. This helps us deliver a top-of-the-line product. Other tokens Choose token Your tokens From a8cec3b9331ca3b359804097d983022ccb79e6f9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 15:54:08 +0300 Subject: [PATCH 24/29] Updated on 2026-08-14 --- .../tangem/tap/proxy/TransactionManagerImpl.kt | 16 ++++++++++++++++ .../feature/swap/viewmodels/SwapViewModel.kt | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt index 0607b9caaa..30a360ad10 100644 --- a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt @@ -171,6 +171,10 @@ class TransactionManagerImpl( val error = result.error as? BlockchainSdkError ?: return SendTxResult.UnknownError() when (error) { is BlockchainSdkError.WrappedTangemError -> { + val errorByCode = mapErrorByCode(error) + if (errorByCode != null) { + return errorByCode + } val tangemSdkError = error.tangemError as? TangemSdkError ?: return SendTxResult.UnknownError() if (tangemSdkError is TangemSdkError.UserCancelled) return SendTxResult.UserCancelledError return SendTxResult.TangemSdkError(tangemSdkError.code, tangemSdkError.cause) @@ -183,6 +187,17 @@ class TransactionManagerImpl( } } + private fun mapErrorByCode(error: BlockchainSdkError.WrappedTangemError): SendTxResult? { + return when (error.code) { + USER_CANCELLED_ERROR_CODE -> { + return SendTxResult.UserCancelledError + } + else -> { + null + } + } + } + private fun transactionSigner(walletManager: WalletManager): TransactionSigner { val actualCard = requireNotNull(appStateHolder.getActualCard()) { "no card found" } return TangemSigner( @@ -291,5 +306,6 @@ class TransactionManagerImpl( companion object { private const val HEX_PREFIX = "0x" + private const val USER_CANCELLED_ERROR_CODE = 50002 } } \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index a8933475a0..a8ca2afb08 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -251,6 +251,9 @@ internal class SwapViewModel @Inject constructor( analyticsEventHandler.send(SwapEvents.SwapInProgressScreen) swapRouter.openScreen(SwapNavScreen.Success) } + is TxState.UserCancelled -> { + startLoadingQuotesFromLastState() + } else -> { startLoadingQuotesFromLastState() uiState = stateBuilder.createErrorTransaction(uiState, it) { @@ -282,6 +285,9 @@ internal class SwapViewModel @Inject constructor( is TxState.TxSent -> { uiState = stateBuilder.loadingPermissionState(uiState) } + is TxState.UserCancelled -> { + // do nothing + } else -> { uiState = stateBuilder.createErrorTransaction(uiState, it) { uiState = stateBuilder.clearAlert(uiState) From a52562696a31ff47b48a58d7fa7ce842259fe822 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 16:35:42 +0300 Subject: [PATCH 25/29] Updated on 2026-08-14 --- .../src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index 4692699435..29065fe534 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -198,6 +198,7 @@ internal class StateBuilder(val actions: UiActions) { canSelectAnotherToken = uiStateHolder.receiveCardData.canSelectAnotherToken, balance = emptyAmountState.toTokenWalletBalance, ), + warnings = emptyList(), fee = FeeState.Empty, swapButton = SwapButton( enabled = false, From 7af83c6998e8f72e21ebfd6f685c0902b7a3d4d9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 21:21:00 +0300 Subject: [PATCH 26/29] Updated on 2026-08-14 --- .../feature/swap/domain/SwapInteractorImpl.kt | 15 +++++++++------ .../com/tangem/feature/swap/ui/StateBuilder.kt | 10 ++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 5d5e32dc6e..5711aca6ad 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -556,12 +556,15 @@ internal class SwapInteractorImpl @Inject constructor( } private suspend fun syncWalletBalanceForTokens(networkId: String, tokens: List) { - val tokensBalance = - userWalletManager.getCurrentWalletTokensBalance( - networkId = networkId, - extraTokens = tokens.map { cryptoCurrencyConverter.convert(it) }, - ) - cache.cacheBalances(tokensBalance.mapValues { SwapAmount(it.value.value, it.value.decimals) }) + val tokensToSync = tokens.filter { cache.getBalanceForToken(it.symbol) == null } + if (tokensToSync.isNotEmpty()) { + val tokensBalance = + userWalletManager.getCurrentWalletTokensBalance( + networkId = networkId, + extraTokens = tokensToSync.map { cryptoCurrencyConverter.convert(it) }, + ) + cache.cacheBalances(tokensBalance.mapValues { SwapAmount(it.value.value, it.value.decimals) }) + } } private fun isBalanceEnough(fromToken: Currency, amount: SwapAmount, fee: BigDecimal?): Boolean { diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index 29065fe534..31d4ce3cb4 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -79,6 +79,8 @@ internal class StateBuilder(val actions: UiActions) { toToken: Currency, mainTokenId: String, ): SwapStateHolder { + val canSelectSendToken = mainTokenId != fromToken.id + val canSelectReceiveToken = mainTokenId != toToken.id return uiStateHolder.copy( sendCardData = SwapCardData( type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard), @@ -88,8 +90,8 @@ internal class StateBuilder(val actions: UiActions) { tokenCurrency = fromToken.symbol, coinId = fromToken.id, isNotNativeToken = fromToken.isNonNative(), - canSelectAnotherToken = mainTokenId != fromToken.id, - balance = "", + canSelectAnotherToken = canSelectSendToken, + balance = if (!canSelectSendToken) uiStateHolder.sendCardData.balance else "", ), receiveCardData = SwapCardData( type = TransactionCardType.ReceiveCard(), @@ -99,8 +101,8 @@ internal class StateBuilder(val actions: UiActions) { tokenCurrency = toToken.symbol, coinId = toToken.id, isNotNativeToken = toToken.isNonNative(), - canSelectAnotherToken = mainTokenId != toToken.id, - balance = "", + canSelectAnotherToken = canSelectReceiveToken, + balance = if (!canSelectReceiveToken) uiStateHolder.receiveCardData.balance else "", ), fee = FeeState.Loading, swapButton = SwapButton(enabled = false, loading = true, onClick = {}), From b9b612c1b833620f200bc6b7b247b1b9cf655a47 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Feb 2023 21:55:00 +0300 Subject: [PATCH 27/29] Updated on 2026-08-14 --- .../feature/swap/domain/SwapInteractorImpl.kt | 31 ++++++++++--------- .../swap/domain/cache/SwapDataCache.kt | 9 +++--- .../swap/domain/cache/SwapDataCacheImpl.kt | 13 ++++---- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 5711aca6ad..f7ba2f4a06 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -68,17 +68,17 @@ internal class SwapInteractorImpl @Inject constructor( .mapValues { SwapAmount(it.value.value, it.value.decimals) } val appCurrency = userWalletManager.getUserAppCurrency() val rates = repository.getRates(appCurrency.code, tokensInWallet.map { it.id }) - cache.cacheLoadedTokens(loadedTokens) cache.cacheBalances(tokensBalance) - cache.cacheInWalletTokens(tokensInWallet) + cache.cacheLoadedTokens(loadedTokens.map { TokenWithBalance(it) }) + cache.cacheInWalletTokens(getTokensWithBalance(tokensInWallet, tokensBalance, rates, appCurrency)) return TokensDataState( preselectTokens = PreselectTokens( fromToken = initialCurrency, toToken = selectToToken(initialCurrency, tokensInWallet, loadedTokens), ), foundTokensState = FoundTokensState( - tokensInWallet = getTokensWithBalance(tokensInWallet, tokensBalance, rates, appCurrency), - loadedTokens = loadedTokens.map { TokenWithBalance(it) }, + tokensInWallet = cache.getInWalletTokens(), + loadedTokens = cache.getLoadedTokens(), ), ) } @@ -87,28 +87,29 @@ internal class SwapInteractorImpl @Inject constructor( val searchQueryLowerCase = searchQuery.lowercase() val tokensInWallet = cache.getInWalletTokens() .filter { - it.name.lowercase().contains(searchQueryLowerCase) || - it.symbol.lowercase().contains(searchQueryLowerCase) + it.token.name.lowercase().contains(searchQueryLowerCase) || + it.token.symbol.lowercase().contains(searchQueryLowerCase) } val loadedTokens = cache.getLoadedTokens() .filter { - it.name.lowercase().contains(searchQueryLowerCase) || - it.symbol.lowercase().contains(searchQueryLowerCase) + it.token.name.lowercase().contains(searchQueryLowerCase) || + it.token.symbol.lowercase().contains(searchQueryLowerCase) } - val tokensBalance = userWalletManager.getCurrentWalletTokensBalance(networkId, emptyList()) - .mapValues { SwapAmount(it.value.value, it.value.decimals) } - val appCurrency = userWalletManager.getUserAppCurrency() - val rates = repository.getRates(appCurrency.code, tokensInWallet.map { it.id }) + // val tokensBalance = userWalletManager.getCurrentWalletTokensBalance(networkId, emptyList()) + // .mapValues { SwapAmount(it.value.value, it.value.decimals) } + // val appCurrency = userWalletManager.getUserAppCurrency() + // val rates = repository.getRates(appCurrency.code, tokensInWallet.map { it.id }) return FoundTokensState( - tokensInWallet = getTokensWithBalance(tokensInWallet, tokensBalance, rates, appCurrency), - loadedTokens = loadedTokens.map { TokenWithBalance(it) }, + tokensInWallet = tokensInWallet, // getTokensWithBalance(tokensInWallet, tokensBalance, rates, appCurrency), + loadedTokens = loadedTokens, // loadedTokens.map { TokenWithBalance(it) }, ) } override fun findTokenById(id: String): Currency? { val tokensInWallet = cache.getInWalletTokens() val loadedTokens = cache.getLoadedTokens() - return tokensInWallet.firstOrNull { it.id == id } ?: loadedTokens.firstOrNull { it.id == id } + return tokensInWallet.firstOrNull { it.token.id == id }?.token + ?: loadedTokens.firstOrNull { it.token.id == id }?.token } override suspend fun givePermissionToSwap( diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCache.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCache.kt index 4736dbf25b..36a0ef8ef3 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCache.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCache.kt @@ -2,18 +2,19 @@ package com.tangem.feature.swap.domain.cache import com.tangem.feature.swap.domain.models.SwapAmount import com.tangem.feature.swap.domain.models.domain.Currency +import com.tangem.feature.swap.domain.models.ui.TokenWithBalance import java.math.BigDecimal interface SwapDataCache { fun cacheAvailableToSwapTokens(networkId: String, tokens: List) - fun cacheInWalletTokens(tokens: List) - fun cacheLoadedTokens(tokens: List) + fun cacheInWalletTokens(tokens: List) + fun cacheLoadedTokens(tokens: List) fun cacheBalances(balances: Map) fun cacheLastFeeForNetwork(fee: BigDecimal, networkId: String) fun getAvailableTokens(networkId: String): List - fun getInWalletTokens(): List - fun getLoadedTokens(): List + fun getInWalletTokens(): List + fun getLoadedTokens(): List fun getBalanceForToken(symbol: String): SwapAmount? fun getLastFeeForNetwork(networkId: String): BigDecimal? } \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCacheImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCacheImpl.kt index 55792cbf26..f044693ece 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCacheImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCacheImpl.kt @@ -2,6 +2,7 @@ package com.tangem.feature.swap.domain.cache import com.tangem.feature.swap.domain.models.SwapAmount import com.tangem.feature.swap.domain.models.domain.Currency +import com.tangem.feature.swap.domain.models.ui.TokenWithBalance import java.math.BigDecimal class SwapDataCacheImpl : SwapDataCache { @@ -9,28 +10,28 @@ class SwapDataCacheImpl : SwapDataCache { private val availableTokensForNetwork: MutableMap> = mutableMapOf() private val feesForNetworks: MutableMap = mutableMapOf() private val tokensBalances: MutableMap = mutableMapOf() - private val lastInWalletTokens = mutableListOf() - private val lastLoadedTokens = mutableListOf() + private val lastInWalletTokens = mutableListOf() + private val lastLoadedTokens = mutableListOf() override fun cacheLastFeeForNetwork(fee: BigDecimal, networkId: String) { feesForNetworks[networkId] = fee } - override fun cacheInWalletTokens(tokens: List) { + override fun cacheInWalletTokens(tokens: List) { lastInWalletTokens.clear() lastInWalletTokens.addAll(tokens) } - override fun cacheLoadedTokens(tokens: List) { + override fun cacheLoadedTokens(tokens: List) { lastLoadedTokens.clear() lastLoadedTokens.addAll(tokens) } - override fun getInWalletTokens(): List { + override fun getInWalletTokens(): List { return lastInWalletTokens } - override fun getLoadedTokens(): List { + override fun getLoadedTokens(): List { return lastLoadedTokens } From 81203441bd2043082ba0342aeadfdc0f1c0c9b6b Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 27 Feb 2023 10:47:39 +0300 Subject: [PATCH 28/29] Updated on 2026-08-14 --- .../com/tangem/datasource/config/ConfigManagerImpl.kt | 2 ++ .../tangem/feature/swap/domain/SwapInteractorImpl.kt | 10 +++------- .../tangem/feature/swap/viewmodels/SwapViewModel.kt | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt index 63e503173e..e438e85955 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/ConfigManagerImpl.kt @@ -14,7 +14,9 @@ import com.tangem.datasource.config.models.ConfigModel import com.tangem.datasource.config.models.ConfigValueModel import com.tangem.datasource.config.models.FeatureModel import javax.inject.Inject +import javax.inject.Singleton +@Singleton internal class ConfigManagerImpl @Inject constructor() : ConfigManager { override var config: Config = Config() diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index f7ba2f4a06..23b6c794b8 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -52,7 +52,7 @@ internal class SwapInteractorImpl @Inject constructor( // replace tokens in wallet tokens list with loaded same val loadedOnWalletsMap = mutableSetOf() - val tokensInWallet = userWalletManager.getUserTokens(networkId, true) + val tokensInWallet = userWalletManager.getUserTokens(networkId = networkId, isExcludeCustom = true) .filter { it.symbol != initialCurrency.symbol } .map { token -> allLoadedTokens.firstOrNull { it.symbol == token.symbol }?.let { @@ -95,13 +95,9 @@ internal class SwapInteractorImpl @Inject constructor( it.token.name.lowercase().contains(searchQueryLowerCase) || it.token.symbol.lowercase().contains(searchQueryLowerCase) } - // val tokensBalance = userWalletManager.getCurrentWalletTokensBalance(networkId, emptyList()) - // .mapValues { SwapAmount(it.value.value, it.value.decimals) } - // val appCurrency = userWalletManager.getUserAppCurrency() - // val rates = repository.getRates(appCurrency.code, tokensInWallet.map { it.id }) return FoundTokensState( - tokensInWallet = tokensInWallet, // getTokensWithBalance(tokensInWallet, tokensBalance, rates, appCurrency), - loadedTokens = loadedTokens, // loadedTokens.map { TokenWithBalance(it) }, + tokensInWallet = tokensInWallet, + loadedTokens = loadedTokens, ) } diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index a8ca2afb08..ddf5f6876c 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -286,7 +286,7 @@ internal class SwapViewModel @Inject constructor( uiState = stateBuilder.loadingPermissionState(uiState) } is TxState.UserCancelled -> { - // do nothing + /* no-op */ } else -> { uiState = stateBuilder.createErrorTransaction(uiState, it) { From b232211f7d675d4f9fc5199576aea6f2edb5cbb7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 28 Feb 2023 12:12:09 +0300 Subject: [PATCH 29/29] Updated on 2026-08-14 --- .../tap/features/walletSelector/ui/components/WalletItem.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt index 93df00409d..385916f599 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding @@ -175,7 +174,7 @@ private fun RowScope.TokensInfo(isLocked: Boolean, balance: UserWalletItem.Balan Column( modifier = Modifier.weight(weight = 3f), verticalArrangement = Arrangement.SpaceAround, - horizontalAlignment = Alignment.End + horizontalAlignment = Alignment.End, ) { if (isLocked) { LockedPlaceholder()