From ad31bdf58e8712ec61e0b4ab22573a43c226d71f Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 17 Apr 2024 16:21:25 +0500 Subject: [PATCH 01/23] Updated on 2026-08-14 --- .../impl/presentation/state/confirm/SendNotificationFactory.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index 0d147eb6fd..4abd80f5cd 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -247,7 +247,7 @@ internal class SendNotificationFactory( val totalAmount = feeAmount + receivedAmount val change = balance - totalAmount val isChangeLowerThanDust = change < dustValue && change != BigDecimal.ZERO - val isShowWarning = totalAmount < dustValue || isChangeLowerThanDust + val isShowWarning = receivedAmount < dustValue || isChangeLowerThanDust if (isShowWarning) { add( SendNotification.Error.MinimumAmountError(dustValue.toPlainString()), From aff8f6d270ec5003f3eec48ad48946a400591ed8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 17 Apr 2024 16:21:57 +0500 Subject: [PATCH 02/23] Updated on 2026-08-14 --- .../presentation/state/amount/SendAmountSubtractConverter.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountSubtractConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountSubtractConverter.kt index bf0f52dd73..fb5d2708ad 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountSubtractConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountSubtractConverter.kt @@ -19,11 +19,13 @@ internal class SendAmountSubtractConverter( val feeValue = feeState.fee?.amount?.value ?: return state val amountTextField = amountState.amountTextField val amountValue = amountTextField.cryptoAmount.value ?: return state + val balance = cryptoCurrencyStatus.value.amount ?: return state val fiatRate = cryptoCurrencyStatus.value.fiatRate val cryptoDecimals = amountTextField.cryptoAmount.decimals val fiatDecimals = amountTextField.fiatAmount.decimals - val feeDiff = amountState.subtractedFee?.let { feeValue.minus(it) } ?: feeValue + val feeDiff = amountState.subtractedFee?.let { feeValue.minus(it) } + ?: amountValue.minus(balance.minus(feeValue)) val decimalCryptoValue = amountValue.minus(feeDiff) if (decimalCryptoValue < BigDecimal.ZERO) return state From ad96d7ce1a395e4bdd1ddd33e5a49e5b75753091 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 11:59:03 +0500 Subject: [PATCH 03/23] Updated on 2026-08-14 --- .../SendRecipientWalletListConverter.kt | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientWalletListConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientWalletListConverter.kt index 855e5d3a3b..6b92680baf 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientWalletListConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientWalletListConverter.kt @@ -18,22 +18,25 @@ internal class SendRecipientWalletListConverter : } } - private fun List.filterWallets() = this.filterNotNull() - .groupBy { item -> item.name } - .values.map { - it.mapIndexed { index, item -> - val name = if (it.size > 1) { - "${item.name} ${index.inc()}" - } else { - item.name + private fun List.filterWallets(): PersistentList { + var walletsCounter = 0 + return this.filterNotNull() + .groupBy { item -> item.name } + .values.map { + it.mapIndexed { index, item -> + val name = if (it.size > 1) { + "${item.name} ${index.inc()}" + } else { + item.name + } + SendRecipientListContent( + id = "${WALLET_KEY_TAG}${walletsCounter++}", + title = TextReference.Str(item.address), + subtitle = TextReference.Str(name), + ) } - SendRecipientListContent( - id = "${WALLET_KEY_TAG}$index", - title = TextReference.Str(item.address), - subtitle = TextReference.Str(name), - ) } - } - .flatten() - .toPersistentList() + .flatten() + .toPersistentList() + } } \ No newline at end of file From dbedf097b91d221d2c189ad79c247d8b70003ffa Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 11:59:41 +0500 Subject: [PATCH 04/23] Updated on 2026-08-14 --- .../presentation/state/confirm/SendNotificationFactory.kt | 4 ++-- .../send/impl/presentation/viewmodel/SendViewModel.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index 4abd80f5cd..441e6dd175 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -70,7 +70,7 @@ internal class SendNotificationFactory( }.toImmutableList() } - fun dismissNotificationState(clazz: Class): SendUiState { + fun dismissNotificationState(clazz: Class, isIgnored: Boolean = false): SendUiState { val state = currentStateProvider() val sendState = state.sendState ?: return state val notificationsToRemove = sendState.notifications.filterIsInstance(clazz) @@ -78,7 +78,7 @@ internal class SendNotificationFactory( updatedNotifications.removeAll(notificationsToRemove) return state.copy( sendState = sendState.copy( - ignoreAmountReduce = true, + ignoreAmountReduce = isIgnored, notifications = updatedNotifications.toImmutableList(), ), ) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index ffad3f3633..57dc709ab1 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -795,7 +795,7 @@ internal class SendViewModel @Inject constructor( } override fun onNotificationCancel(clazz: Class) { - uiState = sendNotificationFactory.dismissNotificationState(clazz) + uiState = sendNotificationFactory.dismissNotificationState(clazz = clazz, isIgnored = true) } private fun verifyAndSendTransaction() { From 1c9c5d62f4e6bc0965fa8bf84a55124551b67bab Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 12:00:08 +0500 Subject: [PATCH 05/23] Updated on 2026-08-14 --- core/res/src/main/res/values-ru/strings.xml | 5 +++++ core/res/src/main/res/values/strings.xml | 9 +++++++++ .../core/ui/components/inputrow/inner/PasteButton.kt | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 5d25d41f8e..9f10054ca1 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -51,6 +51,10 @@ Заводские настройки Тип безопасности Настройки карты + Ввиду особенностей сети Cardano при транзакции токена %1$s помимо комиссии сети будет списано %2$s + Для совершения транзакции %1$s, вам необходимо внести немного %2$s (%3$s), чтобы покрыть комиссию сети и минимальное значение ADA для отправки. + Недостаточно ADA для отправки токена + Вывод всего баланса ADA невозможен при наличии средств на токенах сети Cardano. Сначала выведите средства на ваших токенах. Принять Доступ запрещен Применить @@ -97,6 +101,7 @@ OK Основная карта Кодовая фраза + Вставить Подробнее Получить Отклонить diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index a099c577d4..04985255c2 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -50,6 +50,10 @@ Reset to Factory Settings Security Mode Card Settings + Due to the peculiarities of the Cardano network, when transacting the %1$s token, in addition to the network commission, %2$s will be charged + To make a %1$s transaction, you must deposit some %2$s (%3$s) to cover the network fee and minimum ADA value + Insufficient ADA to token transfer + Withdrawal of the entire ADA balance is not possible if funds are available in Cardano network tokens. First, withdraw funds on your tokens. Accept Access denied Apply @@ -96,6 +100,7 @@ OK Primary Card Passphrase + Paste Read more Receive Reject @@ -427,6 +432,8 @@ Reason: %1$s\nCode: %2$s The transaction is not completed Amount + Base fee + Represents the part of the transaction fee that goes to the miner %1$s, %2$s Address Destination Tag @@ -474,6 +481,8 @@ Due to %1$s limitations only %2$s UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount. Transaction limitation Optional + Priority fee + Represents the minimum gasUsed multiplier required for a transaction to be included in a block. This is the part of the transaction fee that is burnt. Please align your QR code with the square to scan it. Ensure you scan %s network address. Recent Recipient diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/PasteButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/PasteButton.kt index 88ed54192f..49c308e97e 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/PasteButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/inputrow/inner/PasteButton.kt @@ -50,7 +50,7 @@ fun PasteButton(isPasteButtonVisible: Boolean, onClick: (String) -> Unit, modifi modifier = modifier, ) { Text( - text = "Paste", + text = stringResource(R.string.common_paste), style = TangemTheme.typography.button, color = TangemTheme.colors.text.primary2, modifier = Modifier From 31f3394afd9013b70f66202bf5c3e6bdade376cf Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 14:05:03 +0500 Subject: [PATCH 06/23] Updated on 2026-08-14 --- .../presentation/state/SendStateFactory.kt | 1 + .../state/confirm/SendNotificationFactory.kt | 7 ++ .../state/fee/FeeSelectorState.kt | 2 + .../presentation/state/fee/FeeStateFactory.kt | 5 + .../state/fee/SendFeeStateConverter.kt | 2 +- .../impl/presentation/ui/send/FeeBlock.kt | 93 ++++++++++++++----- .../presentation/ui/send/RecipientBlock.kt | 24 +++++ .../presentation/viewmodel/SendViewModel.kt | 4 +- 8 files changed, 113 insertions(+), 25 deletions(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt index f3f304b7ff..0938d051f2 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt @@ -117,6 +117,7 @@ internal class SendStateFactory( recipientState = state.recipientState ?: recipientStateConverter.convert(SendRecipientStateConverter.Data(destinationAddress, memo)), feeState = state.feeState ?: feeStateConverter.convert(Unit), + sendState = confirmStateConverter.convert(Unit), isEditingDisabled = true, cryptoCurrencyName = cryptoCurrencyStatusProvider().currency.name, ) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index 441e6dd175..eb9fdba3a1 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -57,6 +57,7 @@ internal class SendNotificationFactory( val amountValue = state.amountState?.amountTextField?.cryptoAmount?.value ?: BigDecimal.ZERO buildList { // errors + addFeeUnreachableNotification(feeState.feeSelectorState) addExceedBalanceNotification(feeAmount, amountValue) addExceedsBalanceNotification(feeState.fee) addMinimumAmountErrorNotification(feeAmount, amountValue) @@ -84,6 +85,12 @@ internal class SendNotificationFactory( ) } + private fun MutableList.addFeeUnreachableNotification(feeSelectorState: FeeSelectorState) { + if (feeSelectorState is FeeSelectorState.Error) { + add(SendNotification.Warning.NetworkFeeUnreachable(clickIntents::feeReload)) + } + } + private fun MutableList.addExceedBalanceNotification( feeAmount: BigDecimal, receivedAmount: BigDecimal, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeSelectorState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeSelectorState.kt index 67fe86cf8e..cd1fe29939 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeSelectorState.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeSelectorState.kt @@ -15,6 +15,8 @@ internal sealed class FeeSelectorState { val customValues: ImmutableList = persistentListOf(), ) : FeeSelectorState() + data object Loading : FeeSelectorState() + data object Error : FeeSelectorState() } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt index ba181f423f..5e34a54d61 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeStateFactory.kt @@ -47,6 +47,11 @@ internal class FeeStateFactory( return state.copy( amountState = state.amountState?.copy(isFeeLoading = true), feeState = feeState.copy( + feeSelectorState = if (feeState.feeSelectorState is FeeSelectorState.Content) { + feeState.feeSelectorState + } else { + FeeSelectorState.Loading + }, notifications = persistentListOf(), isPrimaryButtonEnabled = false, ), diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt index d9b92b387d..f0cdd28425 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt @@ -14,7 +14,7 @@ internal class SendFeeStateConverter( override fun convert(value: Unit): SendStates.FeeState { return SendStates.FeeState( - feeSelectorState = FeeSelectorState.Error, + feeSelectorState = FeeSelectorState.Loading, fee = null, notifications = persistentListOf(), rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt index a3ee42ccbb..11423e7c73 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt @@ -1,21 +1,22 @@ package com.tangem.features.send.impl.presentation.ui.send +import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import com.tangem.core.ui.components.RectangleShimmer import com.tangem.core.ui.components.rows.SelectorRowItem import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.utils.BigDecimalFormatter import com.tangem.features.send.impl.R import com.tangem.features.send.impl.presentation.state.SendStates import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState @@ -26,20 +27,12 @@ import com.tangem.features.send.impl.presentation.utils.getFiatReference @Composable internal fun FeeBlock(feeState: SendStates.FeeState, isSuccess: Boolean, onClick: () -> Unit) { - val fee = feeState.fee ?: return - val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return - val (title, icon) = when (feeSelectorState.selectedFee) { - FeeType.Slow -> R.string.common_fee_selector_option_slow to R.drawable.ic_tortoise_24 - FeeType.Market -> R.string.common_fee_selector_option_market to R.drawable.ic_bird_24 - FeeType.Fast -> R.string.common_fee_selector_option_fast to R.drawable.ic_hare_24 - FeeType.Custom -> R.string.common_fee_selector_option_custom to R.drawable.ic_edit_24 - } Column( modifier = Modifier .fillMaxWidth() .clip(TangemTheme.shapes.roundedCornersXMedium) .background(TangemTheme.colors.background.action) - .clickable(enabled = !isSuccess) { onClick() } + .clickable(enabled = !isSuccess && feeState.fee != null) { onClick() } .padding(TangemTheme.dimens.spacing12), ) { Text( @@ -47,17 +40,71 @@ internal fun FeeBlock(feeState: SendStates.FeeState, isSuccess: Boolean, onClick style = TangemTheme.typography.caption2, color = TangemTheme.colors.text.secondary, ) - SelectorRowItem( - titleRes = title, - iconRes = icon, - preDot = getCryptoReference(fee.amount, feeState.isFeeApproximate), - postDot = getFiatReference(fee.amount, feeState.rate, feeState.appCurrency), - ellipsizeOffset = fee.amount.currencySymbol.length, - isSelected = true, - showDivider = false, - paddingValues = PaddingValues(), + + Box( modifier = Modifier.padding(top = TangemTheme.dimens.spacing8), - ) + ) { + val feeSelectorState = feeState.feeSelectorState + val feeAmount = feeState.fee?.amount + val (title, icon) = if (feeSelectorState is FeeSelectorState.Content) { + when (feeSelectorState.selectedFee) { + FeeType.Slow -> R.string.common_fee_selector_option_slow to R.drawable.ic_tortoise_24 + FeeType.Market -> R.string.common_fee_selector_option_market to R.drawable.ic_bird_24 + FeeType.Fast -> R.string.common_fee_selector_option_fast to R.drawable.ic_hare_24 + FeeType.Custom -> R.string.common_fee_selector_option_custom to R.drawable.ic_edit_24 + } + } else { + R.string.common_fee_selector_option_market to R.drawable.ic_bird_24 + } + SelectorRowItem( + titleRes = title, + iconRes = icon, + preDot = getCryptoReference(feeAmount, feeState.isFeeApproximate), + postDot = feeAmount?.let { getFiatReference(it, feeState.rate, feeState.appCurrency) }, + ellipsizeOffset = feeAmount?.currencySymbol?.length, + isSelected = true, + showDivider = false, + paddingValues = PaddingValues(), + ) + FeeLoading(feeSelectorState) + FeeError(feeSelectorState) + } + } +} + +@Composable +private fun BoxScope.FeeLoading(feeSelectorState: FeeSelectorState) { + AnimatedContent( + targetState = feeSelectorState, + label = "Fee Loading State Change", + modifier = Modifier.align(Alignment.CenterEnd), + ) { + if (it == FeeSelectorState.Loading) { + RectangleShimmer( + radius = TangemTheme.dimens.radius3, + modifier = Modifier.size( + height = TangemTheme.dimens.size12, + width = TangemTheme.dimens.size90, + ), + ) + } + } +} + +@Composable +private fun BoxScope.FeeError(feeSelectorState: FeeSelectorState) { + AnimatedContent( + targetState = feeSelectorState, + label = "Fee Error State Change", + modifier = Modifier.align(Alignment.CenterEnd), + ) { + if (it == FeeSelectorState.Error) { + Text( + text = BigDecimalFormatter.EMPTY_BALANCE_SIGN, + color = TangemTheme.colors.text.primary1, + style = TangemTheme.typography.body2, + ) + } } } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/RecipientBlock.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/RecipientBlock.kt index f276edf3c1..0801e63cd6 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/RecipientBlock.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/RecipientBlock.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -40,6 +41,7 @@ internal fun RecipientBlock( .padding(TangemTheme.dimens.spacing12), ) { AddressBlock(recipientState.addressTextField) + MemoBlock(recipientState.memoTextField) } } @@ -70,6 +72,28 @@ private fun AddressBlock(address: SendTextField.RecipientAddress) { } } +@Composable +private fun MemoBlock(memo: SendTextField.RecipientMemo?) { + val showMemo = memo != null && memo.value.isNotBlank() + if (showMemo) { + HorizontalDivider( + color = TangemTheme.colors.icon.inactive, + modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing12), + ) + Text( + text = memo?.label?.resolveReference().orEmpty(), + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.secondary, + ) + Text( + text = memo?.value.orEmpty(), + style = TangemTheme.typography.body2, + color = TangemTheme.colors.text.primary1, + modifier = Modifier.padding(top = TangemTheme.dimens.spacing8), + ) + } +} + // region Preview @Preview @Composable diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index 57dc709ab1..a25f112461 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -359,8 +359,9 @@ internal class SendViewModel @Inject constructor( stateRouter.showSend() } transactionId != null && amount != null && destinationAddress != null -> { + loadFee() uiState = stateFactory.getReadyState(amount, destinationAddress, memo) - stateRouter.showFee() + stateRouter.showSend() updateNotifications() } else -> { @@ -702,6 +703,7 @@ internal class SendViewModel @Inject constructor( if (result == null) { onFeeLoadFailed(isShowStatus, isToNextState) } + updateNotifications() updateFeeNotifications() }.saveIn(feeJobHolder) .invokeOnCompletion { From 94155919f7b75dbe08c2ebe9d6419df05b474649 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 17 Apr 2024 18:30:45 +0100 Subject: [PATCH 07/23] Updated on 2026-08-14 --- .../moonpay/MoonPayService.kt | 2 +- .../deeplink/global/SellCurrencyDeepLink.kt | 2 + .../domain/tokens/model/CryptoCurrency.kt | 3 +- .../viewmodels/TokenDetailsViewModel.kt | 16 ----- .../deeplink/WalletDeepLinksHandler.kt | 59 +++++++++++-------- .../wallet/viewmodels/WalletViewModel.kt | 2 +- 6 files changed, 41 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt index 228273c9bd..c004c38b21 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/moonpay/MoonPayService.kt @@ -135,7 +135,7 @@ class MoonPayService( .appendQueryParameter("apiKey", apiKey) .appendQueryParameter("baseCurrencyCode", moonpayCurrency.currencyCode.uppercase()) .appendQueryParameter("refundWalletAddress", walletAddress) - .appendQueryParameter("redirectURL", "tangem://redirect_sell") + .appendQueryParameter("redirectURL", "tangem://redirect_sell?currency_id=${cryptoCurrency.id.value}") if (isDarkTheme) uri.appendQueryParameter("theme", "dark") diff --git a/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/SellCurrencyDeepLink.kt b/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/SellCurrencyDeepLink.kt index 579c72689a..db28975f63 100644 --- a/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/SellCurrencyDeepLink.kt +++ b/core/deep-links/global/src/main/kotlin/com/tangem/core/deeplink/global/SellCurrencyDeepLink.kt @@ -11,6 +11,7 @@ class SellCurrencyDeepLink(val onReceive: (data: Data) -> Unit) : DeepLink { transactionId = params["transactionId"] ?: return, baseCurrencyAmount = params["baseCurrencyAmount"] ?: return, depositWalletAddress = params["depositWalletAddress"] ?: return, + currencyId = params["currency_id"] ?: return, depositWalletAddressTag = params["depositWalletAddressTag"], ) @@ -21,6 +22,7 @@ class SellCurrencyDeepLink(val onReceive: (data: Data) -> Unit) : DeepLink { val transactionId: String, val baseCurrencyAmount: String, val depositWalletAddress: String, + val currencyId: String, val depositWalletAddressTag: String?, ) } \ No newline at end of file diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrency.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrency.kt index 87015b1305..db909d08f3 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrency.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrency.kt @@ -184,8 +184,9 @@ sealed class CryptoCurrency : Parcelable { } private companion object { + // should use delimiters that could be used in URL not like path or query delimiters const val PREFIX_DELIMITER = '_' - const val SUFFIX_DELIMITER = '#' + const val SUFFIX_DELIMITER = ';' const val DERIVATION_PATH_DELIMITER = 'd' } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index f4c38aca5c..02defbde3a 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -10,7 +10,6 @@ import com.tangem.blockchain.common.address.AddressType import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.core.deeplink.global.BuyCurrencyDeepLink -import com.tangem.core.deeplink.global.SellCurrencyDeepLink import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.extensions.resourceReference @@ -165,7 +164,6 @@ internal class TokenDetailsViewModel @Inject constructor( viewModel = this, deepLinks = listOf( BuyCurrencyDeepLink(::onBuyCurrencyDeepLink), - SellCurrencyDeepLink(::onSellCurrencyDeepLink), ), ) } @@ -175,20 +173,6 @@ internal class TokenDetailsViewModel @Inject constructor( analyticsEventsHandler.send(TokenScreenAnalyticsEvent.Bought(currency.symbol)) } - private fun onSellCurrencyDeepLink(data: SellCurrencyDeepLink.Data) { - sendCurrency( - status = cryptoCurrencyStatus ?: return, - transactionInfo = data.let { - TransactionInfo( - transactionId = it.transactionId, - destinationAddress = it.depositWalletAddress, - amount = it.baseCurrencyAmount, - tag = it.depositWalletAddressTag, - ) - }, - ) - } - override fun onCreate(owner: LifecycleOwner) { analyticsEventsHandler.send( event = TokenScreenAnalyticsEvent.DetailsScreenOpened(token = cryptoCurrency.symbol), diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt index 59e2022b58..3c1e89fbeb 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/deeplink/WalletDeepLinksHandler.kt @@ -8,16 +8,14 @@ import com.tangem.core.deeplink.DeepLinksRegistry import com.tangem.core.deeplink.global.BuyCurrencyDeepLink import com.tangem.core.deeplink.global.SellCurrencyDeepLink import com.tangem.domain.redux.ReduxStateHolder -import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase -import com.tangem.domain.tokens.GetCryptoCurrencyUseCase -import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase -import com.tangem.domain.tokens.GetNetworkCoinStatusUseCase +import com.tangem.domain.tokens.* import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.domain.tokens.legacy.TradeCryptoAction.TransactionInfo import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.models.analytics.TokenScreenAnalyticsEvent import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.models.UserWalletId import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch @@ -29,23 +27,20 @@ internal class WalletDeepLinksHandler @Inject constructor( private val analyticsEventHandler: AnalyticsEventHandler, private val getCryptoCurrencyUseCase: GetCryptoCurrencyUseCase, private val getCryptoCurrencyStatusSyncUseCase: GetCryptoCurrencyStatusSyncUseCase, + private val getCryptoCurrencyStatusesSyncUseCase: GetCryptoCurrencyStatusesSyncUseCase, private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase, private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase, private val reduxStateHolder: ReduxStateHolder, ) { - private var deepLinks: List = emptyList() + private var deepLinksMap = mutableMapOf>() - fun registerForSingleCurrencyWallets(viewModel: ViewModel, userWallet: UserWallet) { - if (userWallet.isMultiCurrency) { - deepLinksRegistry.unregister(deepLinks) - } else { - if (deepLinks.isEmpty()) { - deepLinks = getDeepLinks(userWallet, viewModel.viewModelScope) - } - - deepLinksRegistry.register(deepLinks) + fun registerForWallet(viewModel: ViewModel, userWallet: UserWallet) { + val deepLinks = deepLinksMap.getOrPut(userWallet.walletId) { + getDeepLinks(userWallet, viewModel.viewModelScope) } + deepLinksRegistry.unregisterByIds(deepLinks.map { it.id }) + deepLinksRegistry.register(deepLinks) viewModel.addCloseable { deepLinksRegistry.unregister(deepLinks) @@ -60,20 +55,23 @@ internal class WalletDeepLinksHandler @Inject constructor( } }, ) - val buyCurrencyDeepLink = BuyCurrencyDeepLink( - onReceive = { - scope.launch { - onBuyCurrencyDeepLink(userWallet) - } - }, - ) - return listOf(sellCurrencyDeepLink, buyCurrencyDeepLink) + return buildList { + add(sellCurrencyDeepLink) + if (!userWallet.isMultiCurrency) { + add( + BuyCurrencyDeepLink( + onReceive = { + scope.launch { onBuyCurrencyDeepLink(userWallet) } + }, + ), + ) + } + } } private suspend fun onSellCurrencyDeepLink(userWallet: UserWallet, data: SellCurrencyDeepLink.Data) { - val cryptoCurrencyStatus = getCryptoCurrencyStatusSyncUseCase(userWallet.walletId) - .getOrNull() ?: return + val cryptoCurrencyStatus = findCryptoCurrencyStatus(userWallet, data.currencyId) ?: return val feeCurrencyStatus = getFeePaidCryptoCurrencyStatusSyncUseCase( userWallet.walletId, cryptoCurrencyStatus, @@ -110,6 +108,19 @@ internal class WalletDeepLinksHandler @Inject constructor( analyticsEventHandler.send(TokenScreenAnalyticsEvent.Bought(cryptoCurrency.symbol)) } + private suspend fun findCryptoCurrencyStatus( + userWallet: UserWallet, + currencyIdValue: String, + ): CryptoCurrencyStatus? { + return if (userWallet.isMultiCurrency) { + getCryptoCurrencyStatusesSyncUseCase(userWallet.walletId).getOrNull()?.let { currencies -> + currencies.find { currencyIdValue == it.currency.id.value } + } + } else { + getCryptoCurrencyStatusSyncUseCase(userWallet.walletId).getOrNull() + } + } + private fun sendCoin( userWallet: UserWallet, cryptoCurrencyStatus: CryptoCurrencyStatus, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 63db20714d..369ec32691 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -154,7 +154,7 @@ internal class WalletViewModel @Inject constructor( selectedWalletAnalyticsSender.send(selectedWallet) } - walletDeepLinksHandler.registerForSingleCurrencyWallets( + walletDeepLinksHandler.registerForWallet( viewModel = this, userWallet = selectedWallet, ) From bb4e442b4deec1e797a8a1daef4db2d70f6649b7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 18:27:59 +0500 Subject: [PATCH 08/23] Updated on 2026-08-14 --- .../core/ui/utils/BigDecimalFormatter.kt | 23 +++++++++++++++++++ .../state/confirm/SendNotificationFactory.kt | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt index 42309223b1..b724559114 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt @@ -40,6 +40,29 @@ object BigDecimalFormatter { } } + fun formatCryptoAmountUncapped( + cryptoAmount: BigDecimal?, + cryptoCurrency: CryptoCurrency, + locale: Locale = Locale.getDefault(), + ): String { + if (cryptoAmount == null) return EMPTY_BALANCE_SIGN + + val formatter = NumberFormat.getNumberInstance(locale).apply { + maximumFractionDigits = cryptoCurrency.decimals + minimumFractionDigits = 2 + isGroupingUsed = true + roundingMode = RoundingMode.DOWN + } + + return formatter.format(cryptoAmount).let { + if (cryptoCurrency.symbol.isEmpty()) { + it + } else { + it + "\u2009${cryptoCurrency.symbol}" + } + } + } + fun formatCryptoAmount( cryptoAmount: BigDecimal?, cryptoCurrency: CryptoCurrency, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index eb9fdba3a1..09c9497fed 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -205,7 +205,7 @@ internal class SendNotificationFactory( if (currencyDeposit != null && currencyDeposit > diff) { add( SendNotification.Error.ExistentialDeposit( - BigDecimalFormatter.formatCryptoAmount( + BigDecimalFormatter.formatCryptoAmountUncapped( cryptoAmount = currencyDeposit, cryptoCurrency = cryptoCurrency, ), From 2fbbebf0903938122c9869ec3d4be690500286c3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 18:29:02 +0500 Subject: [PATCH 09/23] Updated on 2026-08-14 --- .../send/impl/presentation/viewmodel/SendViewModel.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index a25f112461..9ae90b3b93 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -24,6 +24,7 @@ import com.tangem.domain.tokens.* import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.repository.CurrencyChecksRepository import com.tangem.domain.tokens.utils.convertToAmount import com.tangem.domain.transaction.error.GetFeeError @@ -407,7 +408,8 @@ internal class SendViewModel @Inject constructor( return if (!isMultiCurrency) { val status = getCryptoCurrencyStatusSyncUseCase(walletId).getOrNull() val address = status?.value?.networkAddress.takeIf { - status?.currency?.network?.id == cryptoCurrency.network.id + status?.currency?.network?.id == cryptoCurrency.network.id && + status.currency.network.derivationPath !is Network.DerivationPath.Custom } address?.let { AvailableWallet( @@ -418,7 +420,8 @@ internal class SendViewModel @Inject constructor( } else { val statuses = getCryptoCurrencyStatusesSyncUseCase(walletId).getOrNull() val walletCurrency = statuses?.firstOrNull { - it.currency.network.id == cryptoCurrency.network.id + it.currency.network.id == cryptoCurrency.network.id && + it.currency.network.derivationPath !is Network.DerivationPath.Custom } val address = walletCurrency?.value?.networkAddress address?.let { From 118b53e224ce5b27953c4d8beedd6918b86c50c0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 18:29:30 +0500 Subject: [PATCH 10/23] Updated on 2026-08-14 --- .../features/send/impl/presentation/viewmodel/SendViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index 9ae90b3b93..a349ecebf5 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -366,8 +366,8 @@ internal class SendViewModel @Inject constructor( updateNotifications() } else -> { - getWalletsAndRecent() uiState = stateFactory.getReadyState() + getWalletsAndRecent() stateRouter.showRecipient() updateNotifications() } From 77e0bd86c6b2e4ce9f7ef2a6dd7589d025d5b176 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 16:37:50 +0200 Subject: [PATCH 11/23] Updated on 2026-08-14 --- core/res/src/main/res/values-ru/strings.xml | 10 +++++----- .../tangem/feature/swap/ui/StateBuilder.kt | 20 +++++++++++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 9f10054ca1..5d5c08ef1a 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -100,7 +100,7 @@ Нет адреса OK Основная карта - Кодовая фраза + Парольная фраза Вставить Подробнее Получить @@ -188,9 +188,9 @@ Tangem предоставляет доступ к обмену через сторонних поставщиков в соответствии с их правилами Выберите провайдера Произошла ошибка. Код: %s - К сожалению обмен указанной пары через выбранного провайдера на данный момент не возможен. Попробуйте совершить обмен позже. (Код: %s) + К сожалению, обмен указанной пары через выбранного провайдера на данный момент невозможен. Попробуйте совершить обмен позже. (Код: %s) Выбранный провайдер не доступен для обмена. Попробуйте позже. (Код: %s) - В данный момент обмен не возможен. Попробуйте позже. (Код: %s) + В данный момент обмен невозможен. Попробуйте позже. (Код: %s) Курс обмена Обмен через %s Чтобы вернуть ваши деньги, посетите сайт провайдера @@ -293,7 +293,7 @@ Ошибка активации Вы добавили одну резервную карту. После того, как процесс будет завершен, Вы больше не сможете добавить карт. Если у Вас есть еще одна карта, добавьте ее в резервную копию. Хотите продолжить? Процесс резервного копирования почти завершен. Вы не можете выйти из него сейчас. - Кодовая фраза — это расширенная функция безопасности, которую используют криптокошельки. Она добавляет дополнительное слово или фразу по вашему выбору к уже существующей seed - фразе, чтобы разблокировать совершенно новый набор адресов. + Парольная фраза — это расширенная функция безопасности, которую используют криптокошельки. Она добавляет дополнительное слово или фразу по вашему выбору к уже существующей seed - фразе, чтобы разблокировать совершенно новый набор адресов. Добавить резервную карту Сканировать карту #%d Создать резервную копию @@ -483,7 +483,7 @@ Возможны задержки по транзакции Из-за ограничений %1$s в одну транзакцию может поместиться только %2$s UTXO. Это означает, что вы можете отправить только %3$s или меньше. Вам нужно уменьшить сумму. Лимит транзакции - Необязательное + Опционально Пожалуйста, совместите свой QR-код с квадратом, чтобы отсканировать его. Убедитесь, что вы сканируете адрес в сети %s. Последние Получатель 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 eaf4ddfa6b..d8edc6401c 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 @@ -646,6 +646,7 @@ internal class StateBuilder( } private fun getWarningForError(dataError: DataError, fromToken: CryptoCurrency): SwapWarning { + val providerErrorMessage = getProviderErrorMessage(dataError) return when (dataError) { is DataError.ExchangeTooSmallAmountError -> SwapWarning.GeneralError( notificationConfig = NotificationConfig( @@ -674,10 +675,16 @@ internal class StateBuilder( } else { resourceReference(R.string.warning_express_refresh_required_title) }, - subtitle = if (dataError is DataError.UnknownError) { - resourceReference(R.string.common_unknown_error) - } else { - resourceReference(R.string.express_error_code, wrappedList(dataError.code.toString())) + subtitle = when { + dataError is DataError.UnknownError -> { + resourceReference(R.string.common_unknown_error) + } + providerErrorMessage != null -> { + providerErrorMessage + } + else -> { + resourceReference(R.string.express_error_code, wrappedList(dataError.code.toString())) + } }, iconResId = R.drawable.img_attention_20, buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( @@ -972,7 +979,7 @@ internal class StateBuilder( return uiState.copy( alert = SwapWarning.GenericWarning( message = if (swapTransactionState is SwapTransactionState.ExpressError) { - getAlertErrorMessage(swapTransactionState.dataError) + getProviderErrorMessage(swapTransactionState.dataError) } else { null }, @@ -987,7 +994,7 @@ internal class StateBuilder( ) } - private fun getAlertErrorMessage(dataError: DataError): TextReference? { + private fun getProviderErrorMessage(dataError: DataError): TextReference? { return when (dataError) { is DataError.SwapsAreUnavailableNowError -> resourceReference( id = R.string.express_error_swap_unavailable, @@ -998,6 +1005,7 @@ internal class StateBuilder( formatArgs = wrappedList(dataError.code), ) is DataError.ExchangeProviderNotActiveError, + is DataError.ExchangeProviderNotFoundError, is DataError.ExchangeProviderNotAvailableError, is DataError.ExchangeProviderProviderInternalError, -> resourceReference( From bcbe14d5613d819820206d4682a9a70b95bed5d2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 20:29:52 +0500 Subject: [PATCH 12/23] Updated on 2026-08-14 --- .../features/send/impl/presentation/viewmodel/SendViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index a349ecebf5..7cde4f3f49 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -797,6 +797,7 @@ internal class SendViewModel @Inject constructor( override fun onAmountReduceClick(reducedAmount: BigDecimal, clazz: Class) { uiState = amountStateFactory.getOnAmountValueChange(reducedAmount.parseBigDecimal(cryptoCurrency.decimals)) uiState = sendNotificationFactory.dismissNotificationState(clazz) + updateNotifications() } override fun onNotificationCancel(clazz: Class) { From 44188b11cd289a7280397ed98c5514ed50a7d86c Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 20:32:06 +0500 Subject: [PATCH 13/23] Updated on 2026-08-14 --- .../state/confirm/SendNotificationFactory.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index 09c9497fed..2f597ec8ae 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -96,17 +96,13 @@ internal class SendNotificationFactory( receivedAmount: BigDecimal, ) { val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() - val coinCryptoCurrencyStatus = coinCryptoCurrencyStatusProvider() val feePaidCryptoCurrencyStatus = feePaidCryptoCurrencyStatusProvider() val cryptoAmount = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO - val coinCryptoAmount = coinCryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO - val showNotification = if (cryptoCurrencyStatus.currency.id == feePaidCryptoCurrencyStatus?.currency?.id) { - receivedAmount > cryptoAmount || feeAmount > coinCryptoAmount - } else { - receivedAmount + feeAmount > cryptoAmount - } + val isCurrentNotFeePaidCurrency = cryptoCurrencyStatus.currency.id != feePaidCryptoCurrencyStatus?.currency?.id + if (isCurrentNotFeePaidCurrency) return + val showNotification = receivedAmount + feeAmount > cryptoAmount if (showNotification) { add(SendNotification.Error.TotalExceedsBalance) } From 7b91047ca19bc382f6e217ad5cadfc67de27bbf6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Apr 2024 18:44:26 +0100 Subject: [PATCH 14/23] Updated on 2026-08-14 --- gradle/dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 56d6351be9..9f6bf1bcfd 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -85,7 +85,7 @@ leakcanary = "2.13" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_5.9-600" +tangemBlockchainSdk = "release-app_5.9-602" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_5.9-343" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From 7fc28913ae8b2d907af8a0c120b3b2d308941c6a Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 19 Apr 2024 16:17:21 +0500 Subject: [PATCH 15/23] Updated on 2026-08-14 --- .../state/confirm/SendNotificationFactory.kt | 13 ++++--------- .../presentation/state/fee/FeeCalculation.kt | 18 +++++++++++------- .../presentation/viewmodel/SendViewModel.kt | 3 ++- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index 2f597ec8ae..e17313e475 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -20,6 +20,7 @@ import com.tangem.features.send.impl.presentation.analytics.SendAnalyticEvents import com.tangem.features.send.impl.presentation.state.* import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState import com.tangem.features.send.impl.presentation.state.fee.FeeType +import com.tangem.features.send.impl.presentation.state.fee.checkIfFeeTooHigh import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents import com.tangem.lib.crypto.BlockchainUtils.isDogecoin import com.tangem.utils.Provider @@ -31,7 +32,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import java.math.BigDecimal -import java.math.BigInteger @Suppress("LongParameterList") internal class SendNotificationFactory( @@ -277,13 +277,9 @@ internal class SendNotificationFactory( private fun MutableList.addTooHighNotification(feeSelectorState: FeeSelectorState) { if (feeSelectorState !is FeeSelectorState.Content) return - val multipleFees = feeSelectorState.fees as? TransactionFee.Choosable ?: return - val highValue = multipleFees.priority.amount.value ?: return - val customAmount = feeSelectorState.customValues.firstOrNull() ?: return - val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) - val diff = (customValue / highValue).toBigInteger() - if (feeSelectorState.selectedFee == FeeType.Custom && diff > FEE_MAX_DIFF) { - add(SendNotification.Warning.TooHigh(diff.toString())) + + checkIfFeeTooHigh(feeSelectorState) { diff -> + add(SendNotification.Warning.TooHigh(diff)) } } @@ -366,6 +362,5 @@ internal class SendNotificationFactory( companion object { private const val DOGECOIN_MINIMUM = "0.01" - internal val FEE_MAX_DIFF = BigInteger("5") } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt index 57e567a586..31307124fd 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeCalculation.kt @@ -1,10 +1,12 @@ package com.tangem.features.send.impl.presentation.state.fee import com.tangem.blockchain.common.transaction.TransactionFee +import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.core.ui.utils.parseToBigDecimal import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.send.impl.presentation.state.SendUiState -import com.tangem.features.send.impl.presentation.state.confirm.SendNotificationFactory +import java.math.BigDecimal +import java.math.RoundingMode /** * Check if sending amount with fee is greater than balance @@ -32,14 +34,16 @@ internal fun checkIfFeeTooLow(state: SendUiState): Boolean { /** * Check if custom fee is too high */ -internal fun checkIfFeeTooHigh(state: SendUiState, onShow: (String) -> Unit): Boolean { - val feeSelectorState = state.feeState?.feeSelectorState as? FeeSelectorState.Content ?: return false +internal fun checkIfFeeTooHigh(feeSelectorState: FeeSelectorState.Content, onShow: (String) -> Unit): Boolean { val multipleFees = feeSelectorState.fees as? TransactionFee.Choosable ?: return false val highValue = multipleFees.priority.amount.value ?: return false val customAmount = feeSelectorState.customValues.firstOrNull() ?: return false val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals) - val diff = (customValue / highValue).toBigInteger() - val isShow = feeSelectorState.selectedFee == FeeType.Custom && diff > SendNotificationFactory.FEE_MAX_DIFF - if (isShow) onShow(diff.toString()) + val diff = customValue / highValue + val isShow = feeSelectorState.selectedFee == FeeType.Custom && diff > FEE_MAX_DIFF + if (isShow) onShow(diff.parseBigDecimal(ZERO_DECIMALS, RoundingMode.HALF_UP)) return isShow -} \ No newline at end of file +} + +private val FEE_MAX_DIFF = BigDecimal("5") +private const val ZERO_DECIMALS = 0 \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index 7cde4f3f49..93300b23c2 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -526,8 +526,9 @@ internal class SendViewModel @Inject constructor( ) return true } + val feeSelectorState = uiState.feeState?.feeSelectorState as? FeeSelectorState.Content ?: return false return checkIfFeeTooHigh( - state = uiState, + feeSelectorState = feeSelectorState, onShow = { diff -> uiState = eventStateFactory.getFeeTooHighAlert( diff = diff, From 9ee6c1d9538e922f4d6a8f178ee7e956ad76fd65 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 19 Apr 2024 17:13:23 +0500 Subject: [PATCH 16/23] Updated on 2026-08-14 --- .../state/confirm/SendNotificationFactory.kt | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index e17313e475..3ad03b434c 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -24,7 +24,6 @@ import com.tangem.features.send.impl.presentation.state.fee.checkIfFeeTooHigh import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents import com.tangem.lib.crypto.BlockchainUtils.isDogecoin import com.tangem.utils.Provider -import com.tangem.utils.isNullOrZero import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -108,23 +107,6 @@ internal class SendNotificationFactory( } } - private fun MutableList.addMinimumAmountErrorNotification( - feeAmount: BigDecimal, - receivedAmount: BigDecimal, - ) { - val coinCryptoCurrencyStatus = coinCryptoCurrencyStatusProvider() - - val totalAmount = feeAmount + receivedAmount - val balance = coinCryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO - - if (isDogecoin(coinCryptoCurrencyStatus.currency.network.id.value)) { - val minimum = BigDecimal(DOGECOIN_MINIMUM) - if (receivedAmount < minimum || balance - totalAmount < minimum) { - add(SendNotification.Error.MinimumAmountError(DOGECOIN_MINIMUM)) - } - } - } - // todo temporarily disabling notification // private suspend fun MutableList.addReserveAmountErrorNotification(recipientAddress: String) { // val userWalletId = userWalletProvider().walletId @@ -236,6 +218,20 @@ internal class SendNotificationFactory( } } + private fun MutableList.addMinimumAmountErrorNotification( + feeAmount: BigDecimal, + receivedAmount: BigDecimal, + ) { + val coinCryptoCurrencyStatus = coinCryptoCurrencyStatusProvider() + val minimum = BigDecimal(DOGECOIN_MINIMUM) + + val isDogecoin = isDogecoin(coinCryptoCurrencyStatus.currency.network.id.value) + val isExceedDustLimit = checkDustLimits(feeAmount, receivedAmount, minimum) + if (isDogecoin && isExceedDustLimit) { + add(SendNotification.Error.MinimumAmountError(DOGECOIN_MINIMUM)) + } + } + private suspend fun MutableList.addDustWarningNotification( feeAmount: BigDecimal, receivedAmount: BigDecimal, @@ -244,18 +240,12 @@ internal class SendNotificationFactory( val dustValue = currencyChecksRepository.getDustValue( userWalletProvider().walletId, cryptoCurrencyStatus.currency.network, - ) - val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO - if (dustValue != null && !balance.isNullOrZero() && receivedAmount < balance) { - val totalAmount = feeAmount + receivedAmount - val change = balance - totalAmount - val isChangeLowerThanDust = change < dustValue && change != BigDecimal.ZERO - val isShowWarning = receivedAmount < dustValue || isChangeLowerThanDust - if (isShowWarning) { - add( - SendNotification.Error.MinimumAmountError(dustValue.toPlainString()), - ) - } + ) ?: return + + if (checkDustLimits(feeAmount, receivedAmount, dustValue)) { + add( + SendNotification.Error.MinimumAmountError(dustValue.toPlainString()), + ) } } @@ -360,6 +350,16 @@ internal class SendNotificationFactory( return Blockchain.fromNetworkId(this.currency.network.backendId) == Blockchain.Arbitrum } + private fun checkDustLimits(feeAmount: BigDecimal, receivedAmount: BigDecimal, dustValue: BigDecimal): Boolean { + val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() + val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO + + val totalAmount = feeAmount + receivedAmount + val change = balance - totalAmount + val isChangeLowerThanDust = change < dustValue && change > BigDecimal.ZERO + return receivedAmount < dustValue || isChangeLowerThanDust + } + companion object { private const val DOGECOIN_MINIMUM = "0.01" } From 4a9062821bb92c489135e28329f4c9d227b36f00 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 19 Apr 2024 16:53:39 +0300 Subject: [PATCH 17/23] Updated on 2026-08-14 --- .../segmentedbutton/SegmentedButton.kt | 14 +++++---- .../wallet2/ui/YourSeedPhraseScreen.kt | 2 +- .../impl/presentation/state/SendUiState.kt | 1 + .../state/amount/SendAmountStateConverter.kt | 29 +++++++++---------- .../previewdata/AmountStatePreviewData.kt | 1 + .../presentation/ui/amount/AmountButtons.kt | 2 ++ .../ui/amount/SendAmountContent.kt | 1 + 7 files changed, 27 insertions(+), 23 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt index 712fc8cb52..f3cbfca76d 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/segmentedbutton/SegmentedButton.kt @@ -47,14 +47,15 @@ inline fun SegmentedButtons( selectedColor: Color = TangemTheme.colors.background.action, dividerColor: Color = TangemTheme.colors.stroke.primary, showIndication: Boolean = true, - selectedItem: T? = null, + initialSelectedItem: T? = null, + isEnabled: Boolean = true, crossinline buttonContent: @Composable (T) -> Unit, ) { if (config.isEmpty() || config.size == 1) return - var selected by remember { - val selectedIndex = if (selectedItem == null) 0 else config.indexOf(selectedItem) - mutableIntStateOf(selectedIndex) + var selectedIndex by remember { + val index = if (initialSelectedItem == null) 0 else config.indexOf(initialSelectedItem) + mutableIntStateOf(index) } Row( @@ -69,7 +70,7 @@ inline fun SegmentedButtons( val rightRadius = if (index == config.lastIndex) TangemTheme.dimens.radius26 else TangemTheme.dimens.radius0 val animateColor by animateColorAsState( - targetValue = if (index == selected) selectedColor else color, + targetValue = if (index == selectedIndex) selectedColor else color, label = "Segmented Button Selected Color Animation", animationSpec = spring(stiffness = Spring.StiffnessMedium), ) @@ -86,11 +87,12 @@ inline fun SegmentedButtons( ), ) .clickable( + enabled = isEnabled, interactionSource = remember { MutableInteractionSource() }, indication = if (showIndication) LocalIndication.current else null, ) { + selectedIndex = index onClick(config[index]) - selected = index }, ) { buttonContent.invoke(config[index]) diff --git a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt index 94f072a0ac..609e2df784 100644 --- a/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt +++ b/features/onboarding/src/main/java/com/tangem/feature/onboarding/presentation/wallet2/ui/YourSeedPhraseScreen.kt @@ -93,7 +93,7 @@ private fun SegmentSeedBlock(state: SegmentSeedState, modifier: Modifier = Modif SegmentedButtons( modifier = modifier.padding(horizontal = TangemTheme.dimens.spacing76), config = state.seedSegments, - selectedItem = state.selectedSeedType, + initialSelectedItem = state.selectedSeedType, onClick = { state.onSelectType(it) }, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt index 586c55c978..eb0e05e900 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt @@ -48,6 +48,7 @@ internal sealed class SendStates { val walletBalance: TextReference, val tokenIconState: TokenIconState, val segmentedButtonConfig: PersistentList, + val isSegmentedButtonsEnabled: Boolean, val amountTextField: SendTextField.AmountField, val notifications: ImmutableList, val appCurrencyCode: String, diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt index f06a20bf48..65c85ac2e6 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/amount/SendAmountStateConverter.kt @@ -42,22 +42,19 @@ internal class SendAmountStateConverter( isFeeLoading = false, appCurrencyCode = appCurrency.code, subtractedFee = null, - segmentedButtonConfig = if (status.value.fiatRate.isNullOrZero()) { - persistentListOf() - } else { - persistentListOf( - SendAmountSegmentedButtonsConfig( - title = stringReference(status.currency.symbol), - iconState = iconStateConverter.convert(status), - isFiat = false, - ), - SendAmountSegmentedButtonsConfig( - title = stringReference(appCurrency.code), - iconUrl = appCurrency.iconSmallUrl, - isFiat = true, - ), - ) - }, + segmentedButtonConfig = persistentListOf( + SendAmountSegmentedButtonsConfig( + title = stringReference(status.currency.symbol), + iconState = iconStateConverter.convert(status), + isFiat = false, + ), + SendAmountSegmentedButtonsConfig( + title = stringReference(appCurrency.code), + iconUrl = appCurrency.iconSmallUrl, + isFiat = true, + ), + ), + isSegmentedButtonsEnabled = !status.value.fiatRate.isNullOrZero(), ) } } \ No newline at end of file diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt index 91dbbde9bf..c301029957 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/AmountStatePreviewData.kt @@ -49,6 +49,7 @@ internal object AmountStatePreviewData { isError = false, error = TextReference.EMPTY, ), + isSegmentedButtonsEnabled = true, ) val fiatAmountState = amountState.copy( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountButtons.kt index 00af1e90e7..26d41708cc 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountButtons.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/AmountButtons.kt @@ -29,6 +29,7 @@ internal fun LazyListScope.buttons( segmentedButtonConfig: PersistentList, clickIntents: SendClickIntents, isMaxButtonEnabled: Boolean, + isSegmentedButtonsEnabled: Boolean, ) { item( key = AMOUNT_BUTTONS_KEY, @@ -48,6 +49,7 @@ internal fun LazyListScope.buttons( hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) clickIntents.onCurrencyChangeClick(it.isFiat) }, + isEnabled = isSegmentedButtonsEnabled, ) { SendAmountCurrencyButton(it) } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt index 0f5b6493e8..fb9d2df22c 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/amount/SendAmountContent.kt @@ -36,6 +36,7 @@ internal fun SendAmountContent( segmentedButtonConfig = amountState.segmentedButtonConfig, clickIntents = clickIntents, isMaxButtonEnabled = !amountState.isFeeLoading, + isSegmentedButtonsEnabled = amountState.isSegmentedButtonsEnabled, ) notifications(amountState.notifications) } From 19c80763c3b009a81bb2bc115b6310eae763fd27 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 22 Apr 2024 10:57:22 +0300 Subject: [PATCH 18/23] Updated on 2026-08-14 --- .../components/currency/fiaticon/FiatIcon.kt | 17 +++++++-- .../CryptoCurrencyToIconStateConverter.kt | 37 +++++++++++++++---- .../state/amount/SendAmountStateConverter.kt | 9 ++++- .../presentation/ui/amount/AmountButtons.kt | 24 ++++++------ 4 files changed, 64 insertions(+), 23 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/currency/fiaticon/FiatIcon.kt b/core/ui/src/main/java/com/tangem/core/ui/components/currency/fiaticon/FiatIcon.kt index 3255b50af7..76d5c9d094 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/currency/fiaticon/FiatIcon.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/currency/fiaticon/FiatIcon.kt @@ -4,11 +4,16 @@ import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.Dp import com.tangem.core.ui.R import com.tangem.core.ui.components.currency.DefaultCurrencyIcon +private const val GRAY_SCALE_SATURATION = 0f +private const val GRAY_SCALE_ALPHA = 0.4f + /** * Simple icon from network * @@ -20,16 +25,19 @@ import com.tangem.core.ui.components.currency.DefaultCurrencyIcon fun FiatIcon( url: String?, size: Dp, + isGrayscale: Boolean, modifier: Modifier = Modifier, @DrawableRes fallbackResId: Int = R.drawable.ic_shape_circle, ) { val iconData: Any = if (url.isNullOrBlank()) fallbackResId else url + val alpha = if (isGrayscale) GRAY_SCALE_ALPHA else 1f + val colorFilter = if (isGrayscale) GrayscaleColorFilter else null DefaultCurrencyIcon( iconData = iconData, size = size, - alpha = 1f, - colorFilter = null, + alpha = alpha, + colorFilter = colorFilter, errorIcon = { Image( painter = painterResource(id = fallbackResId), @@ -38,4 +46,7 @@ fun FiatIcon( }, modifier = modifier, ) -} \ No newline at end of file +} + +private val GrayscaleColorFilter: ColorFilter + get() = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(GRAY_SCALE_SATURATION) }) \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt index 19703e82b9..48d6dabf99 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt @@ -20,6 +20,21 @@ class CryptoCurrencyToIconStateConverter : Converter getIconStateForCoin( + coin = currency, + isUnreachable = value.value.isError, + forceGrayscale = true, + ) + is CryptoCurrency.Token -> getIconStateForToken( + token = currency, + isErrorStatus = value.value.isError, + forceGrayscale = true, + ) + } + } + fun convert(currency: CryptoCurrency): TokenIconState { return when (currency) { is CryptoCurrency.Coin -> getIconStateForCoin(currency, isUnreachable = false) @@ -27,18 +42,26 @@ class CryptoCurrencyToIconStateConverter : Converter Date: Mon, 22 Apr 2024 14:19:13 +0300 Subject: [PATCH 19/23] Updated on 2026-08-14 --- .../converters/AnalyticsErrorConverter.kt | 2 +- .../tap/di/domain/TransactionDomainModule.kt | 12 ++++-- .../redux/middlewares/RequestFeeMiddleware.kt | 2 +- .../send/redux/middlewares/SendMiddleware.kt | 2 +- domain/demo/build.gradle.kts | 1 + .../domain}/demo/DemoTransactionSender.kt | 2 +- .../transaction/error/SendTransactionError.kt | 4 +- .../transaction/usecase/GetFeeUseCase.kt | 37 ++++++++++++++---- .../usecase/SendTransactionUseCase.kt | 38 +++++++++++++++++-- .../presentation/viewmodel/SendViewModel.kt | 2 +- .../swap/domain/di/SwapDomainModule.kt | 5 ++- 11 files changed, 82 insertions(+), 25 deletions(-) rename {app/src/main/java/com/tangem/tap/features => domain/demo/src/main/java/com/tangem/domain}/demo/DemoTransactionSender.kt (98%) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/AnalyticsErrorConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/AnalyticsErrorConverter.kt index b8e9b2e458..4f32eee854 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/AnalyticsErrorConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/AnalyticsErrorConverter.kt @@ -2,8 +2,8 @@ package com.tangem.tap.common.analytics.converters import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.common.core.TangemSdkError +import com.tangem.domain.demo.DemoTransactionSender import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.features.demo.DemoTransactionSender import com.tangem.utils.converter.Converter /** diff --git a/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt index 5fc760156f..bf4f00059e 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt @@ -1,7 +1,7 @@ package com.tangem.tap.di.domain import com.tangem.domain.card.repository.CardSdkConfigRepository -import com.tangem.domain.demo.IsDemoCardUseCase +import com.tangem.domain.demo.DemoConfig import com.tangem.domain.transaction.FeeRepository import com.tangem.domain.transaction.TransactionRepository import com.tangem.domain.transaction.usecase.CreateTransactionUseCase @@ -22,20 +22,24 @@ internal object TransactionDomainModule { @Provides @ViewModelScoped fun provideGetFeeUseCase(walletManagersFacade: WalletManagersFacade): GetFeeUseCase { - return GetFeeUseCase(walletManagersFacade) + return GetFeeUseCase( + walletManagersFacade = walletManagersFacade, + demoConfig = DemoConfig(), + ) } @Provides @ViewModelScoped fun provideSendTransactionUseCase( - isDemoCardUseCase: IsDemoCardUseCase, cardSdkConfigRepository: CardSdkConfigRepository, transactionRepository: TransactionRepository, + walletManagersFacade: WalletManagersFacade, ): SendTransactionUseCase { return SendTransactionUseCase( - isDemoCardUseCase = isDemoCardUseCase, + demoConfig = DemoConfig(), cardSdkConfigRepository = cardSdkConfigRepository, transactionRepository = transactionRepository, + walletManagersFacade = walletManagersFacade, ) } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt index 2cb96aa486..cfdcf74a19 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/RequestFeeMiddleware.kt @@ -7,7 +7,7 @@ import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.blockchain.extensions.Result import com.tangem.common.extensions.isZero import com.tangem.tap.common.redux.AppState -import com.tangem.tap.features.demo.DemoTransactionSender +import com.tangem.domain.demo.DemoTransactionSender import com.tangem.tap.features.demo.isDemoCard import com.tangem.tap.features.send.redux.AmountActionUi import com.tangem.tap.features.send.redux.FeeAction diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index dd10c08389..e85db98c7b 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -31,7 +31,7 @@ import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TangemSigner import com.tangem.tap.domain.TapError import com.tangem.tap.domain.configurable.warningMessage.WarningMessage -import com.tangem.tap.features.demo.DemoTransactionSender +import com.tangem.domain.demo.DemoTransactionSender import com.tangem.tap.features.demo.isDemoCard import com.tangem.tap.features.send.redux.* import com.tangem.tap.features.send.redux.FeeAction.RequestFee diff --git a/domain/demo/build.gradle.kts b/domain/demo/build.gradle.kts index f0c56e2a73..a9e6de5249 100644 --- a/domain/demo/build.gradle.kts +++ b/domain/demo/build.gradle.kts @@ -10,4 +10,5 @@ android { dependencies { implementation(deps.tangem.blockchain) + implementation(deps.tangem.card.core) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoTransactionSender.kt b/domain/demo/src/main/java/com/tangem/domain/demo/DemoTransactionSender.kt similarity index 98% rename from app/src/main/java/com/tangem/tap/features/demo/DemoTransactionSender.kt rename to domain/demo/src/main/java/com/tangem/domain/demo/DemoTransactionSender.kt index faecf5aac1..e98373f775 100644 --- a/app/src/main/java/com/tangem/tap/features/demo/DemoTransactionSender.kt +++ b/domain/demo/src/main/java/com/tangem/domain/demo/DemoTransactionSender.kt @@ -1,4 +1,4 @@ -package com.tangem.tap.features.demo +package com.tangem.domain.demo import com.tangem.blockchain.common.* import com.tangem.blockchain.common.transaction.Fee diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/error/SendTransactionError.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/error/SendTransactionError.kt index 22b7991290..3f5f7485d4 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/error/SendTransactionError.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/error/SendTransactionError.kt @@ -4,7 +4,7 @@ import com.tangem.core.ui.extensions.TextReference sealed class SendTransactionError { - object DemoCardError : SendTransactionError() + data object DemoCardError : SendTransactionError() data class DataError(val message: String?) : SendTransactionError() @@ -12,7 +12,7 @@ sealed class SendTransactionError { data class BlockchainSdkError(val code: Int, val message: String?) : SendTransactionError() - object UserCancelledError : SendTransactionError() + data object UserCancelledError : SendTransactionError() data class CreateAccountUnderfunded(val amount: String) : SendTransactionError() diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetFeeUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetFeeUseCase.kt index ae697ceb08..2f113a02a0 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetFeeUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetFeeUseCase.kt @@ -6,10 +6,12 @@ import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Token import com.tangem.blockchain.extensions.Result +import com.tangem.domain.demo.DemoConfig +import com.tangem.domain.demo.DemoTransactionSender import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.walletmanager.WalletManagersFacade -import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.domain.wallets.models.UserWallet import java.math.BigDecimal /** @@ -17,23 +19,31 @@ import java.math.BigDecimal */ class GetFeeUseCase( private val walletManagersFacade: WalletManagersFacade, + private val demoConfig: DemoConfig, ) { suspend operator fun invoke( amount: BigDecimal, destination: String, - userWalletId: UserWalletId, + userWallet: UserWallet, cryptoCurrency: CryptoCurrency, ) = either { catch( block = { - val result = requireNotNull( - walletManagersFacade.getFee( - amount = convertCryptoCurrencyToAmount(cryptoCurrency, amount), + val amountData = convertCryptoCurrencyToAmount(cryptoCurrency, amount) + + val result = if (demoConfig.isDemoCardId(userWallet.scanResponse.card.cardId)) { + demoTransactionSender(userWallet, cryptoCurrency).getFee( + amount = amountData, destination = destination, - userWalletId = userWalletId, + ) + } else { + walletManagersFacade.getFee( + amount = amountData, + destination = destination, + userWalletId = userWallet.walletId, network = cryptoCurrency.network, - ), - ) { "Fee is null" } + ) ?: error("Fee is null") + } val maybeFee = when (result) { is Result.Success -> result.data @@ -47,6 +57,17 @@ class GetFeeUseCase( ) } + private suspend fun demoTransactionSender( + userWallet: UserWallet, + cryptoCurrency: CryptoCurrency, + ): DemoTransactionSender { + return DemoTransactionSender( + walletManagersFacade + .getOrCreateWalletManager(userWallet.walletId, cryptoCurrency.network) + ?: error("WalletManager is null"), + ) + } + private fun convertCryptoCurrencyToAmount(cryptoCurrency: CryptoCurrency, amount: BigDecimal) = Amount( currencySymbol = cryptoCurrency.symbol, value = amount, diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt index d2c9cbd085..379d90d4be 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/SendTransactionUseCase.kt @@ -5,6 +5,7 @@ import arrow.core.left import arrow.core.right import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.blockchain.common.TransactionData +import com.tangem.blockchain.common.TransactionSigner import com.tangem.blockchain.extensions.SimpleResult import com.tangem.blockchain.network.ResultChecker import com.tangem.common.core.TangemSdkError @@ -12,20 +13,23 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.TapWorkarounds.isStart2Coin -import com.tangem.domain.demo.IsDemoCardUseCase +import com.tangem.domain.demo.DemoConfig +import com.tangem.domain.demo.DemoTransactionSender import com.tangem.domain.tokens.model.Network import com.tangem.domain.transaction.R import com.tangem.domain.transaction.TransactionRepository import com.tangem.domain.transaction.error.SendTransactionError import com.tangem.domain.transaction.error.SendTransactionError.Companion.USER_CANCELLED_ERROR_CODE +import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWallet import com.tangem.sdk.extensions.localizedDescriptionRes import com.tangem.utils.toFormattedString class SendTransactionUseCase( - private val isDemoCardUseCase: IsDemoCardUseCase, + private val demoConfig: DemoConfig, private val cardSdkConfigRepository: CardSdkConfigRepository, private val transactionRepository: TransactionRepository, + private val walletManagersFacade: WalletManagersFacade, ) { suspend operator fun invoke( txData: TransactionData, @@ -39,8 +43,13 @@ class SendTransactionUseCase( cardSdkConfigRepository.setLinkedTerminal(false) } val sendResult = try { - if (isDemoCardUseCase(cardId = userWallet.cardId)) { - SendTransactionError.DemoCardError.left() + if (demoConfig.isDemoCardId(cardId = userWallet.cardId)) { + sendDemo( + userWallet = userWallet, + network = network, + transactionData = txData, + signer = signer, + ) } else { transactionRepository.sendTransaction( txData = txData, @@ -66,6 +75,27 @@ class SendTransactionUseCase( ) } + private suspend fun sendDemo( + userWallet: UserWallet, + network: Network, + transactionData: TransactionData, + signer: TransactionSigner, + ): Either { + val demoTransactionSender = DemoTransactionSender( + walletManagersFacade + .getOrCreateWalletManager(userWallet.walletId, network) + ?: error("WalletManager is null"), + ) + + val result = demoTransactionSender.send(transactionData = transactionData, signer = signer) + + return if (result is SimpleResult.Failure && result.error.customMessage.contains(DemoTransactionSender.ID)) { + SendTransactionError.DemoCardError.left() + } else { + result.right() + } + } + private fun handleError(result: SimpleResult.Failure): SendTransactionError { if (ResultChecker.isNetworkError(result)) { return SendTransactionError.NetworkError( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt index 93300b23c2..77708a0eda 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/viewmodel/SendViewModel.kt @@ -741,7 +741,7 @@ internal class SendViewModel @Inject constructor( return getFeeUseCase.invoke( amount = amount, destination = recipientState.addressTextField.value, - userWalletId = userWalletId, + userWallet = userWallet, cryptoCurrency = cryptoCurrency, ) } diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt index 196d529e7b..afb2f253a4 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt @@ -126,14 +126,15 @@ class SwapDomainModule { @Provides @Singleton fun provideSendTransactionUseCase( - @SwapScope isDemoCardUseCase: IsDemoCardUseCase, cardSdkConfigRepository: CardSdkConfigRepository, transactionRepository: TransactionRepository, + walletManagersFacade: WalletManagersFacade, ): SendTransactionUseCase { return SendTransactionUseCase( - isDemoCardUseCase = isDemoCardUseCase, + demoConfig = DemoConfig(), cardSdkConfigRepository = cardSdkConfigRepository, transactionRepository = transactionRepository, + walletManagersFacade = walletManagersFacade, ) } From 4c0e92ffc6a80c035a901311cfe64f6a5db53547 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 22 Apr 2024 18:24:23 +0300 Subject: [PATCH 20/23] Updated on 2026-08-14 --- .../ui/components/transactions/TransactionDoneTitle.kt | 8 ++++++-- .../src/main/java/com/tangem/core/ui/utils/DateUtils.kt | 2 +- .../state/recipient/SendRecipientHistoryListConverter.kt | 4 ++-- .../factory/TokenDetailsSwapTransactionsStateConverter.kt | 4 ++-- .../txhistory/TokenDetailsTxHistoryItemFlowConverter.kt | 6 +++--- .../transformers/converter/TxHistoryItemFlowConverter.kt | 6 +++--- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TransactionDoneTitle.kt b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TransactionDoneTitle.kt index 2adcbdc369..6f23701fea 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TransactionDoneTitle.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/transactions/TransactionDoneTitle.kt @@ -16,7 +16,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.tangem.core.ui.R import com.tangem.core.ui.res.TangemTheme -import com.tangem.core.ui.utils.toDateFormat +import com.tangem.core.ui.utils.DateTimeFormatters import com.tangem.core.ui.utils.toTimeFormat /** @@ -47,7 +47,11 @@ fun TransactionDoneTitle(@StringRes titleRes: Int, date: Long, modifier: Modifie .padding(top = TangemTheme.dimens.spacing16), ) Text( - text = stringResource(id = R.string.send_date_format, date.toDateFormat(), date.toTimeFormat()), + text = stringResource( + id = R.string.send_date_format, + date.toTimeFormat(DateTimeFormatters.dateFormatter), + date.toTimeFormat(), + ), style = TangemTheme.typography.body2, color = TangemTheme.colors.text.tertiary, modifier = Modifier diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/DateUtils.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/DateUtils.kt index 8d596fc41f..bc2560f6e9 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/utils/DateUtils.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/utils/DateUtils.kt @@ -11,7 +11,7 @@ import org.joda.time.format.DateTimeFormatter * If [this] timestamp is today or yesterday, returns relative date, * otherwise returns formatting date. */ -fun Long.toDateFormat(formatter: DateTimeFormatter = DateTimeFormatters.dateFormatter): String { +fun Long.toDateFormatWithTodayYesterday(formatter: DateTimeFormatter = DateTimeFormatters.dateFormatter): String { val localDate = DateTime(this, DateTimeZone.getDefault()) return if (localDate.isToday() || localDate.isYesterday()) { DateUtils.getRelativeTimeSpanString( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientHistoryListConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientHistoryListConverter.kt index f6ccb6ba98..3b555a7e21 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientHistoryListConverter.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/recipient/SendRecipientHistoryListConverter.kt @@ -4,7 +4,7 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.utils.DateTimeFormatters -import com.tangem.core.ui.utils.toDateFormat +import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday import com.tangem.core.ui.utils.toTimeFormat import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus @@ -81,7 +81,7 @@ internal class SendRecipientHistoryListConverter( } private fun TxHistoryItem.extractTimestamp(): TextReference { - val date = timestampInMillis.toDateFormat( + val date = timestampInMillis.toDateFormatWithTodayYesterday( formatter = DateTimeFormatters.dateDDMMYYYY, ) val time = timestampInMillis.toTimeFormat() diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt index d5445e3d1a..55e6cba9b0 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt @@ -4,7 +4,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.components.currency.tokenicon.converter.CryptoCurrencyToIconStateConverter import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.utils.BigDecimalFormatter -import com.tangem.core.ui.utils.toDateFormat +import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday import com.tangem.core.ui.utils.toTimeFormat import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrency @@ -71,7 +71,7 @@ internal class TokenDetailsSwapTransactionsStateConverter( txUrl = transaction.status?.txExternalUrl, txExternalId = transaction.status?.txExternalId, timestamp = TextReference.Str( - "${timestamp.toDateFormat()}, ${timestamp.toTimeFormat()}", + "${timestamp.toDateFormatWithTodayYesterday()}, ${timestamp.toTimeFormat()}", ), fiatSymbol = appCurrency.symbol, statuses = getStatuses(transaction.status?.status), diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt index 9fb6df70b1..6a8bc163c7 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt @@ -4,7 +4,7 @@ import androidx.paging.* import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.components.transactions.state.TxHistoryState.TxHistoryItemState -import com.tangem.core.ui.utils.toDateFormat +import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents @@ -68,7 +68,7 @@ internal class TokenDetailsTxHistoryItemFlowConverter( // Use raw timestamp to get date // If [afterDate] is the first transaction in the flow, add the group title - val afterDate = after.getTimestamp()?.toDateFormat() ?: return@insertSeparators null + val afterDate = after.getTimestamp()?.toDateFormatWithTodayYesterday() ?: return@insertSeparators null if (before is TxHistoryItemState.Title) { return@insertSeparators TxHistoryItemState.GroupTitle( title = afterDate, @@ -80,7 +80,7 @@ internal class TokenDetailsTxHistoryItemFlowConverter( * If [beforeDate] is not equals to [afterDate], then [afterDate] is first transaction in * the new group */ - val beforeDate = before.getTimestamp()?.toDateFormat() ?: return@insertSeparators null + val beforeDate = before.getTimestamp()?.toDateFormatWithTodayYesterday() ?: return@insertSeparators null return@insertSeparators if (beforeDate != afterDate) { TxHistoryItemState.GroupTitle( title = afterDate, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemFlowConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemFlowConverter.kt index 62c49d5586..b24e902bfa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemFlowConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemFlowConverter.kt @@ -4,7 +4,7 @@ import androidx.paging.* import com.tangem.core.ui.components.transactions.state.TransactionState import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.components.transactions.state.TxHistoryState.TxHistoryItemState -import com.tangem.core.ui.utils.toDateFormat +import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents import com.tangem.utils.converter.Converter import kotlinx.coroutines.CoroutineScope @@ -50,7 +50,7 @@ internal class TxHistoryItemFlowConverter( // Use raw timestamp to get date // If [afterDate] is the first transaction in the flow, add the group title - val afterDate = after.getTimestamp()?.toDateFormat() ?: return@insertSeparators null + val afterDate = after.getTimestamp()?.toDateFormatWithTodayYesterday() ?: return@insertSeparators null if (before is TxHistoryItemState.Title) { return@insertSeparators TxHistoryItemState.GroupTitle(afterDate, itemKey = UUID.randomUUID().toString()) } @@ -59,7 +59,7 @@ internal class TxHistoryItemFlowConverter( * If [beforeDate] is not equals to [afterDate], then [afterDate] is first transaction in * the new group */ - val beforeDate = before.getTimestamp()?.toDateFormat() ?: return@insertSeparators null + val beforeDate = before.getTimestamp()?.toDateFormatWithTodayYesterday() ?: return@insertSeparators null return@insertSeparators if (beforeDate != afterDate) { TxHistoryItemState.GroupTitle(afterDate, itemKey = UUID.randomUUID().toString()) } else { From ee3d9ff43b3e37883c5d440996c70be33652a5ac Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 22 Apr 2024 18:24:54 +0300 Subject: [PATCH 21/23] Updated on 2026-08-14 --- .../CryptoCurrencyToIconStateConverter.kt | 14 ++++++++++---- .../state/amount/SendAmountStateConverter.kt | 10 +++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt index 48d6dabf99..fbcc6e3caa 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/currency/tokenicon/converter/CryptoCurrencyToIconStateConverter.kt @@ -20,17 +20,22 @@ class CryptoCurrencyToIconStateConverter : Converter getIconStateForCoin( coin = currency, isUnreachable = value.value.isError, - forceGrayscale = true, + forceGrayscale = forceGrayscale, ) is CryptoCurrency.Token -> getIconStateForToken( token = currency, isErrorStatus = value.value.isError, - forceGrayscale = true, + forceGrayscale = forceGrayscale, + showCustomBadge = showCustomTokenBadge, ) } } @@ -58,6 +63,7 @@ class CryptoCurrencyToIconStateConverter : Converter Date: Mon, 22 Apr 2024 18:26:20 +0300 Subject: [PATCH 22/23] Updated on 2026-08-14 --- gradle/dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 9f6bf1bcfd..eec9a20c7b 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -85,7 +85,7 @@ leakcanary = "2.13" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_5.9-602" +tangemBlockchainSdk = "release-app_5.9-605" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_5.9-343" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ From 194b71e38b80bf65924924b889b037a5a5b76d86 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 22 Apr 2024 16:41:37 +0100 Subject: [PATCH 23/23] Updated on 2026-08-14 --- .../src/main/assets/configs/feature_toggles_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json index 84088baede..7da3c6d73d 100644 --- a/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json +++ b/core/featuretoggles/src/main/assets/configs/feature_toggles_config.json @@ -9,7 +9,7 @@ }, { "name": "REDESIGNED_SEND_SCREEN_ENABLED", - "version": "5.9.0" + "version": "5.9.1" }, { "name": "GENERAL_USER_WALLETS_LIST_MANAGER_ENABLED",