Updated on 2026-08-14

This commit is contained in:
Tangem 2024-07-22 21:48:53 +03:00
parent f426a1f922
commit 909ff3be7c
17 changed files with 104 additions and 21 deletions

View file

@ -564,6 +564,7 @@
<string name="send_total_subtitle_fiat_format">≈ %1$s (вкл. комиссию: %2$s)</string>
<string name="send_total_subtitle_format">%s будет отправлено</string>
<string name="send_transaction_success">Транзакция успешно подписана и отправлена в блокчейн. Баланс будет обновлен через некоторое время</string>
<string name="send_tron_account_activation_error">%1$s — это монета в сети Tron. Чтобы рассчитать комиссию и совершить транзакцию, вам необходимо внести немного Tron (TRX) на свой адрес.</string>
<string name="send_validation_invalid_address">Неверный адрес</string>
<string name="sent_transaction_sent_title">Транзакция отправлена</string>
<string name="settings_card_settings_footer">Подготовьтесь к сканированию карты, которую вы хотите настроить.</string>

View file

@ -627,6 +627,7 @@
<string name="send_total_subtitle_fiat_format">≈ %1$s (inc. fee: %2$s)</string>
<string name="send_total_subtitle_format">%s will be sent</string>
<string name="send_transaction_success">Transaction has been successfully signed and sent to the blockchain node. Wallet balance will be updated in a while</string>
<string name="send_tron_account_activation_error">%1$s is an asset in the Tron network. To calculate the fee and make a transaction you need to deposit some Tron(TRX) in your account.</string>
<string name="send_validation_invalid_address">Invalid address</string>
<string name="send_wallet_balance_format">%1$s (%2$s)</string>
<string name="sent_transaction_sent_title">Transaction sent</string>

View file

@ -0,0 +1,13 @@
package com.tangem.domain.transaction.error
import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.blockchain.extensions.Result
fun Result.Failure.mapToFeeError(): GetFeeError {
return when (this.error) {
is BlockchainSdkError.Tron.AccountActivationError -> {
GetFeeError.BlockchainErrors.TronActivationError
}
else -> GetFeeError.DataError(this.error)
}
}

View file

@ -2,5 +2,9 @@ package com.tangem.domain.transaction.error
sealed class GetFeeError {
data class DataError(val cause: Throwable?) : GetFeeError()
object UnknownError : GetFeeError()
data object UnknownError : GetFeeError()
sealed class BlockchainErrors : GetFeeError() {
data object TronActivationError : BlockchainErrors()
}
}

View file

@ -12,6 +12,7 @@ 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.transaction.error.mapToFeeError
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWallet
import kotlinx.coroutines.flow.Flow
@ -47,7 +48,7 @@ class EstimateFeeUseCase(
val maybeFee = when (result) {
is Result.Success -> result.data.right()
is Result.Failure -> GetFeeError.DataError(result.error).left()
is Result.Failure -> result.mapToFeeError().left()
null -> GetFeeError.UnknownError.left()
}
emit(maybeFee)

View file

@ -10,6 +10,7 @@ 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.transaction.error.mapToFeeError
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWallet
import java.math.BigDecimal
@ -47,7 +48,7 @@ class GetFeeUseCase(
val maybeFee = when (result) {
is Result.Success -> result.data
is Result.Failure -> raise(GetFeeError.DataError(result.error))
is Result.Failure -> raise(result.mapToFeeError())
}
maybeFee
},

View file

@ -0,0 +1,19 @@
package com.tangem.features.send.impl.presentation.errors
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState
internal class FeeErrorStateMapper {
fun getFeeError(loadFeeError: GetFeeError?, tokenName: String): FeeSelectorState.Error {
return when (loadFeeError) {
GetFeeError.BlockchainErrors.TronActivationError -> FeeSelectorState.Error.TronAccountActivationError(
tokenName,
)
is GetFeeError.DataError,
GetFeeError.UnknownError,
null,
-> FeeSelectorState.Error.NetworkError
}
}
}

View file

@ -157,6 +157,14 @@ internal sealed class SendNotification(val config: NotificationConfig) {
),
)
data class TronAccountNotActivated(val tokenName: String) : Warning(
title = resourceReference(R.string.send_fee_unreachable_error_title),
subtitle = resourceReference(
R.string.send_tron_account_activation_error,
wrappedList(tokenName),
),
)
data class FeeCoverageNotification(val cryptoAmount: String, val fiatAmount: String) : Warning(
title = resourceReference(R.string.send_network_fee_warning_title),
subtitle = resourceReference(

View file

@ -126,8 +126,18 @@ internal class SendNotificationFactory(
}
private fun MutableList<SendNotification>.addFeeUnreachableNotification(feeSelectorState: FeeSelectorState) {
if (feeSelectorState is FeeSelectorState.Error) {
add(SendNotification.Warning.NetworkFeeUnreachable(clickIntents::feeReload))
when (feeSelectorState) {
is FeeSelectorState.Error.TronAccountActivationError -> add(
SendNotification.Warning.TronAccountNotActivated(
feeSelectorState.tokenName,
),
)
is FeeSelectorState.Error.NetworkError -> add(
SendNotification.Warning.NetworkFeeUnreachable(clickIntents::feeReload),
)
else -> {
/* do nothing */
}
}
}

View file

@ -1,6 +1,9 @@
package com.tangem.features.send.impl.presentation.state.fee
import com.tangem.features.send.impl.presentation.state.*
import com.tangem.features.send.impl.presentation.state.SendNotification
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.state.SendUiStateType
import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import kotlinx.collections.immutable.persistentListOf
@ -21,13 +24,25 @@ internal class FeeNotificationFactory(
val state = currentStateProvider()
val feeState = state.getFeeState(stateRouterProvider().isEditState) ?: return@map persistentListOf()
buildList {
addFeeUnreachableNotification(feeState.feeSelectorState)
addFeeUnreachableNotification(
feeState.feeSelectorState,
)
}.toImmutableList()
}
private fun MutableList<SendNotification>.addFeeUnreachableNotification(feeSelectorState: FeeSelectorState) {
if (feeSelectorState is FeeSelectorState.Error) {
add(SendNotification.Warning.NetworkFeeUnreachable(clickIntents::feeReload))
when (feeSelectorState) {
is FeeSelectorState.Error.TronAccountActivationError -> add(
SendNotification.Warning.TronAccountNotActivated(
feeSelectorState.tokenName,
),
)
is FeeSelectorState.Error.NetworkError -> add(
SendNotification.Warning.NetworkFeeUnreachable(clickIntents::feeReload),
)
else -> {
/* do nothing */
}
}
}
}

View file

@ -17,7 +17,10 @@ internal sealed class FeeSelectorState {
data object Loading : FeeSelectorState()
data object Error : FeeSelectorState()
sealed class Error : FeeSelectorState() {
data object NetworkError : Error()
data class TronAccountActivationError(val tokenName: String) : Error()
}
}
enum class FeeType {

View file

@ -99,13 +99,13 @@ internal class FeeStateFactory(
)
}
fun onFeeOnErrorState(): SendUiState {
fun onFeeOnErrorState(feeError: FeeSelectorState.Error): SendUiState {
val state = currentStateProvider()
val isEditState = stateRouterProvider().isEditState
return state.copyWrapped(
isEditState = isEditState,
feeState = state.getFeeState(isEditState)?.copy(
feeSelectorState = FeeSelectorState.Error,
feeSelectorState = feeError,
),
sendState = state.sendState?.copy(
isPrimaryButtonEnabled = false,

View file

@ -102,6 +102,6 @@ internal object FeeStatePreviewData {
)
val errorFeeState = feeState.copy(
feeSelectorState = FeeSelectorState.Error,
feeSelectorState = FeeSelectorState.Error.NetworkError,
)
}

View file

@ -98,7 +98,7 @@ private fun FeeError(feeSelectorState: FeeSelectorState) {
Row {
SpacerWMax()
AnimatedVisibility(
visible = feeSelectorState == FeeSelectorState.Error,
visible = feeSelectorState is FeeSelectorState.Error,
label = "Fee Error State Change",
modifier = Modifier.align(Alignment.CenterVertically),
) {

View file

@ -105,7 +105,7 @@ private fun BoxScope.FeeError(feeSelectorState: FeeSelectorState) {
label = "Fee Error State Change",
modifier = Modifier.align(Alignment.CenterEnd),
) {
if (it == FeeSelectorState.Error) {
if (it is FeeSelectorState.Error) {
Text(
text = BigDecimalFormatter.EMPTY_BALANCE_SIGN,
color = TangemTheme.colors.text.primary1,

View file

@ -45,6 +45,7 @@ import com.tangem.features.send.impl.presentation.analytics.SendAnalyticEvents
import com.tangem.features.send.impl.presentation.analytics.SendScreenSource
import com.tangem.features.send.impl.presentation.analytics.utils.SendScreenAnalyticSender
import com.tangem.features.send.impl.presentation.domain.AvailableWallet
import com.tangem.features.send.impl.presentation.errors.FeeErrorStateMapper
import com.tangem.features.send.impl.presentation.state.*
import com.tangem.features.send.impl.presentation.state.amount.AmountStateFactory
import com.tangem.features.send.impl.presentation.state.confirm.SendNotificationFactory
@ -120,6 +121,8 @@ internal class SendViewModel @Inject constructor(
var stateRouter: StateRouter by Delegates.notNull()
private set
private val feeErrorHandler = FeeErrorStateMapper()
private val stateFactory = SendStateFactory(
clickIntents = this,
stateRouterProvider = Provider { stateRouter },
@ -711,20 +714,24 @@ internal class SendViewModel @Inject constructor(
uiState.value = feeStateFactory.onFeeOnLoadedState(it)
sendIdleTimer = SystemClock.elapsedRealtime()
},
ifLeft = {
onFeeLoadFailed(isShowStatus)
ifLeft = { loadFeeError ->
onFeeLoadFailed(isShowStatus, loadFeeError)
},
)
if (result == null) {
onFeeLoadFailed(isShowStatus)
onFeeLoadFailed(isShowStatus, null)
}
updateNotifications()
updateFeeNotifications()
}.saveIn(feeJobHolder)
}
private fun onFeeLoadFailed(isShowStatus: Boolean) {
if (isShowStatus) uiState.value = feeStateFactory.onFeeOnErrorState()
private fun onFeeLoadFailed(isShowStatus: Boolean, loadFeeError: GetFeeError?) {
if (isShowStatus) {
uiState.value = feeStateFactory.onFeeOnErrorState(
feeErrorHandler.getFeeError(loadFeeError, cryptoCurrency.name),
)
}
}
private suspend fun checkIfSubtractAvailable() {

View file

@ -88,7 +88,7 @@ markdown = "0.7.2"
# endregion Other libraries
# region Tangem
tangemBlockchainSdk = "develop-700"
tangemBlockchainSdk = "develop-702"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-375"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^