Updated on 2026-08-14
This commit is contained in:
parent
56c32291f2
commit
a19b9c01b5
8 changed files with 61 additions and 54 deletions
|
|
@ -438,6 +438,7 @@
|
|||
<string name="send_amount_label">Amount</string>
|
||||
<string name="send_amount_substract">Subtract from send amount</string>
|
||||
<string name="send_amount_substract_footer">The recipient will receive %s</string>
|
||||
<string name="send_confirm_label">Confirm</string>
|
||||
<string name="send_date_format">%1$s at %2$s</string>
|
||||
<string name="send_destination_hint_address">Address</string>
|
||||
<string name="send_destination_tag_field">Destination Tag</string>
|
||||
|
|
@ -488,6 +489,7 @@
|
|||
<string name="send_qrcode_scan_info">Please align your QR code with the square to scan it. Ensure you scan %s network address.</string>
|
||||
<string name="send_recent_transactions">Recent</string>
|
||||
<string name="send_recipient">Recipient</string>
|
||||
<string name="send_recipient_label">Send to</string>
|
||||
<string name="send_recipient_address_error">Not a valid address</string>
|
||||
<string name="send_recipient_address_footer">Ensure that you are sending funds to an %s wallet address. Errors may result in the loss of your tokens</string>
|
||||
<string name="send_recipient_memo_footer">A Memo/Destination Tag is a unique ID for differentiating transactions sent to the same recipient on the same network. Caution: Omitting a memo may lead to misplaced funds</string>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ internal sealed class SendRecipientListContent {
|
|||
val id: String,
|
||||
val title: TextReference,
|
||||
val subtitle: TextReference,
|
||||
val info: TextReference? = null,
|
||||
val timestamp: TextReference? = null,
|
||||
val subtitleEndOffset: Int = 0,
|
||||
@DrawableRes val subtitleIconRes: Int? = null,
|
||||
) : SendRecipientListContent()
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import java.lang.ref.WeakReference
|
|||
internal class StateRouter(
|
||||
private val fragmentManager: WeakReference<FragmentManager>,
|
||||
) {
|
||||
var currentState: MutableStateFlow<SendUiStateType> = MutableStateFlow(SendUiStateType.Amount)
|
||||
var currentState: MutableStateFlow<SendUiStateType> = MutableStateFlow(SendUiStateType.Recipient)
|
||||
private set
|
||||
|
||||
private var isFromSend: Boolean = false
|
||||
|
|
@ -22,9 +22,9 @@ internal class StateRouter(
|
|||
showSend()
|
||||
} else {
|
||||
when (currentState.value) {
|
||||
SendUiStateType.Amount -> popBackStack()
|
||||
SendUiStateType.Recipient -> showAmount()
|
||||
SendUiStateType.Fee -> showRecipient()
|
||||
SendUiStateType.Recipient -> popBackStack()
|
||||
SendUiStateType.Amount -> showRecipient()
|
||||
SendUiStateType.Fee -> showAmount()
|
||||
SendUiStateType.Send -> showFee()
|
||||
}
|
||||
}
|
||||
|
|
@ -32,8 +32,8 @@ internal class StateRouter(
|
|||
|
||||
fun onNextClick() {
|
||||
when (currentState.value) {
|
||||
SendUiStateType.Amount -> showRecipient()
|
||||
SendUiStateType.Recipient -> showFee()
|
||||
SendUiStateType.Recipient -> showAmount()
|
||||
SendUiStateType.Amount -> showFee()
|
||||
SendUiStateType.Fee -> showSend()
|
||||
SendUiStateType.Send -> onBackClick()
|
||||
}
|
||||
|
|
@ -41,9 +41,9 @@ internal class StateRouter(
|
|||
|
||||
fun onPrevClick() {
|
||||
when (currentState.value) {
|
||||
SendUiStateType.Amount -> popBackStack()
|
||||
SendUiStateType.Recipient -> showAmount()
|
||||
SendUiStateType.Fee -> showRecipient()
|
||||
SendUiStateType.Recipient -> popBackStack()
|
||||
SendUiStateType.Amount -> showRecipient()
|
||||
SendUiStateType.Fee -> showAmount()
|
||||
SendUiStateType.Send -> popBackStack()
|
||||
}
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ internal class StateRouter(
|
|||
currentState.update { SendUiStateType.Fee }
|
||||
}
|
||||
|
||||
fun showSend() {
|
||||
private fun showSend() {
|
||||
currentState.update { SendUiStateType.Send }
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,12 @@ package com.tangem.features.send.impl.presentation.state.recipient
|
|||
import androidx.paging.*
|
||||
import com.tangem.common.Provider
|
||||
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.toTimeFormat
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.txhistory.models.TxHistoryItem
|
||||
import com.tangem.features.send.impl.R
|
||||
|
|
@ -34,6 +36,7 @@ internal class SendRecipientListConverter(
|
|||
|
||||
val walletsItem = getWalletItems(filteredWallets, txHistoryCount)
|
||||
|
||||
val cryptoCurrency = cryptoCurrencyStatusProvider().currency
|
||||
currentStateProvider().recipientList.update {
|
||||
if (txHistoryCount == 0) {
|
||||
PagingData.from(listOf(walletsItem))
|
||||
|
|
@ -51,8 +54,9 @@ internal class SendRecipientListConverter(
|
|||
SendRecipientListContent.Item(
|
||||
id = tx.txHash,
|
||||
title = tx.extractAddress(),
|
||||
subtitle = TextReference.Str(tx.getAmount()),
|
||||
info = tx.extractTimestamp(),
|
||||
subtitle = stringReference(tx.getAmount(cryptoCurrency).trim()),
|
||||
timestamp = tx.extractTimestamp(),
|
||||
subtitleEndOffset = cryptoCurrency.symbol.length,
|
||||
subtitleIconRes = tx.extractIconRes(),
|
||||
)
|
||||
}.insertWallets(walletsItem)
|
||||
|
|
@ -104,8 +108,7 @@ internal class SendRecipientListConverter(
|
|||
R.drawable.ic_arrow_down_24
|
||||
}
|
||||
|
||||
private fun TxHistoryItem.getAmount(): String {
|
||||
val cryptoCurrency = cryptoCurrencyStatusProvider().currency
|
||||
private fun TxHistoryItem.getAmount(cryptoCurrency: CryptoCurrency): String {
|
||||
return amount.toFormattedCurrencyString(
|
||||
currency = cryptoCurrency.symbol,
|
||||
decimals = cryptoCurrency.decimals,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ internal fun SendNavigationButtons(uiState: SendUiState) {
|
|||
private fun SendSecondaryNavigationButton(uiState: SendUiState) {
|
||||
val currentState = uiState.currentState.collectAsState()
|
||||
AnimatedVisibility(
|
||||
visible = currentState.value == SendUiStateType.Recipient ||
|
||||
visible = currentState.value == SendUiStateType.Amount ||
|
||||
currentState.value == SendUiStateType.Fee,
|
||||
) {
|
||||
Icon(
|
||||
|
|
|
|||
|
|
@ -38,16 +38,15 @@ internal fun SendScreen(uiState: SendUiState) {
|
|||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
val titleRes = when (currentState.value) {
|
||||
SendUiStateType.Amount -> R.string.common_send
|
||||
SendUiStateType.Recipient -> R.string.send_recipient
|
||||
SendUiStateType.Amount -> R.string.send_amount_label
|
||||
SendUiStateType.Recipient -> R.string.send_recipient_label
|
||||
SendUiStateType.Fee -> R.string.common_fee_selector_title
|
||||
SendUiStateType.Send -> if (isSuccess?.value == false) R.string.common_send else null
|
||||
SendUiStateType.Send -> if (isSuccess?.value == false) R.string.send_confirm_label else null
|
||||
}
|
||||
val iconRes = when (currentState.value) {
|
||||
SendUiStateType.Amount,
|
||||
SendUiStateType.Recipient,
|
||||
-> R.drawable.ic_qrcode_scan_24
|
||||
else -> null
|
||||
val iconRes = if (currentState.value == SendUiStateType.Recipient) {
|
||||
R.drawable.ic_qrcode_scan_24
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
AppBarWithBackButtonAndIcon(
|
||||
|
|
|
|||
|
|
@ -3,24 +3,26 @@ package com.tangem.features.send.impl.presentation.ui.recipient
|
|||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.constraintlayout.compose.Dimension
|
||||
import androidx.constraintlayout.compose.Visibility
|
||||
import com.tangem.core.ui.components.MiddleEllipsisText
|
||||
import com.tangem.core.ui.components.atoms.text.EllipsisText
|
||||
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
||||
import com.tangem.core.ui.components.icons.identicon.IdentIcon
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.send.impl.R
|
||||
|
|
@ -33,6 +35,7 @@ import com.tangem.features.send.impl.R
|
|||
* @param onClick click listener
|
||||
* @param modifier modifier
|
||||
* @param info info
|
||||
* @param subtitleEndOffset offset for subtitle ellipsis
|
||||
* @param subtitleIconRes icon
|
||||
*/
|
||||
@Suppress("DestructuringDeclarationWithTooManyEntries", "LongMethod")
|
||||
|
|
@ -43,6 +46,7 @@ fun ListItemWithIcon(
|
|||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
info: String? = null,
|
||||
subtitleEndOffset: Int = 0,
|
||||
@DrawableRes subtitleIconRes: Int? = null,
|
||||
) {
|
||||
ConstraintLayout(
|
||||
|
|
@ -51,7 +55,7 @@ fun ListItemWithIcon(
|
|||
.clickable { onClick() }
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
val (iconRef, titleRef, subtitleRef, subtitleIconRef, infoRef) = createRefs()
|
||||
val (iconRef, titleRef, subtitleRef, subtitleIconRef) = createRefs()
|
||||
|
||||
val spacing2 = TangemTheme.dimens.spacing2
|
||||
val spacing8 = TangemTheme.dimens.spacing8
|
||||
|
|
@ -68,11 +72,12 @@ fun ListItemWithIcon(
|
|||
bottom.linkTo(parent.bottom, margin = spacing8)
|
||||
},
|
||||
)
|
||||
MiddleEllipsisText(
|
||||
EllipsisText(
|
||||
text = title,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Justify,
|
||||
ellipsis = TextEllipsis.Middle,
|
||||
modifier = Modifier
|
||||
.constrainAs(titleRef) {
|
||||
start.linkTo(iconRef.end, margin = spacing12)
|
||||
|
|
@ -87,7 +92,7 @@ fun ListItemWithIcon(
|
|||
tint = TangemTheme.colors.icon.informative,
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size16)
|
||||
.background(TangemTheme.colors.background.tertiary, CircleShape)
|
||||
.background(TangemTheme.colors.icon.informative.copy(alpha = 0.1f), CircleShape)
|
||||
.constrainAs(subtitleIconRef) {
|
||||
start.linkTo(iconRef.end, margin = spacing12)
|
||||
top.linkTo(titleRef.bottom)
|
||||
|
|
@ -95,36 +100,29 @@ fun ListItemWithIcon(
|
|||
visibility = if (subtitleIconRes == null) Visibility.Gone else Visibility.Visible
|
||||
},
|
||||
)
|
||||
Text(
|
||||
text = subtitle,
|
||||
|
||||
val (text, offset) = remember(subtitle, info) {
|
||||
if (info != null) {
|
||||
val suffix = ", $info"
|
||||
subtitle + suffix to suffix.length + subtitleEndOffset
|
||||
} else {
|
||||
subtitle to 0
|
||||
}
|
||||
}
|
||||
EllipsisText(
|
||||
text = text,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
ellipsis = TextEllipsis.OffsetEnd(offsetEnd = offset),
|
||||
modifier = Modifier
|
||||
.constrainAs(subtitleRef) {
|
||||
start.linkTo(subtitleIconRef.end, margin = spacing2, goneMargin = spacing12)
|
||||
end.linkTo(infoRef.start)
|
||||
end.linkTo(parent.end)
|
||||
top.linkTo(titleRef.bottom)
|
||||
bottom.linkTo(parent.bottom, margin = spacing10)
|
||||
width = Dimension.fillToConstraints
|
||||
},
|
||||
)
|
||||
info?.let {
|
||||
Text(
|
||||
text = it,
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
modifier = Modifier
|
||||
.constrainAs(infoRef) {
|
||||
start.linkTo(subtitleRef.end, goneMargin = spacing12)
|
||||
end.linkTo(parent.end)
|
||||
top.linkTo(titleRef.bottom)
|
||||
bottom.linkTo(parent.bottom, margin = spacing10)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +136,7 @@ private fun ListItemWithIconPreview_Light(
|
|||
ListItemWithIcon(
|
||||
title = config.title,
|
||||
subtitle = config.subtitle,
|
||||
info = config.info,
|
||||
subtitleEndOffset = config.subtitleEndOffset,
|
||||
subtitleIconRes = config.iconRes,
|
||||
onClick = {},
|
||||
)
|
||||
|
|
@ -154,7 +152,7 @@ private fun ListItemWithIconPreview_Dark(
|
|||
ListItemWithIcon(
|
||||
title = config.title,
|
||||
subtitle = config.subtitle,
|
||||
info = config.info,
|
||||
subtitleEndOffset = config.subtitleEndOffset,
|
||||
subtitleIconRes = config.iconRes,
|
||||
onClick = {},
|
||||
)
|
||||
|
|
@ -165,6 +163,7 @@ private data class ListItemWithIconPreviewConfig(
|
|||
val title: String,
|
||||
val subtitle: String,
|
||||
val info: String? = null,
|
||||
val subtitleEndOffset: Int = 0,
|
||||
val iconRes: Int? = null,
|
||||
)
|
||||
|
||||
|
|
@ -174,12 +173,14 @@ private class ListItemWithIconPreviewProvider : CollectionPreviewParameterProvid
|
|||
title = "0x34B4492A412D84A6E606288f3Bd714b89135D4dE",
|
||||
subtitle = "0.000000000000000000000000000000 BTC",
|
||||
info = "0.0.0000 at 00:00",
|
||||
subtitleEndOffset = "BTC".length,
|
||||
iconRes = R.drawable.ic_arrow_down_24,
|
||||
),
|
||||
ListItemWithIconPreviewConfig(
|
||||
title = "0x34B4492A412D84A6E606288f3Bd714b89135D4dE",
|
||||
subtitle = "1 BTC",
|
||||
info = "0.0.0000 at 00:00",
|
||||
subtitleEndOffset = "BTC".length,
|
||||
iconRes = R.drawable.ic_arrow_down_24,
|
||||
),
|
||||
ListItemWithIconPreviewConfig(
|
||||
|
|
|
|||
|
|
@ -141,7 +141,8 @@ private fun LazyListScope.recipientListItem(
|
|||
ListItemWithIcon(
|
||||
title = item.title.resolveReference(),
|
||||
subtitle = item.subtitle.resolveReference(),
|
||||
info = item.info?.let { ", ${it.resolveReference()}" },
|
||||
info = item.timestamp?.resolveReference(),
|
||||
subtitleEndOffset = item.subtitleEndOffset,
|
||||
subtitleIconRes = item.subtitleIconRes,
|
||||
modifier = Modifier
|
||||
.then(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue