Updated on 2026-08-14

This commit is contained in:
Tangem 2023-11-29 20:10:20 +03:00
commit cd2f5bfeed
14 changed files with 425 additions and 59 deletions

View file

@ -6,7 +6,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.text.TextLayoutResult
@ -18,10 +17,12 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.TextUnit
import com.tangem.core.ui.components.atoms.text.BoundCounter
/**
* https://stackoverflow.com/questions/69083061/how-to-make-middle-ellipsis-in-text-with-jetpack-compose
*/
@Deprecated("Use EllipsisText with TextEllipsis.Middle ellipsis instead")
@Suppress("LongMethod")
@Composable
fun MiddleEllipsisText(
@ -138,38 +139,4 @@ fun MiddleEllipsisText(
private const val ELLIPSIS_CHARACTERS_COUNT = 3
private const val ELLIPSIS_CHARACTER = '.'
private val ellipsisText = List(ELLIPSIS_CHARACTERS_COUNT) { ELLIPSIS_CHARACTER }.joinToString(separator = "")
private class BoundCounter(
private val text: String,
private val textLayoutResult: TextLayoutResult,
private val charPosition: (Int) -> Int,
) {
var string = ""
private set
var width = 0f
private set
private var _nextCharWidth: Float? = null
private var invalidCharsCount = 0
fun widthWithNextChar(): Float = width + nextCharWidth()
private fun nextCharWidth(): Float = _nextCharWidth ?: run {
var boundingBox: Rect
// invalidCharsCount fixes this bug: https://issuetracker.google.com/issues/197146630
invalidCharsCount--
do {
boundingBox = textLayoutResult
.getBoundingBox(charPosition(string.count() + ++invalidCharsCount))
} while (boundingBox.right == 0f)
_nextCharWidth = boundingBox.width
boundingBox.width
}
fun addNextChar() {
string += text[charPosition(string.count())]
width += nextCharWidth()
_nextCharWidth = null
}
}
private val ellipsisText = List(ELLIPSIS_CHARACTERS_COUNT) { ELLIPSIS_CHARACTER }.joinToString(separator = "")

View file

@ -0,0 +1,38 @@
package com.tangem.core.ui.components.atoms.text
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.text.TextLayoutResult
internal class BoundCounter(
private val text: String,
private val textLayoutResult: TextLayoutResult,
private val charPosition: (Int) -> Int,
) {
var string = ""
private set
var width = 0f
private set
private var _nextCharWidth: Float? = null
private var invalidCharsCount = 0
fun widthWithNextChar(): Float = width + nextCharWidth()
private fun nextCharWidth(): Float = _nextCharWidth ?: run {
var boundingBox: Rect
// invalidCharsCount fixes this bug: https://issuetracker.google.com/issues/197146630
invalidCharsCount--
do {
boundingBox = textLayoutResult
.getBoundingBox(charPosition(string.count() + ++invalidCharsCount))
} while (boundingBox.right == 0f)
_nextCharWidth = boundingBox.width
boundingBox.width
}
fun addNextChar() {
string += text[charPosition(string.count())]
width += nextCharWidth()
_nextCharWidth = null
}
}

View file

@ -0,0 +1,242 @@
package com.tangem.core.ui.components.atoms.text
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.TextUnit
import com.tangem.core.ui.res.TangemTheme
sealed class TextEllipsis {
object Middle : TextEllipsis()
object End : TextEllipsis()
data class OffsetEnd(
val offsetEnd: Int = 0,
val hasSeparator: Boolean = true,
) : TextEllipsis()
}
/**
* https://stackoverflow.com/questions/69083061/how-to-make-middle-ellipsis-in-text-with-jetpack-compose
*
* Customized Text with ellipsis. Ellipsis can be placed in: Middle, End or OffsetEnd (OffsetEnd with separator).
*
* * OffsetEnd can be useful to display big amounts with currency symbol. OffsetEnd 0 is equal to End.
*/
@Suppress("LongMethod")
@Composable
fun EllipsisText(
text: String,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
softWrap: Boolean = true,
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current,
ellipsis: TextEllipsis = TextEllipsis.End,
) {
val ellipsisText = remember(text) {
if (ellipsis is TextEllipsis.OffsetEnd && ellipsis.hasSeparator) {
ELLIPSIS_TEXT_WITH_SEPARATOR
} else {
ELLIPSIS_TEXT
}
}
// some letters, like "r", will have less width when placed right before "."
// adding a space to prevent such case
val layoutText = remember(text) { "$text $ellipsisText" }
val textLayoutResultState = remember(layoutText) {
mutableStateOf<TextLayoutResult?>(null)
}
SubcomposeLayout(modifier) { constraints ->
// result is ignored - we only need to fill our textLayoutResult
subcompose("measure") {
Text(
text = layoutText,
color = color,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
softWrap = softWrap,
maxLines = 1,
onTextLayout = { textLayoutResultState.value = it },
style = style,
)
}.first().measure(Constraints())
// to allow smart cast
val textLayoutResult = textLayoutResultState.value
?: // shouldn't happen - onTextLayout is called before subcompose finishes
return@SubcomposeLayout layout(0, 0) {}
val placeable = subcompose("visible") {
val finalText = remember(text, textLayoutResult, constraints.maxWidth) {
if (
text.isEmpty() ||
textLayoutResult.getBoundingBox(text.indices.last).right <= constraints.maxWidth
) {
// text not including ellipsis fits on the first line.
return@remember text
}
var ellipsisWidth = 0f
layoutText.indices.toList()
.takeLast(ellipsisText.length)
.forEach widthLet@{
ellipsisWidth += textLayoutResult.getBoundingBox(it).width
}
val availableWidth = constraints.maxWidth - ellipsisWidth
val startCounter = BoundCounter(text, textLayoutResult) { it }
val endCounter = BoundCounter(text, textLayoutResult) { text.indices.last - it }
when (ellipsis) {
TextEllipsis.Middle -> {
middleEllipsisText(
availableWidth,
startCounter,
endCounter,
)
}
TextEllipsis.End -> {
offsetEndEllipsisText(
availableWidth = availableWidth,
startCounter = startCounter,
endCounter = endCounter,
)
}
is TextEllipsis.OffsetEnd -> {
offsetEndEllipsisText(
availableWidth = availableWidth,
startCounter = startCounter,
endCounter = endCounter,
offsetEnd = ellipsis.offsetEnd,
withSeparator = ellipsis.hasSeparator,
)
}
}
}
Text(
text = finalText,
color = color,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
softWrap = softWrap,
onTextLayout = onTextLayout,
style = style,
)
}[0].measure(constraints)
layout(placeable.width, placeable.height) {
placeable.place(0, 0)
}
}
}
private const val ELLIPSIS_SEPARATOR = ""
private const val ELLIPSIS_TEXT = "..."
private const val ELLIPSIS_TEXT_WITH_SEPARATOR = ELLIPSIS_TEXT.plus(ELLIPSIS_SEPARATOR)
private fun middleEllipsisText(availableWidth: Float, startCounter: BoundCounter, endCounter: BoundCounter): String {
while (availableWidth - startCounter.width - endCounter.width > 0) {
val possibleEndWidth = endCounter.widthWithNextChar()
if (
startCounter.width >= possibleEndWidth &&
availableWidth - startCounter.width - possibleEndWidth >= 0
) {
endCounter.addNextChar()
} else if (availableWidth - startCounter.widthWithNextChar() - endCounter.width >= 0) {
startCounter.addNextChar()
} else {
break
}
}
return startCounter.string.trimEnd() + ELLIPSIS_TEXT + endCounter.string.reversed().trimStart()
}
private fun offsetEndEllipsisText(
availableWidth: Float,
startCounter: BoundCounter,
endCounter: BoundCounter,
offsetEnd: Int = 0,
withSeparator: Boolean = false,
): String {
while (availableWidth - startCounter.width - endCounter.width > 0) {
val possibleEndWidth = endCounter.widthWithNextChar()
if (
offsetEnd > endCounter.string.length &&
availableWidth - startCounter.width - possibleEndWidth >= 0
) {
endCounter.addNextChar()
} else if (availableWidth - startCounter.widthWithNextChar() - endCounter.width >= 0) {
startCounter.addNextChar()
} else {
break
}
}
val ellipsis = if (withSeparator) ELLIPSIS_TEXT_WITH_SEPARATOR else ELLIPSIS_TEXT
return startCounter.string.trimEnd() + ellipsis + endCounter.string.reversed().trimStart()
}
//region Preview
@Preview(widthDp = 200)
@Composable
private fun EllipsisTexPreview(@PreviewParameter(EllipsisTexPreviewParameterProvider::class) ellipsis: TextEllipsis) {
TangemTheme {
EllipsisText(
text = "11111111111111111111111111111111111111111111111111 END",
ellipsis = ellipsis,
modifier = Modifier
.background(TangemTheme.colors.background.primary)
.fillMaxWidth(),
)
}
}
private class EllipsisTexPreviewParameterProvider : PreviewParameterProvider<TextEllipsis> {
override val values: Sequence<TextEllipsis>
get() = sequenceOf(
TextEllipsis.Middle,
TextEllipsis.End,
TextEllipsis.OffsetEnd("TEXT".length),
TextEllipsis.OffsetEnd("TEXT".length, false),
)
}
//endregion

View file

@ -3,13 +3,13 @@ package com.tangem.core.ui.components.inputrow
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.R
import com.tangem.core.ui.components.atoms.text.EllipsisText
import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
import com.tangem.core.ui.components.inputrow.inner.DividerContainer
@ -56,6 +56,7 @@ fun InputRowApprox(
iconState = leftIcon,
title = leftTitle,
subtitle = leftSubtitle,
modifier = Modifier.weight(1f),
)
Icon(
painter = painterResource(id = R.drawable.ic_approx_24),
@ -71,6 +72,7 @@ fun InputRowApprox(
iconState = rightIcon,
title = rightTitle,
subtitle = rightSubtitle,
modifier = Modifier.weight(1f),
)
}
}
@ -97,12 +99,12 @@ private fun InputRowApproxItem(
start = TangemTheme.dimens.spacing12,
),
) {
Text(
EllipsisText(
text = title.resolveReference(),
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
)
Text(
EllipsisText(
text = subtitle.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
@ -123,7 +125,7 @@ private fun InputRowApproxPreview_Light() {
leftTitle = TextReference.Str("Left title"),
leftSubtitle = TextReference.Str("Left subtitle"),
rightIcon = TokenIconState.Loading,
rightTitle = TextReference.Str("Right title"),
rightTitle = TextReference.Str("Right title Right title Right title Right title Right title"),
rightSubtitle = TextReference.Str("Right subtitle"),
modifier = Modifier
.background(TangemTheme.colors.background.action),
@ -137,7 +139,7 @@ private fun InputRowApproxPreview_Dark() {
TangemTheme(isDark = true) {
InputRowApprox(
leftIcon = TokenIconState.Loading,
leftTitle = TextReference.Str("Left title"),
leftTitle = TextReference.Str("Left title Left title Left title Left title Left title"),
leftSubtitle = TextReference.Str("Left subtitle"),
rightIcon = TokenIconState.Loading,
rightTitle = TextReference.Str("Right title"),

View file

@ -20,4 +20,9 @@ internal class MockQuotesRepository(
override suspend fun getQuotesSync(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean): Set<Quote> {
return getQuotesUpdates(currenciesIds).first()
}
override suspend fun getQuoteSync(currencyId: CryptoCurrency.ID): Quote {
return quotes.map { it.getOrElse { e -> throw e } }.first()
.first { it.rawCurrencyId == currencyId.rawCurrencyId }
}
}

View file

@ -101,6 +101,7 @@ internal object TokenDetailsPreviewData {
),
dialogConfig = null,
pendingTxs = persistentListOf(),
swapTxs = persistentListOf(),
pullToRefreshConfig = pullToRefreshConfig,
bottomSheetConfig = null,
isBalanceHidden = false,

View file

@ -2,21 +2,25 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
import com.tangem.feature.swap.domain.models.domain.SwapProvider
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotifications
import kotlinx.collections.immutable.PersistentList
import java.math.BigDecimal
internal data class SwapTransactionsState(
val txId: String,
val providerId: Int,
val provider: SwapProvider,
val txUrl: String? = null,
val rate: BigDecimal,
val timestamp: Long,
val status: PersistentList<ExchangeStatusState>,
val statuses: PersistentList<ExchangeStatusState>,
val activeStatus: ExchangeStatus?,
val fiatSymbol: String,
val notification: ExchangeStatusNotifications? = null,
val toCryptoAmount: String,
val toCryptoSymbol: String,
val toFiatAmount: String,
val toCurrencyIcon: TokenIconState,
val fromCryptoAmount: String,
val fromCryptoSymbol: String,
val fromFiatAmount: String,
val fromCurrencyIcon: TokenIconState,
val onClick: () -> Unit,
@ -25,7 +29,6 @@ internal data class SwapTransactionsState(
internal class ExchangeStatusState(
val status: ExchangeStatus,
val text: String,
val isActive: Boolean,
val isDone: Boolean,
)

View file

@ -19,6 +19,7 @@ internal data class TokenDetailsState(
val marketPriceBlockState: MarketPriceBlockState,
val notifications: ImmutableList<TokenDetailsNotification>,
val pendingTxs: PersistentList<TransactionState>,
val swapTxs: PersistentList<SwapTransactionsState>,
val txHistoryState: TxHistoryState,
val dialogConfig: TokenDetailsDialogConfig?,
val pullToRefreshConfig: TokenDetailsPullToRefreshConfig,

View file

@ -0,0 +1,38 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.state.components
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.features.tokendetails.impl.R
@Immutable
internal sealed class ExchangeStatusNotifications(val config: NotificationConfig) {
data class NeedVerification(
val onGoToProviderClick: () -> Unit,
) : ExchangeStatusNotifications(
config = NotificationConfig(
title = TextReference.Res(R.string.express_exchange_notification_verification_title),
subtitle = TextReference.Res(R.string.express_exchange_notification_verification_text),
iconResId = R.drawable.ic_alert_triangle_20,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = TextReference.Res(R.string.express_go_to_provider),
onClick = onGoToProviderClick,
),
),
)
data class Failed(
val onGoToProviderClick: () -> Unit,
) : ExchangeStatusNotifications(
config = NotificationConfig(
title = TextReference.Res(R.string.express_exchange_notification_failed_title),
subtitle = TextReference.Res(R.string.express_exchange_notification_failed_text),
iconResId = R.drawable.ic_alert_circle_24,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = TextReference.Res(R.string.express_go_to_provider),
onClick = onGoToProviderClick,
),
),
)
}

View file

@ -45,6 +45,7 @@ internal class TokenDetailsSkeletonStateConverter(
marketPriceBlockState = MarketPriceBlockState.Loading(value.symbol),
notifications = persistentListOf(),
pendingTxs = persistentListOf(),
swapTxs = persistentListOf(),
txHistoryState = TxHistoryState.Content(
contentItems = MutableStateFlow(
value = TxHistoryState.getDefaultLoadingTransactions(clickIntents::onExploreClick),

View file

@ -2,7 +2,9 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.ui
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.ExperimentalMaterialApi
@ -40,6 +42,9 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.T
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsDialogs
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenDetailsTopAppBar
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.TokenInfoBlock
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.ExchangeStatusBottomSheet
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.ExchangeStatusBottomSheetConfig
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange.swapTransactionsItems
// TODO: Split to blocks [REDACTED_JIRA]
@Suppress("LongMethod")
@ -117,6 +122,11 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
)
}
swapTransactionsItems(
state.swapTxs,
itemModifier,
)
txHistoryItems(
state = state.txHistoryState,
isBalanceHidden = state.isBalanceHidden,
@ -141,6 +151,9 @@ internal fun TokenDetailsScreen(state: TokenDetailsState) {
is ChooseAddressBottomSheetConfig -> {
ChooseAddressBottomSheet(config = config)
}
is ExchangeStatusBottomSheetConfig -> {
ExchangeStatusBottomSheet(config = config)
}
}
}

View file

@ -26,7 +26,7 @@ import kotlinx.collections.immutable.PersistentList
@Composable
internal fun ExchangeStatusBlock(
status: PersistentList<ExchangeStatusState>,
statuses: PersistentList<ExchangeStatusState>,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
@ -70,10 +70,10 @@ internal fun ExchangeStatusBlock(
}
}
status.forEachIndexed { index, item ->
statuses.forEachIndexed { index, item ->
ExchangeStatusStep(
stepStatus = item,
isLast = index == status.lastIndex,
isLast = index == statuses.lastIndex,
)
}
}
@ -128,7 +128,7 @@ private fun ExchangeStatusStepText(stepStatus: ExchangeStatusState) {
}
Text(
text = stepStatus.text,
text = getStatusText(stepStatus)?.let { stringResource(it) }.orEmpty(),
style = TangemTheme.typography.body2,
color = textColor,
modifier = Modifier
@ -206,4 +206,34 @@ private fun ExchangeStepSeparator() {
shape = CircleShape,
),
)
}
private fun getStatusText(stepStatus: ExchangeStatusState) = when (stepStatus.status) {
ExchangeStatus.Failed -> R.string.express_exchange_status_failed
ExchangeStatus.Verifying -> if (stepStatus.isDone) {
R.string.express_exchange_status_verified
} else {
R.string.express_exchange_status_verifying
}
ExchangeStatus.New, ExchangeStatus.Waiting -> if (stepStatus.isDone) {
R.string.express_exchange_status_received
} else {
R.string.express_exchange_status_receiving
}
ExchangeStatus.Confirming -> if (stepStatus.isDone) {
R.string.express_exchange_status_confirmed
} else {
R.string.express_exchange_status_confirming
}
ExchangeStatus.Exchanging -> if (stepStatus.isDone) {
R.string.express_exchange_status_exchanged
} else {
R.string.express_exchange_status_exchanging
}
ExchangeStatus.Sending -> if (stepStatus.isDone) {
R.string.express_exchange_status_sent
} else {
R.string.express_exchange_status_sending
}
else -> null
}

View file

@ -1,5 +1,6 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.ui.components.exchange
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
@ -15,6 +16,7 @@ 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.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.toDateFormat
@ -64,17 +66,25 @@ private fun ExchangeStatusBottomSheetContent(content: ExchangeStatusBottomSheetC
toFiatAmount = TextReference.Str(config.toFiatAmount),
)
SpacerH12()
// todo replace with real provider data
ExchangeProvider(
providerName = TextReference.Str(config.providerId.toString()),
providerType = TextReference.Str("CEX"),
imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/changenow_512.png",
providerName = TextReference.Str(config.provider.name),
providerType = TextReference.Str(config.provider.type.name),
imageUrl = config.provider.imageLarge,
)
SpacerH12()
ExchangeStatusBlock(
status = config.status,
statuses = config.statuses,
onClick = config.onGoToProviderClick,
)
AnimatedContent(
targetState = config.notification,
label = "Exchange Status Notification Change",
) {
it?.let {
SpacerH12()
Notification(config = it.config)
}
}
SpacerH24()
}
}

View file

@ -17,7 +17,10 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import androidx.constraintlayout.compose.Visibility
import com.tangem.core.ui.components.atoms.text.EllipsisText
import com.tangem.core.ui.components.atoms.text.TextEllipsis
import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
import com.tangem.core.ui.res.TangemTheme
@ -46,11 +49,13 @@ internal fun LazyListScope.swapTransactionsItems(
}
ExchangeStatusItem(
providerName = item.providerId.toString(),
providerName = item.provider.name,
fromTokenIconState = item.fromCurrencyIcon,
toTokenIconState = item.toCurrencyIcon,
fromAmount = item.fromCryptoAmount,
fromSymbol = item.fromCryptoSymbol,
toAmount = item.toCryptoAmount,
toSymbol = item.toCryptoSymbol,
onClick = item.onClick,
infoIconRes = iconRes,
infoIconTint = tint,
@ -67,7 +72,9 @@ private fun ExchangeStatusItem(
fromTokenIconState: TokenIconState,
toTokenIconState: TokenIconState,
fromAmount: String,
fromSymbol: String,
toAmount: String,
toSymbol: String,
onClick: () -> Unit,
modifier: Modifier = Modifier,
@DrawableRes infoIconRes: Int? = null,
@ -104,14 +111,17 @@ private fun ExchangeStatusItem(
bottom.linkTo(parent.bottom)
},
)
Text(
EllipsisText(
text = fromAmount,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
ellipsis = TextEllipsis.OffsetEnd(fromSymbol.length),
modifier = Modifier.constrainAs(fromRef) {
start.linkTo(fromIconRef.end, padding6)
top.linkTo(titleRef.bottom, padding6)
end.linkTo(swapIconRef.start)
bottom.linkTo(parent.bottom)
width = Dimension.fillToConstraints
},
)
Icon(
@ -123,6 +133,7 @@ private fun ExchangeStatusItem(
.constrainAs(swapIconRef) {
start.linkTo(fromRef.end, padding6)
top.linkTo(titleRef.bottom, padding6)
end.linkTo(toIconRef.start)
bottom.linkTo(parent.bottom)
},
)
@ -134,17 +145,21 @@ private fun ExchangeStatusItem(
.constrainAs(toIconRef) {
start.linkTo(swapIconRef.end, padding6)
top.linkTo(titleRef.bottom, padding6)
end.linkTo(toRef.start)
bottom.linkTo(parent.bottom)
},
)
Text(
EllipsisText(
text = toAmount,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.primary1,
ellipsis = TextEllipsis.OffsetEnd(toSymbol.length),
modifier = Modifier.constrainAs(toRef) {
start.linkTo(toIconRef.end, padding6)
top.linkTo(titleRef.bottom, padding6)
end.linkTo(infoIconRef.start, padding6)
bottom.linkTo(parent.bottom)
width = Dimension.fillToConstraints
},
)
Icon(