Updated on 2026-08-14

This commit is contained in:
Tangem 2024-02-15 10:09:13 +01:00
parent eadc650d26
commit cad513c95b
7 changed files with 87 additions and 14 deletions

View file

@ -91,7 +91,8 @@
<string name="common_explore_transaction_history">Посмотреть историю транзакций</string>
<string name="common_explorer">Обозреватель</string>
<string name="common_fee_label">Комиссия</string>
<string name="common_fee_selector_footer">Сетевые комиссии за транзакции используются для поддержки безопасности сети, поощрения валидаторов, выделения ресурсов и определения приоритета транзакции.</string>
<string name="common_fee_selector_footer">Сетевые комиссии это плата пользователя за обработку и подтверждение транзакций. Размер комиссии зависит от нагрузка на сеть, объема транзакции и приоритета исполнения. %s</string>
<string name="common_fee_selector_link_description">Подробнее</string>
<string name="common_fee_selector_option_custom">Свое</string>
<string name="common_fee_selector_option_fast">Быстро</string>
<string name="common_fee_selector_option_market">По рынку</string>

View file

@ -89,7 +89,8 @@
<string name="common_explore_transaction_history">Explore transaction history</string>
<string name="common_explorer">Explorer</string>
<string name="common_fee_label">Fee</string>
<string name="common_fee_selector_footer">Network transaction fees are used to support network security, incentivize validators, allocate resources, and determine transaction priority.</string>
<string name="common_fee_selector_footer">Network fees are charges users pay to process and confirm transactions. The fee amount can be affected by network congestion, transaction size, and execution priority. %s</string>
<string name="common_fee_selector_link_description">Read more</string>
<string name="common_fee_selector_option_custom">Custom</string>
<string name="common_fee_selector_option_fast">Fast</string>
<string name="common_fee_selector_option_market">Market</string>

View file

@ -24,4 +24,5 @@ data class UiActions(
val onPolicyClick: (String) -> Unit,
val onTosClick: (String) -> Unit,
val onReceiveCardWarningClick: () -> Unit,
val onFeeReadMoreClick: (String) -> Unit,
)

View file

@ -1,6 +1,7 @@
package com.tangem.feature.swap.models.states
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.feature.swap.domain.models.ui.FeeType
import kotlinx.collections.immutable.ImmutableList
@ -8,4 +9,7 @@ data class ChooseFeeBottomSheetConfig(
val selectedFee: FeeType,
val onSelectFeeType: (FeeType) -> Unit,
val feeItems: ImmutableList<FeeItemState.Content>,
val readMoreUrl: String,
val readMore: TextReference,
val onReadMoreClick: (String) -> Unit,
) : TangemBottomSheetConfigContent

View file

@ -3,18 +3,23 @@ package com.tangem.feature.swap.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.components.SpacerH24
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.rows.SelectorRowItem
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.swap.domain.models.ui.FeeType
@ -33,7 +38,9 @@ fun ChooseFeeBottomSheet(config: TangemBottomSheetConfig) {
@Composable
private fun ChooseFeeBottomSheetContent(content: ChooseFeeBottomSheetConfig) {
Column(
modifier = Modifier.background(TangemTheme.colors.background.primary),
modifier = Modifier
.background(TangemTheme.colors.background.primary)
.padding(bottom = TangemTheme.dimens.spacing8),
) {
Text(
text = stringResource(R.string.common_fee_selector_title),
@ -53,21 +60,47 @@ private fun ChooseFeeBottomSheetContent(content: ChooseFeeBottomSheetConfig) {
) {
FeeItemsBlock(content)
}
Text(
text = stringResource(R.string.common_fee_selector_footer),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.secondary,
modifier = Modifier
.padding(
vertical = TangemTheme.dimens.spacing8,
horizontal = TangemTheme.dimens.spacing16,
)
.align(Alignment.CenterHorizontally),
textAlign = TextAlign.Start,
FooterBlock(
readMore = content.readMore,
readMoreUrl = content.readMoreUrl,
onReadMoreClick = content.onReadMoreClick,
)
}
}
@Composable
private fun FooterBlock(readMore: TextReference, readMoreUrl: String, onReadMoreClick: (String) -> Unit) {
val linkText = readMore.resolveReference()
val fullString = stringResource(R.string.common_fee_selector_footer, linkText)
val linkTextPosition = fullString.length - linkText.length
val annotatedString = buildAnnotatedString {
withStyle(SpanStyle(color = TangemTheme.colors.text.tertiary)) {
append(fullString.substring(0, linkTextPosition))
}
withStyle(SpanStyle(color = TangemTheme.colors.text.accent)) {
append(fullString.substring(linkTextPosition, fullString.length))
}
}
val click = { i: Int ->
val readMoreStyle = requireNotNull(annotatedString.spanStyles.getOrNull(1))
if (i in readMoreStyle.start..readMoreStyle.end) {
onReadMoreClick(readMoreUrl)
}
}
ClickableText(
text = annotatedString,
modifier = Modifier
.padding(
vertical = TangemTheme.dimens.spacing8,
horizontal = TangemTheme.dimens.spacing16,
),
style = TangemTheme.typography.caption2.copy(textAlign = TextAlign.Start),
onClick = click,
)
}
@Composable
private fun FeeItemsBlock(content: ChooseFeeBottomSheetConfig) {
content.feeItems.forEach { feeItem ->
@ -129,6 +162,9 @@ private fun ChooseFeeBottomSheetContent_Preview() {
selectedFee = FeeType.NORMAL,
onSelectFeeType = {},
feeItems = feeItems,
readMore = stringReference("Read more"),
readMoreUrl = "",
onReadMoreClick = {},
),
)
}
@ -141,6 +177,9 @@ private fun ChooseFeeBottomSheetContent_Preview() {
selectedFee = FeeType.NORMAL,
onSelectFeeType = {},
feeItems = feeItems,
readMore = stringReference("Read more"),
readMoreUrl = "",
onReadMoreClick = {},
),
)
}

View file

@ -25,6 +25,7 @@ import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import java.math.BigDecimal
import java.math.RoundingMode
import java.util.Locale
import kotlin.math.min
/**
@ -1090,7 +1091,10 @@ internal class StateBuilder(
}
actions.onSelectFeeType.invoke(selectedItem)
},
readMoreUrl = buildReadMoreUrl(),
feeItems = txFeeState.toFeeItemState(),
readMore = resourceReference(R.string.common_fee_selector_link_description),
onReadMoreClick = actions.onFeeReadMoreClick,
)
return uiState.copy(
bottomSheetConfig = TangemBottomSheetConfig(
@ -1101,6 +1105,14 @@ internal class StateBuilder(
)
}
private fun buildReadMoreUrl(): String {
return buildString {
append(FEE_READ_MORE_URL_FIRST_PART)
append(getLocaleName())
append(FEE_READ_MORE_URL_SECOND_PART)
}
}
fun updateSelectedFeeBottomSheet(uiState: SwapStateHolder, selectedFee: FeeType): SwapStateHolder {
val config = uiState.bottomSheetConfig?.content as? ChooseFeeBottomSheetConfig
return if (config != null) {
@ -1346,12 +1358,24 @@ internal class StateBuilder(
return text.replace(",", ".").toBigDecimalOrNull()
}
private fun getLocaleName(): String {
return if (Locale.getDefault().language == "ru") {
RU_LOCALE
} else {
EN_LOCALE
}
}
private companion object {
private const val RU_LOCALE = "ru"
private const val EN_LOCALE = "en"
const val ADDRESS_MIN_LENGTH = 11
const val ADDRESS_FIRST_PART_LENGTH = 7
const val ADDRESS_SECOND_PART_LENGTH = 4
private const val PRICE_IMPACT_THRESHOLD = 0.1
private const val UNKNOWN_AMOUNT_SIGN = ""
private const val MAX_DECIMALS_TO_SHOW = 8
private const val FEE_READ_MORE_URL_FIRST_PART = "https://tangem.com/"
private const val FEE_READ_MORE_URL_SECOND_PART = "/blog/post/what-is-a-transaction-fee-and-why-do-we-need-it/"
}
}

View file

@ -890,6 +890,9 @@ internal class SwapViewModel @Inject constructor(
uiState = stateBuilder.clearAlert(uiState)
}
},
onFeeReadMoreClick = {
swapRouter.openUrl(it)
},
)
}