Updated on 2026-08-14
This commit is contained in:
commit
afff7892bb
721 changed files with 24513 additions and 7275 deletions
|
|
@ -71,6 +71,7 @@ dependencies {
|
|||
implementation(projects.domain.txhistory)
|
||||
implementation(projects.domain.txhistory.models)
|
||||
implementation(projects.domain.transaction)
|
||||
implementation(projects.domain.transaction.models)
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.balanceHiding)
|
||||
implementation(projects.domain.balanceHiding.models)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.core.analytics.models.AnalyticsParam
|
|||
import com.tangem.core.analytics.models.AnalyticsParam.Key.BLOCKCHAIN
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.FEE_TYPE
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.SOURCE
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.TYPE
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.VALIDATION
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.OnOffState
|
||||
|
|
@ -105,7 +105,7 @@ internal sealed class SendAnalyticEvents(
|
|||
) : SendAnalyticEvents(
|
||||
event = "Transaction Sent Screen Opened",
|
||||
params = mapOf(
|
||||
TOKEN to token,
|
||||
TOKEN_PARAM to token,
|
||||
FEE_TYPE to feeType.value,
|
||||
),
|
||||
)
|
||||
|
|
@ -119,13 +119,13 @@ internal sealed class SendAnalyticEvents(
|
|||
/** If not enough fee notification is present */
|
||||
data class NoticeNotEnoughFee(val token: String, val blockchain: String) : SendAnalyticEvents(
|
||||
event = "Notice - Not Enough Fee",
|
||||
params = mapOf(TOKEN to token, BLOCKCHAIN to blockchain),
|
||||
params = mapOf(TOKEN_PARAM to token, BLOCKCHAIN to blockchain),
|
||||
)
|
||||
|
||||
/** If transaction delays notification is present */
|
||||
data class NoticeTransactionDelays(val token: String) : SendAnalyticEvents(
|
||||
event = "Notice - Transaction Delays Are Possible",
|
||||
params = mapOf(TOKEN to token),
|
||||
params = mapOf(TOKEN_PARAM to token),
|
||||
)
|
||||
|
||||
data object NoticeFeeCoverage : SendAnalyticEvents(
|
||||
|
|
@ -135,7 +135,7 @@ internal sealed class SendAnalyticEvents(
|
|||
/** If error occurs during send transactions */
|
||||
data class TransactionError(val token: String) : SendAnalyticEvents(
|
||||
event = "Error - Transaction Rejected",
|
||||
params = mapOf(TOKEN to token),
|
||||
params = mapOf(TOKEN_PARAM to token),
|
||||
)
|
||||
// endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ internal sealed class SendNotification(val config: NotificationConfig) {
|
|||
title = resourceReference(R.string.send_notification_existential_deposit_title),
|
||||
subtitle = resourceReference(R.string.send_notification_existential_deposit_text, wrappedList(deposit)),
|
||||
buttonState = NotificationConfig.ButtonsState.PrimaryButtonConfig(
|
||||
text = resourceReference(R.string.send_notification_leave_button, wrappedList(deposit)),
|
||||
text = resourceReference(R.string.common_ok),
|
||||
onClick = onConfirmClick,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.features.send.impl.presentation.state
|
||||
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
|
@ -15,7 +17,7 @@ internal class SendTransactionAlertConverter(
|
|||
is SendTransactionError.TangemSdkError -> SendAlertState.TransactionError(
|
||||
code = value.code.toString(),
|
||||
cause = null,
|
||||
causeTextReference = value.messageReference,
|
||||
causeTextReference = resourceReference(value.messageRes, wrappedList(value.args)),
|
||||
onConfirmClick = { clickIntents.onFailedTxEmailClick(value.code.toString()) },
|
||||
)
|
||||
is SendTransactionError.BlockchainSdkError -> SendAlertState.TransactionError(
|
||||
|
|
|
|||
|
|
@ -72,7 +72,10 @@ internal class FeeConverter(
|
|||
normalFee
|
||||
} else {
|
||||
when (normalFee) {
|
||||
is Fee.Ethereum -> ethereumCustomFeeConverter.convertBack(normalFee = normalFee, value = customValues)
|
||||
is Fee.Ethereum.Legacy -> ethereumCustomFeeConverter.convertBack(
|
||||
normalFee = normalFee,
|
||||
value = customValues,
|
||||
)
|
||||
is Fee.Bitcoin -> bitcoinCustomFeeConverter.convertBack(normalFee = normalFee, value = customValues)
|
||||
is Fee.Kaspa -> kaspaCustomFeeConverter.convertBack(normalFee = normalFee, value = customValues)
|
||||
else -> {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.tangem.features.send.impl.presentation.state.fee
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.core.ui.utils.parseToBigDecimal
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.model.AmountType
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
|
||||
import com.tangem.features.send.impl.presentation.state.SendNotification
|
||||
|
|
@ -15,6 +17,7 @@ import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
|||
import com.tangem.utils.Provider
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import com.tangem.blockchain.common.AmountType as SdkAmountType
|
||||
|
||||
/**
|
||||
* Factory to produce fee state for [SendUiState]
|
||||
|
|
@ -94,7 +97,7 @@ internal class FeeStateFactory(
|
|||
feeState = feeState.copy(
|
||||
feeSelectorState = updatedFeeSelectorState,
|
||||
fee = fee,
|
||||
isFeeApproximate = isFeeApproximate(fee),
|
||||
isFeeApproximate = isFeeApproximate(state.amountState),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -180,11 +183,29 @@ internal class FeeStateFactory(
|
|||
return noErrors && (isNotEmptyCustom || isNotCustom)
|
||||
}
|
||||
|
||||
private fun isFeeApproximate(fee: Fee): Boolean {
|
||||
private fun isFeeApproximate(state: AmountState): Boolean {
|
||||
val cryptoCurrencyStatus = feeCryptoCurrencyStatusProvider() ?: return false
|
||||
val amount = (state as? AmountState.Data)?.amountTextField?.cryptoAmount ?: return false
|
||||
return isFeeApproximateUseCase(
|
||||
networkId = cryptoCurrencyStatus.currency.network.id,
|
||||
amountType = fee.amount.type,
|
||||
amountType = amount.type.toSdkAmountType(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun AmountType.toSdkAmountType(): SdkAmountType {
|
||||
return when (this) {
|
||||
AmountType.CoinType -> SdkAmountType.Coin
|
||||
is AmountType.FiatType -> error("unsupported type FiatType")
|
||||
AmountType.ReserveType -> SdkAmountType.Reserve
|
||||
is AmountType.TokenType -> SdkAmountType.Token(
|
||||
Token(
|
||||
name = this.token.name,
|
||||
symbol = this.token.symbol,
|
||||
contractAddress = this.token.contractAddress,
|
||||
decimals = this.token.decimals,
|
||||
id = this.token.id.rawCurrencyId,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ internal class SendFeeCustomFieldConverter(
|
|||
|
||||
override fun convert(value: Fee): ImmutableList<SendTextField.CustomFee> {
|
||||
return when (value) {
|
||||
is Fee.Ethereum -> ethereumCustomFeeConverter.convert(value)
|
||||
is Fee.Ethereum.Legacy -> ethereumCustomFeeConverter.convert(value)
|
||||
is Fee.Bitcoin -> bitcoinCustomFeeConverter.convert(value)
|
||||
is Fee.Kaspa -> kaspaCustomFeeConverter.convert(value)
|
||||
else -> persistentListOf()
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ internal class EthereumCustomFeeConverter(
|
|||
private val stateRouterProvider: Provider<StateRouter>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val feeCryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
) : CustomFeeConverter<Fee.Ethereum> {
|
||||
) : CustomFeeConverter<Fee.Ethereum.Legacy> {
|
||||
|
||||
override fun convert(value: Fee.Ethereum): ImmutableList<SendTextField.CustomFee> {
|
||||
override fun convert(value: Fee.Ethereum.Legacy): ImmutableList<SendTextField.CustomFee> {
|
||||
val feeValue = value.amount.value
|
||||
val feeCurrency = feeCryptoCurrencyStatusProvider()?.value
|
||||
return persistentListOf(
|
||||
|
|
@ -91,7 +91,10 @@ internal class EthereumCustomFeeConverter(
|
|||
)
|
||||
}
|
||||
|
||||
override fun convertBack(normalFee: Fee.Ethereum, value: ImmutableList<SendTextField.CustomFee>): Fee.Ethereum {
|
||||
override fun convertBack(
|
||||
normalFee: Fee.Ethereum.Legacy,
|
||||
value: ImmutableList<SendTextField.CustomFee>,
|
||||
): Fee.Ethereum.Legacy {
|
||||
val feeAmount = value[FEE_AMOUNT].value.parseToBigDecimal(value[FEE_AMOUNT].decimals)
|
||||
val gasPrice = value[GAS_PRICE].value.parseToBigDecimal(GAS_DECIMALS).toBigInteger()
|
||||
val gasLimit = value[GAS_LIMIT].value.parseToBigDecimal(GAS_DECIMALS).toBigInteger()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.tangem.core.ui.components.BasicDialog
|
||||
import com.tangem.core.ui.components.DialogButton
|
||||
import com.tangem.core.ui.components.DialogButtonUM
|
||||
import com.tangem.core.ui.event.EventEffect
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
|
|
@ -45,24 +45,24 @@ internal fun SendEventEffect(event: StateEvent<SendEvent>, snackbarHostState: Sn
|
|||
|
||||
@Composable
|
||||
internal fun SendAlert(state: SendAlertState, onDismiss: () -> Unit) {
|
||||
val confirmButton: DialogButton
|
||||
val dismissButton: DialogButton?
|
||||
val confirmButton: DialogButtonUM
|
||||
val dismissButton: DialogButtonUM?
|
||||
|
||||
val onActionClick = state.onConfirmClick
|
||||
if (onActionClick != null) {
|
||||
confirmButton = DialogButton(
|
||||
confirmButton = DialogButtonUM(
|
||||
title = state.confirmButtonText.resolveReference(),
|
||||
onClick = {
|
||||
onActionClick()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
dismissButton = DialogButton(
|
||||
dismissButton = DialogButtonUM(
|
||||
title = stringResource(id = R.string.common_cancel),
|
||||
onClick = onDismiss,
|
||||
)
|
||||
} else {
|
||||
confirmButton = DialogButton(
|
||||
confirmButton = DialogButtonUM(
|
||||
title = state.confirmButtonText.resolveReference(),
|
||||
onClick = onDismiss,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -163,13 +163,15 @@ private fun SendScreenContent(uiState: SendUiState, currentState: SendUiCurrentS
|
|||
when (state.type) {
|
||||
SendUiStateType.Amount -> AmountScreenContent(
|
||||
amountState = uiState.amountState,
|
||||
isBalanceHiding = uiState.isBalanceHidden,
|
||||
isBalanceHidden = uiState.isBalanceHidden,
|
||||
clickIntents = uiState.clickIntents,
|
||||
modifier = Modifier.background(TangemTheme.colors.background.tertiary),
|
||||
)
|
||||
SendUiStateType.EditAmount -> AmountScreenContent(
|
||||
amountState = uiState.editAmountState!!,
|
||||
isBalanceHiding = uiState.isBalanceHidden,
|
||||
amountState = uiState.editAmountState,
|
||||
isBalanceHidden = uiState.isBalanceHidden,
|
||||
clickIntents = uiState.clickIntents,
|
||||
modifier = Modifier.background(TangemTheme.colors.background.tertiary),
|
||||
)
|
||||
SendUiStateType.Recipient -> SendRecipientContent(
|
||||
uiState = uiState.recipientState,
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
|||
import com.tangem.features.send.impl.presentation.state.previewdata.RecipientStatePreviewData
|
||||
import com.tangem.features.send.impl.presentation.state.previewdata.SendClickIntentsStub
|
||||
import com.tangem.core.ui.components.containers.FooterContainer
|
||||
import com.tangem.core.ui.extensions.orMaskWithStars
|
||||
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
|
||||
import com.tangem.utils.StringsSigns.STARS
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
private const val ADDRESS_FIELD_KEY = "ADDRESS_FIELD_KEY"
|
||||
|
|
@ -205,7 +205,7 @@ private fun LazyListScope.listItem(
|
|||
AnimateRecentAppearance(item.isVisible) {
|
||||
ListItemWithIcon(
|
||||
title = title,
|
||||
subtitle = if (isBalanceHidden) STARS else item.subtitle.resolveReference(),
|
||||
subtitle = item.subtitle.orMaskWithStars(isBalanceHidden).resolveReference(),
|
||||
info = item.timestamp?.resolveReference(),
|
||||
subtitleEndOffset = item.subtitleEndOffset,
|
||||
subtitleIconRes = item.subtitleIconRes,
|
||||
|
|
|
|||
|
|
@ -26,8 +26,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.common.ui.amountScreen.ui.AmountBlock
|
||||
import com.tangem.core.ui.components.transactions.TransactionDoneTitle
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.utils.DateTimeFormatters
|
||||
import com.tangem.core.ui.utils.toTimeFormat
|
||||
import com.tangem.features.send.impl.R
|
||||
import com.tangem.features.send.impl.presentation.state.SendUiState
|
||||
import com.tangem.features.send.impl.presentation.state.previewdata.ConfirmStatePreviewData
|
||||
|
|
@ -69,8 +73,14 @@ private fun LazyListScope.blocks(uiState: SendUiState) {
|
|||
modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
TransactionDoneTitle(
|
||||
titleRes = R.string.sent_transaction_sent_title,
|
||||
date = timestamp,
|
||||
title = resourceReference(R.string.sent_transaction_sent_title),
|
||||
subtitle = resourceReference(
|
||||
R.string.send_date_format,
|
||||
wrappedList(
|
||||
timestamp.toTimeFormat(DateTimeFormatters.dateFormatter),
|
||||
timestamp.toTimeFormat(),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
RecipientBlock(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue