Updated on 2026-08-14
This commit is contained in:
parent
3378f50dd2
commit
fd93510a74
8 changed files with 438 additions and 359 deletions
|
|
@ -1,155 +0,0 @@
|
|||
package com.tangem.tap.features.tokens.ui.compose
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.tap.common.extensions.getGreyedOutIconRes
|
||||
import com.tangem.tap.common.extensions.getRoundIconRes
|
||||
import com.tangem.tap.domain.tokens.Currency
|
||||
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Composable
|
||||
fun CollapsedCurrencyItem(
|
||||
currency: Currency,
|
||||
addedTokens: List<TokenWithBlockchain>,
|
||||
addedBlockchains: List<Blockchain>,
|
||||
onCurrencyClick: (String) -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = { onCurrencyClick(currency.id) })
|
||||
) {
|
||||
val blockchain = Blockchain.fromNetworkId(currency.id)
|
||||
|
||||
SubcomposeAsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(currency.iconUrl)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
contentDescription = currency.id,
|
||||
loading = { CurrencyPlaceholderIcon(currency.id) },
|
||||
error = { CurrencyPlaceholderIcon(currency.id) },
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.padding(16.dp)
|
||||
.size(46.dp),
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.align(Alignment.CenterVertically)
|
||||
) {
|
||||
Text(
|
||||
text = currency.fullName,
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(0xFF1C1C1E),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(6.dp))
|
||||
Row {
|
||||
if (!currency.contracts.isNullOrEmpty()) {
|
||||
currency.contracts.map { contract ->
|
||||
if (contract.address == null) {
|
||||
BlockchainNetworkItem(
|
||||
blockchain = contract.blockchain,
|
||||
isMainNetwork = true,
|
||||
addedBlockchains = addedBlockchains
|
||||
)
|
||||
} else {
|
||||
val added =
|
||||
addedTokens.map { it.token.contractAddress }
|
||||
.contains(contract.address)
|
||||
val icon = if (added) {
|
||||
contract.blockchain.getRoundIconRes()
|
||||
} else {
|
||||
contract.blockchain.getGreyedOutIconRes()
|
||||
}
|
||||
Image(
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = null,
|
||||
Modifier
|
||||
.size(20.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.size(5.dp))
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
BlockchainNetworkItem(
|
||||
blockchain = blockchain,
|
||||
isMainNetwork = false,
|
||||
addedBlockchains = addedBlockchains
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_arrow_collapsed),
|
||||
contentDescription = null,
|
||||
Modifier
|
||||
.padding(20.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BlockchainNetworkItem(
|
||||
blockchain: Blockchain?,
|
||||
isMainNetwork: Boolean,
|
||||
addedBlockchains: List<Blockchain>
|
||||
) {
|
||||
val added = addedBlockchains.contains(blockchain)
|
||||
val icon =
|
||||
if (added) blockchain?.getRoundIconRes() else blockchain?.getGreyedOutIconRes()
|
||||
if (icon != null) {
|
||||
Box(Modifier
|
||||
.size(20.dp)) {
|
||||
Image(
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = null,
|
||||
Modifier
|
||||
.size(20.dp)
|
||||
)
|
||||
if (isMainNetwork) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.size(7.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(5.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color(0xFF1ACE80))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.size(5.dp))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
package com.tangem.tap.features.tokens.ui.compose
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.tap.domain.tokens.Currency
|
||||
import com.tangem.tap.features.tokens.redux.ContractAddress
|
||||
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Composable
|
||||
fun ExpandedCurrencyItem(
|
||||
currency: Currency,
|
||||
addedTokens: List<TokenWithBlockchain>,
|
||||
addedBlockchains: List<Blockchain>,
|
||||
allowToAdd: Boolean,
|
||||
onCurrencyClick: (String) -> Unit,
|
||||
onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit,
|
||||
onNetworkItemClicked: (ContractAddress) -> Unit
|
||||
) {
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = { onCurrencyClick(currency.id) })
|
||||
) {
|
||||
SubcomposeAsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(currency.iconUrl)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
contentDescription = currency.id,
|
||||
loading = { CurrencyPlaceholderIcon(currency.id) },
|
||||
error = { CurrencyPlaceholderIcon(currency.id) },
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.padding(start = 16.dp, top = 16.dp, end = 16.dp)
|
||||
.size(46.dp),
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.padding(top = 14.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
) {
|
||||
Text(
|
||||
text = currency.fullName,
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(0xFF1C1C1E),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(6.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.currency_subtitle_expanded),
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(0xFF8E8E93),
|
||||
)
|
||||
}
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_arrow_extended),
|
||||
contentDescription = null,
|
||||
Modifier
|
||||
.padding(20.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
|
||||
val blockchains = currency.contracts.map { it.blockchain }
|
||||
|
||||
Row {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
) {
|
||||
if (blockchains.size > 1) {
|
||||
val dividerHeight = if (blockchains.size == 2) {
|
||||
60
|
||||
} else if (blockchains.size == 3) {
|
||||
110
|
||||
} else {
|
||||
43 * blockchains.size
|
||||
}
|
||||
Divider(
|
||||
color = Color(0xFFDEDEDE),
|
||||
modifier = Modifier
|
||||
.height(dividerHeight.dp)
|
||||
.padding(start = 37.5.dp)
|
||||
.width(1.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Column {
|
||||
blockchains.map {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_link),
|
||||
contentDescription = null,
|
||||
Modifier
|
||||
.padding(
|
||||
start = 37.dp,
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.size(13.5.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 6.dp),
|
||||
) {
|
||||
blockchains.map { blockchain ->
|
||||
val contract = currency.contracts.firstOrNull { it.blockchain == blockchain }
|
||||
?: return@map
|
||||
val added = if (contract.address != null) {
|
||||
addedTokens.map { it.token.contractAddress }.contains(contract.address)
|
||||
} else {
|
||||
addedBlockchains.contains(blockchain)
|
||||
}
|
||||
NetworkItem(
|
||||
currency = currency,
|
||||
contract = contract,
|
||||
blockchain = blockchain,
|
||||
allowToAdd = allowToAdd,
|
||||
added = added,
|
||||
onAddCurrencyToggled = onAddCurrencyToggled,
|
||||
onNetworkItemClicked = onNetworkItemClicked,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.features.tokens.ui.compose
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
|
|
@ -16,7 +17,7 @@ import com.tangem.tap.common.compose.extensions.OnBottomReached
|
|||
import com.tangem.tap.domain.tokens.Currency
|
||||
import com.tangem.tap.features.tokens.redux.ContractAddress
|
||||
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
|
||||
|
||||
import com.tangem.tap.features.tokens.ui.compose.currencyItem.CurrencyItem
|
||||
|
||||
@Composable
|
||||
fun ListOfCurrencies(
|
||||
|
|
@ -27,7 +28,7 @@ fun ListOfCurrencies(
|
|||
allowToAdd: Boolean,
|
||||
onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit,
|
||||
onNetworkItemClicked: (ContractAddress) -> Unit,
|
||||
onLoadMore: () -> Unit
|
||||
onLoadMore: () -> Unit,
|
||||
) {
|
||||
|
||||
val expandedCurrencies = remember { mutableStateOf(listOf("")) }
|
||||
|
|
@ -50,7 +51,8 @@ fun ListOfCurrencies(
|
|||
state = listState,
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
contentPadding = PaddingValues(bottom = 90.dp)
|
||||
contentPadding = PaddingValues(bottom = 90.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
item { header() }
|
||||
itemsIndexed(currencies) { index, currency ->
|
||||
|
|
@ -59,10 +61,10 @@ fun ListOfCurrencies(
|
|||
addedTokens = addedTokens,
|
||||
addedBlockchains = addedBlockchains,
|
||||
allowToAdd = allowToAdd,
|
||||
expanded = expandedCurrencies.value.contains(currency.id),
|
||||
isExpanded = expandedCurrencies.value.contains(currency.id),
|
||||
onCurrencyClick = onCurrencyClick,
|
||||
onAddCurrencyToggled = onAddCurrencyToggled,
|
||||
onNetworkItemClicked = onNetworkItemClicked
|
||||
onNetworkItemClicked = onNetworkItemClicked,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package com.tangem.tap.features.tokens.ui.compose.currencyItem
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.tap.domain.tokens.Currency
|
||||
import com.tangem.tap.features.tokens.redux.ContractAddress
|
||||
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
|
||||
|
||||
@Composable
|
||||
fun CurrencyExpandedContent(
|
||||
currency: Currency,
|
||||
addedTokens: List<TokenWithBlockchain>,
|
||||
addedBlockchains: List<Blockchain>,
|
||||
allowToAdd: Boolean,
|
||||
isExpanded: Boolean,
|
||||
onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit,
|
||||
onNetworkItemClicked: (ContractAddress) -> Unit,
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = isExpanded,
|
||||
enter = fadeIn() + expandVertically(),
|
||||
exit = fadeOut() + shrinkVertically(),
|
||||
) {
|
||||
val blockchains = currency.contracts.map { it.blockchain }
|
||||
Row {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
blockchains.mapIndexed { index, blockchain ->
|
||||
val contract = currency.contracts.firstOrNull { it.blockchain == blockchain }
|
||||
?: return@mapIndexed
|
||||
val added = if (contract.address != null) {
|
||||
addedTokens.map { it.token.contractAddress }.contains(contract.address)
|
||||
} else {
|
||||
addedBlockchains.contains(blockchain)
|
||||
}
|
||||
NetworkItem(
|
||||
currency = currency,
|
||||
contract = contract,
|
||||
blockchain = blockchain,
|
||||
allowToAdd = allowToAdd,
|
||||
added = added,
|
||||
index = index,
|
||||
size = blockchains.size,
|
||||
onAddCurrencyToggled = onAddCurrencyToggled,
|
||||
onNetworkItemClicked = onNetworkItemClicked,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.features.tokens.ui.compose
|
||||
package com.tangem.tap.features.tokens.ui.compose.currencyItem
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.tap.domain.tokens.Currency
|
||||
|
|
@ -12,24 +13,27 @@ fun CurrencyItem(
|
|||
addedTokens: List<TokenWithBlockchain>,
|
||||
addedBlockchains: List<Blockchain>,
|
||||
allowToAdd: Boolean,
|
||||
expanded: Boolean,
|
||||
isExpanded: Boolean,
|
||||
onCurrencyClick: (String) -> Unit,
|
||||
onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit,
|
||||
onNetworkItemClicked: (ContractAddress) -> Unit
|
||||
onNetworkItemClicked: (ContractAddress) -> Unit,
|
||||
) {
|
||||
if (expanded) {
|
||||
ExpandedCurrencyItem(
|
||||
Column {
|
||||
CurrencyItemHeader(
|
||||
currency = currency,
|
||||
addedTokens = addedTokens,
|
||||
addedBlockchains = addedBlockchains,
|
||||
isExpanded = isExpanded,
|
||||
onCurrencyClick = onCurrencyClick,
|
||||
)
|
||||
CurrencyExpandedContent(
|
||||
currency = currency,
|
||||
addedTokens = addedTokens,
|
||||
addedBlockchains = addedBlockchains,
|
||||
allowToAdd = allowToAdd,
|
||||
onCurrencyClick = onCurrencyClick, onAddCurrencyToggled = onAddCurrencyToggled,
|
||||
onNetworkItemClicked = onNetworkItemClicked
|
||||
)
|
||||
} else {
|
||||
CollapsedCurrencyItem(
|
||||
currency = currency, addedTokens = addedTokens,
|
||||
addedBlockchains = addedBlockchains, onCurrencyClick
|
||||
isExpanded = isExpanded,
|
||||
onAddCurrencyToggled = onAddCurrencyToggled,
|
||||
onNetworkItemClicked = onNetworkItemClicked,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package com.tangem.tap.features.tokens.ui.compose.currencyItem
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.wallet.R
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
fun CurrencyItemArrow(
|
||||
rowHeight: Dp,
|
||||
isLastArrow: Boolean,
|
||||
) {
|
||||
Box(Modifier.height(rowHeight)) {
|
||||
if (!isLastArrow) {
|
||||
MiddleArrowView(rowHeight)
|
||||
} else {
|
||||
LastArrowView(rowHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MiddleArrowView(rowHeight: Dp) {
|
||||
Box {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(start = 0.5.dp),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(color = Color(0xFFDEDEDE))
|
||||
.width(0.8.dp)
|
||||
.fillMaxHeight(),
|
||||
)
|
||||
}
|
||||
|
||||
LastArrowView(rowHeight)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LastArrowView(rowHeight: Dp) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.height(rowHeight / 2 + 3.5.dp),
|
||||
painter = painterResource(id = R.drawable.ic_link),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ArrowViewPreview() {
|
||||
Box(
|
||||
Modifier
|
||||
.background(color = Color.White),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(start = 37.dp),
|
||||
) {
|
||||
CurrencyItemArrow(
|
||||
rowHeight = 62.dp,
|
||||
isLastArrow = false,
|
||||
)
|
||||
CurrencyItemArrow(
|
||||
rowHeight = 62.dp,
|
||||
isLastArrow = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
package com.tangem.tap.features.tokens.ui.compose.currencyItem
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
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.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.tap.common.extensions.getGreyedOutIconRes
|
||||
import com.tangem.tap.common.extensions.getRoundIconRes
|
||||
import com.tangem.tap.domain.tokens.Currency
|
||||
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
|
||||
import com.tangem.tap.features.tokens.ui.compose.CurrencyPlaceholderIcon
|
||||
import com.tangem.tap.features.tokens.ui.compose.fullName
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Composable
|
||||
fun CurrencyItemHeader(
|
||||
currency: Currency,
|
||||
addedTokens: List<TokenWithBlockchain>,
|
||||
addedBlockchains: List<Blockchain>,
|
||||
isExpanded: Boolean,
|
||||
onCurrencyClick: (String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(62.dp)
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = { onCurrencyClick(currency.id) },
|
||||
),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
.clip(RoundedCornerShape(6.dp)),
|
||||
) {
|
||||
SubcomposeAsyncImage(
|
||||
modifier = Modifier
|
||||
.size(46.dp),
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(currency.iconUrl)
|
||||
.crossfade(true)
|
||||
.build(),
|
||||
contentDescription = currency.id,
|
||||
loading = { CurrencyPlaceholderIcon(currency.id) },
|
||||
error = { CurrencyPlaceholderIcon(currency.id) },
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.align(Alignment.CenterVertically),
|
||||
) {
|
||||
Text(
|
||||
text = currency.fullName,
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(0xFF1C1C1E),
|
||||
)
|
||||
Spacer(modifier = Modifier.size(6.dp))
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp),
|
||||
) {
|
||||
if (isExpanded) {
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.TopStart),
|
||||
text = stringResource(id = R.string.currency_subtitle_expanded),
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = Color(0xFF8E8E93),
|
||||
)
|
||||
} else {
|
||||
NetworksRow(
|
||||
currency = currency,
|
||||
addedTokens = addedTokens,
|
||||
addedBlockchains = addedBlockchains,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val expandCollapseArrow = if (isExpanded) R.drawable.ic_arrow_extended else R.drawable.ic_arrow_collapsed
|
||||
Image(
|
||||
painter = painterResource(id = expandCollapseArrow),
|
||||
contentDescription = null,
|
||||
Modifier
|
||||
.padding(20.dp)
|
||||
.align(Alignment.CenterVertically),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetworksRow(
|
||||
currency: Currency,
|
||||
addedTokens: List<TokenWithBlockchain>,
|
||||
addedBlockchains: List<Blockchain>,
|
||||
) {
|
||||
Row {
|
||||
if (currency.contracts.isNotEmpty()) {
|
||||
currency.contracts.map { contract ->
|
||||
if (contract.address == null) {
|
||||
BlockchainNetworkItem(
|
||||
blockchain = contract.blockchain,
|
||||
isMainNetwork = true,
|
||||
addedBlockchains = addedBlockchains,
|
||||
)
|
||||
} else {
|
||||
val isAdded = addedTokens.map { it.token.contractAddress }.contains(contract.address)
|
||||
val iconResId = if (isAdded) {
|
||||
contract.blockchain.getRoundIconRes()
|
||||
} else {
|
||||
contract.blockchain.getGreyedOutIconRes()
|
||||
}
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(20.dp),
|
||||
painter = painterResource(id = iconResId),
|
||||
contentDescription = null,
|
||||
)
|
||||
Spacer(Modifier.size(5.dp))
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
BlockchainNetworkItem(
|
||||
blockchain = Blockchain.fromNetworkId(currency.id),
|
||||
isMainNetwork = false,
|
||||
addedBlockchains = addedBlockchains,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BlockchainNetworkItem(
|
||||
blockchain: Blockchain?,
|
||||
isMainNetwork: Boolean,
|
||||
addedBlockchains: List<Blockchain>,
|
||||
) {
|
||||
val added = addedBlockchains.contains(blockchain)
|
||||
val icon =
|
||||
if (added) blockchain?.getRoundIconRes() else blockchain?.getGreyedOutIconRes()
|
||||
if (icon != null) {
|
||||
Box(
|
||||
Modifier
|
||||
.size(20.dp),
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = null,
|
||||
Modifier
|
||||
.size(20.dp),
|
||||
)
|
||||
if (isMainNetwork) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.size(7.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(5.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color(0xFF1ACE80)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.size(5.dp))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,18 @@
|
|||
package com.tangem.tap.features.tokens.ui.compose
|
||||
package com.tangem.tap.features.tokens.ui.compose.currencyItem
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Switch
|
||||
import androidx.compose.material.SwitchDefaults
|
||||
|
|
@ -31,6 +39,7 @@ import com.tangem.tap.domain.tokens.Contract
|
|||
import com.tangem.tap.domain.tokens.Currency
|
||||
import com.tangem.tap.features.tokens.redux.ContractAddress
|
||||
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
|
||||
import com.tangem.tap.features.tokens.ui.compose.CurrencyPlaceholderIcon
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
|
|
@ -40,13 +49,17 @@ fun NetworkItem(
|
|||
blockchain: Blockchain,
|
||||
allowToAdd: Boolean,
|
||||
added: Boolean,
|
||||
index: Int,
|
||||
size: Int,
|
||||
onAddCurrencyToggled: (Currency, TokenWithBlockchain?) -> Unit,
|
||||
onNetworkItemClicked: (ContractAddress) -> Unit
|
||||
onNetworkItemClicked: (ContractAddress) -> Unit,
|
||||
) {
|
||||
val rowHeight = 53.dp
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(rowHeight)
|
||||
.combinedClickable(
|
||||
enabled = allowToAdd,
|
||||
onLongClick = {
|
||||
|
|
@ -54,13 +67,22 @@ fun NetworkItem(
|
|||
},
|
||||
onClick = {},
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
)
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
),
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.width(78.dp)
|
||||
.padding(start = 38.dp),
|
||||
) {
|
||||
CurrencyItemArrow(
|
||||
rowHeight = rowHeight,
|
||||
isLastArrow = index == size - 1,
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.padding(start = 8.dp, top = 16.dp, bottom = 16.dp, end = 6.dp)
|
||||
.align(Alignment.CenterVertically),
|
||||
) {
|
||||
SubcomposeAsyncImage(
|
||||
model = if (added) blockchain.getRoundIconRes() else blockchain.getGreyedOutIconRes(),
|
||||
|
|
@ -68,7 +90,7 @@ fun NetworkItem(
|
|||
loading = { CurrencyPlaceholderIcon(blockchain.id) },
|
||||
error = { CurrencyPlaceholderIcon(blockchain.id) },
|
||||
modifier = Modifier
|
||||
.size(20.dp)
|
||||
.size(20.dp),
|
||||
)
|
||||
if (contract.address == null) {
|
||||
Box(
|
||||
|
|
@ -76,34 +98,31 @@ fun NetworkItem(
|
|||
.align(Alignment.TopEnd)
|
||||
.size(7.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White)
|
||||
.background(Color.White),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(5.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color(0xFF1ACE80))
|
||||
.background(Color(0xFF1ACE80)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(
|
||||
Spacer(Modifier.width(6.dp))
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.align(Alignment.CenterVertically)
|
||||
) {
|
||||
Text(
|
||||
text = prepareNetworkNameSpannableText(
|
||||
blockchain = blockchain,
|
||||
contractAddress = contract.address
|
||||
),
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 13.sp,
|
||||
color = if (added) Color.Black else Color(0xFF848488),
|
||||
)
|
||||
}
|
||||
.align(Alignment.CenterVertically),
|
||||
text = prepareNetworkNameSpannableText(
|
||||
blockchain = blockchain,
|
||||
contractAddress = contract.address,
|
||||
),
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 13.sp,
|
||||
color = if (added) Color.Black else Color(0xFF848488),
|
||||
)
|
||||
|
||||
if (allowToAdd) {
|
||||
val token = if (contract.address != null) {
|
||||
|
|
@ -117,8 +136,7 @@ fun NetworkItem(
|
|||
} else {
|
||||
null
|
||||
}
|
||||
val tokenWithBlockchain =
|
||||
token?.let { TokenWithBlockchain(token, contract.blockchain) }
|
||||
val tokenWithBlockchain = token?.let { TokenWithBlockchain(it, contract.blockchain) }
|
||||
|
||||
val currencyToSave = if (contract.address == null) {
|
||||
currency.copy(id = contract.networkId)
|
||||
|
|
@ -127,22 +145,23 @@ fun NetworkItem(
|
|||
}
|
||||
|
||||
Switch(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(start = 16.dp, end = 16.dp),
|
||||
checked = added,
|
||||
onCheckedChange = { onAddCurrencyToggled(currencyToSave, tokenWithBlockchain) },
|
||||
modifier = Modifier.padding(start = 16.dp, end = 16.dp),
|
||||
colors = SwitchDefaults.colors(
|
||||
checkedThumbColor = Color(0xFF1ACE80)
|
||||
)
|
||||
checkedThumbColor = Color(0xFF1ACE80),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun prepareNetworkNameSpannableText(
|
||||
private fun prepareNetworkNameSpannableText(
|
||||
blockchain: Blockchain,
|
||||
contractAddress: String?
|
||||
contractAddress: String?,
|
||||
): AnnotatedString {
|
||||
|
||||
val blockchainName = blockchain.fullNameWithoutTestnet.uppercase()
|
||||
|
|
@ -158,11 +177,11 @@ fun prepareNetworkNameSpannableText(
|
|||
AnnotatedString.Range(
|
||||
SpanStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = if (contractAddress != null) Color(0xFF8E8E93) else Color(0xFF1ACE80)
|
||||
color = if (contractAddress != null) Color(0xFF8E8E93) else Color(0xFF1ACE80),
|
||||
),
|
||||
start = startOfAdditionalText,
|
||||
end = text.length
|
||||
)
|
||||
end = text.length,
|
||||
),
|
||||
)
|
||||
return AnnotatedString(text = text, spanStyles = spanStyles)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue