Updated on 2026-08-14
This commit is contained in:
commit
c62e02ae91
24 changed files with 755 additions and 451 deletions
4
.idea/codeStyles/Project.xml
generated
4
.idea/codeStyles/Project.xml
generated
|
|
@ -175,8 +175,8 @@
|
|||
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
|
||||
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
|
||||
<option name="LINE_COMMENT_ADD_SPACE_ON_REFORMAT" value="true" />
|
||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="0" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="0" />
|
||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="EXTENDS_LIST_WRAP" value="5" />
|
||||
|
|
|
|||
|
|
@ -148,14 +148,14 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
|
|||
val techService = store.state.domainNetworks.tangemTechService
|
||||
when (val result = techService.userCountry()) {
|
||||
is Result.Success -> {
|
||||
store.dispatch(
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.FetchUserCountry.Success(
|
||||
countryCode = result.data.code.lowercase()
|
||||
)
|
||||
)
|
||||
}
|
||||
is Result.Failure -> {
|
||||
store.dispatch(
|
||||
store.dispatchOnMain(
|
||||
GlobalAction.FetchUserCountry.Success(
|
||||
countryCode = Locale.getDefault().country.lowercase()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ class ConfigManager(
|
|||
blockchairApiKey = values.blockchairApiKey,
|
||||
blockchairAuthorizationToken = values.blockchairAuthorizationToken,
|
||||
blockcypherTokens = values.blockcypherTokens,
|
||||
infuraProjectId = values.infuraProjectId
|
||||
infuraProjectId = values.infuraProjectId,
|
||||
tronGridApiKey = values.tronGridApiKey
|
||||
),
|
||||
appsFlyerDevKey = values.appsFlyerDevKey,
|
||||
shopify = values.shopifyShop,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class ConfigValueModel(
|
|||
val appsFlyerDevKey: String,
|
||||
val shopifyShop: ShopifyShop?,
|
||||
val zendesk: ZendeskConfig?,
|
||||
val tronGridApiKey: String,
|
||||
)
|
||||
|
||||
class ConfigModel(val features: FeatureModel?, val configValues: ConfigValueModel?) {
|
||||
|
|
|
|||
|
|
@ -104,56 +104,25 @@ class DemoConfig {
|
|||
?: Amount(BigDecimal.ZERO, blockchain).copy()
|
||||
|
||||
private fun getReleaseIds(): List<String> {
|
||||
return (releaseDemoCardIds +
|
||||
releaseDemoCardIds_19042022 +
|
||||
testDemoCardIds).distinct()
|
||||
return (releaseDemoCardIds + testDemoCardIds).distinct()
|
||||
}
|
||||
|
||||
private val releaseDemoCardIds = mutableListOf(
|
||||
// Tangem Wallet:
|
||||
"AC01000000041100",
|
||||
"AC01000000042462",
|
||||
"AC01000000041647",
|
||||
"AC01000000041621",
|
||||
"AC01000000041217",
|
||||
// === Not from the Google Sheet table ===
|
||||
"FB10000000000196", // Note BTC
|
||||
"FB20000000000186", // Note ETH
|
||||
"FB30000000000176", // Wallet
|
||||
"AC01000000041225",
|
||||
"AC01000000041209",
|
||||
"AC01000000041092",
|
||||
"AC01000000041472",
|
||||
"AC01000000041662",
|
||||
"AC01000000045754",
|
||||
"AC01000000045960",
|
||||
// Tangem Note BTC:
|
||||
"AB01000000046530",
|
||||
"AB01000000046720",
|
||||
"AB01000000046746",
|
||||
"AB01000000046498",
|
||||
"AB01000000046753",
|
||||
"AB01000000049608",
|
||||
"AB01000000046761",
|
||||
"AB01000000049574",
|
||||
"AB01000000046605",
|
||||
"AB01000000046571",
|
||||
"AB01000000046704",
|
||||
"AB01000000046647",
|
||||
// Tangem Note Ethereum:
|
||||
"AB02000000051000",
|
||||
"AB02000000050986",
|
||||
"AB02000000051026",
|
||||
"AB02000000051042",
|
||||
"AB02000000051091",
|
||||
"AB02000000051083",
|
||||
"AB02000000050960",
|
||||
"AB02000000051034",
|
||||
"AB02000000050911",
|
||||
"AB02000000051133",
|
||||
"AB02000000051158",
|
||||
"AB02000000051059",
|
||||
)
|
||||
|
||||
// https://tangem.slack.com/archives/GMXC6PP71/p1650360610759269
|
||||
private val releaseDemoCardIds_19042022 = listOf(
|
||||
// Wallet
|
||||
// === Mvideo ===
|
||||
// Wallet
|
||||
"AC01000000045754",
|
||||
"AC01000000041662",
|
||||
"AC01000000041647",
|
||||
|
|
@ -186,7 +155,58 @@ class DemoConfig {
|
|||
"AC01000000013497",
|
||||
"AC01000000013836",
|
||||
"AC01000000013505",
|
||||
// Note BTC
|
||||
"AC03000000046693",
|
||||
"AC03000000046685",
|
||||
"AC03000000046677",
|
||||
"AC03000000046669",
|
||||
"AC03000000046651",
|
||||
"AC03000000046644",
|
||||
"AC03000000046636",
|
||||
"AC03000000046628",
|
||||
"AC03000000046610",
|
||||
"AC03000000046602",
|
||||
"AC03000000046594",
|
||||
"AC03000000046586",
|
||||
"AC03000000046578",
|
||||
"AC03000000046560",
|
||||
"AC03000000046552",
|
||||
"AC03000000046545",
|
||||
"AC03000000046537",
|
||||
"AC03000000046529",
|
||||
"AC03000000046511",
|
||||
"AC03000000046800",
|
||||
"AC03000000046792",
|
||||
"AC03000000046784",
|
||||
"AC03000000046776",
|
||||
"AC03000000046768",
|
||||
"AC03000000046750",
|
||||
"AC03000000046743",
|
||||
"AC03000000046735",
|
||||
"AC03000000046727",
|
||||
"AC03000000046446",
|
||||
"AC03000000046438",
|
||||
"AC03000000046412",
|
||||
"AC03000000046388",
|
||||
"AC03000000046370",
|
||||
"AC03000000046354",
|
||||
"AC03000000046347",
|
||||
"AC03000000046339",
|
||||
"AC03000000046321",
|
||||
"AC03000000046172",
|
||||
"AC03000000046396",
|
||||
"AC03000000046404",
|
||||
"AC03000000046701",
|
||||
"AC03000000046420",
|
||||
"AC03000000046719",
|
||||
"AC03000000046503",
|
||||
"AC03000000046495",
|
||||
"AC03000000046487",
|
||||
"AC03000000046362",
|
||||
"AC03000000046479",
|
||||
"AC03000000046461",
|
||||
"AC03000000046453",
|
||||
|
||||
// Note BTC
|
||||
"AB01000000059608",
|
||||
"AB01000000046647",
|
||||
"AB01000000046571",
|
||||
|
|
@ -219,7 +239,58 @@ class DemoConfig {
|
|||
"AB01000000015782",
|
||||
"AB01000000022598",
|
||||
"AB01000000022580",
|
||||
// Note ETH
|
||||
"AB01000000005688",
|
||||
"AB07000000005696",
|
||||
"AB07000000005902",
|
||||
"AB07000000005910",
|
||||
"AB07000000005928",
|
||||
"AB07000000005936",
|
||||
"AB07000000005944",
|
||||
"AB07000000005993",
|
||||
"AB07000000005985",
|
||||
"AB07000000005977",
|
||||
"AB07000000005969",
|
||||
"AB07000000005951",
|
||||
"AB07000000005605",
|
||||
"AB07000000005803",
|
||||
"AB07000000005811",
|
||||
"AB07000000005829",
|
||||
"AB07000000005837",
|
||||
"AB07000000005845",
|
||||
"AB07000000005852",
|
||||
"AB07000000005860",
|
||||
"AB07000000005878",
|
||||
"AB07000000005886",
|
||||
"AB07000000005894",
|
||||
"AB07000000005704",
|
||||
"AB07000000005712",
|
||||
"AB07000000005720",
|
||||
"AB07000000005738",
|
||||
"AB07000000005746",
|
||||
"AB07000000005514",
|
||||
"AB07000000005522",
|
||||
"AB07000000005563",
|
||||
"AB07000000005571",
|
||||
"AB07000000005589",
|
||||
"AB07000000005597",
|
||||
"AB07000000005613",
|
||||
"AB07000000005621",
|
||||
"AB07000000005639",
|
||||
"AB07000000005647",
|
||||
"AB07000000005654",
|
||||
"AB07000000005662",
|
||||
"AB07000000005670",
|
||||
"AB07000000005530",
|
||||
"AB07000000005548",
|
||||
"AB07000000005555",
|
||||
"AB07000000005753",
|
||||
"AB07000000005761",
|
||||
"AB07000000005779",
|
||||
"AB07000000005787",
|
||||
"AB07000000005795",
|
||||
"AB07000000005506",
|
||||
|
||||
// Note ETH
|
||||
"AB02000000051083",
|
||||
"AB02000000051059",
|
||||
"AB02000000051158",
|
||||
|
|
@ -252,6 +323,123 @@ class DemoConfig {
|
|||
"AB02000000020252",
|
||||
"AB02000000018652",
|
||||
"AB02000000018561",
|
||||
"AB08000000009481",
|
||||
"AB08000000009473",
|
||||
"AB08000000009705",
|
||||
"AB08000000009897",
|
||||
"AB08000000009689",
|
||||
"AB08000000009671",
|
||||
"AB08000000009465",
|
||||
"AB08000000009457",
|
||||
"AB08000000009440",
|
||||
"AB08000000009432",
|
||||
"AB08000000009424",
|
||||
"AB08000000009416",
|
||||
"AB08000000009408",
|
||||
"AB08000000009390",
|
||||
"AB08000000009374",
|
||||
"AB08000000009382",
|
||||
"AB08000000009267",
|
||||
"AB08000000009275",
|
||||
"AB08000000009283",
|
||||
"AB08000000009291",
|
||||
"AB08000000009309",
|
||||
"AB08000000009317",
|
||||
"AB08000000009325",
|
||||
"AB08000000009333",
|
||||
"AB08000000009341",
|
||||
"AB08000000009358",
|
||||
"AB08000000009366",
|
||||
"AB08000000009077",
|
||||
"AB08000000009143",
|
||||
"AB08000000009168",
|
||||
"AB08000000009184",
|
||||
"AB08000000009192",
|
||||
"AB08000000009200",
|
||||
"AB08000000009226",
|
||||
"AB08000000009218",
|
||||
"AB08000000009234",
|
||||
"AB08000000009242",
|
||||
"AB08000000008574",
|
||||
"AB08000000009069",
|
||||
"AB08000000008525",
|
||||
"AB08000000009051",
|
||||
"AB08000000009135",
|
||||
"AB08000000009150",
|
||||
"AB08000000009176",
|
||||
"AB08000000009085",
|
||||
"AB08000000009093",
|
||||
"AB08000000009101",
|
||||
"AB08000000009119",
|
||||
"AB08000000009127",
|
||||
"AB08000000009259",
|
||||
|
||||
// === Technopark ===
|
||||
// Wallet
|
||||
"AC01000000044120",
|
||||
"AC01000000044997",
|
||||
"AC01000000044989",
|
||||
"AC01000000043494",
|
||||
"AC01000000043486",
|
||||
"AC01000000044187",
|
||||
"AC01000000043148",
|
||||
"AC01000000044013",
|
||||
"AC01000000043973",
|
||||
"AC01000000044815",
|
||||
"AC01000000044807",
|
||||
"AC01000000043809",
|
||||
"AC01000000043833",
|
||||
"AC01000000043460",
|
||||
"AC01000000043064",
|
||||
"AC01000000044138",
|
||||
"AC01000000044500",
|
||||
"AC01000000044492",
|
||||
"AC01000000044260",
|
||||
"AC01000000044278",
|
||||
|
||||
// Note BTC
|
||||
"AB01000000049864",
|
||||
"AB01000000053239",
|
||||
"AB01000000053056",
|
||||
"AB01000000054237",
|
||||
"AB01000000054245",
|
||||
"AB01000000054211",
|
||||
"AB01000000054229",
|
||||
"AB01000000053189",
|
||||
"AB01000000054195",
|
||||
"AB01000000050797",
|
||||
"AB01000000053833",
|
||||
"AB01000000052124",
|
||||
"AB01000000051605",
|
||||
"AB01000000052223",
|
||||
"AB01000000052207",
|
||||
"AB01000000052199",
|
||||
"AB01000000047785",
|
||||
"AB01000000047850",
|
||||
"AB01000000047868",
|
||||
"AB01000000048288",
|
||||
|
||||
// Note ETH
|
||||
"AB02000000049715",
|
||||
"AB02000000049848",
|
||||
"AB02000000049814",
|
||||
"AB02000000049863",
|
||||
"AB02000000049871",
|
||||
"AB02000000049855",
|
||||
"AB02000000049285",
|
||||
"AB02000000049277",
|
||||
"AB02000000049558",
|
||||
"AB02000000049889",
|
||||
"AB02000000049988",
|
||||
"AB02000000049707",
|
||||
"AB02000000049699",
|
||||
"AB02000000049897",
|
||||
"AB02000000049905",
|
||||
"AB02000000049913",
|
||||
"AB02000000049251",
|
||||
"AB02000000049533",
|
||||
"AB02000000049541",
|
||||
"AB02000000049830",
|
||||
)
|
||||
|
||||
private val testDemoCardIds = listOf(
|
||||
|
|
@ -281,7 +469,6 @@ class DemoTransactionSender(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
|
||||
val dataToSign = randomString(32).toByteArray()
|
||||
val signerResponse = signer.sign(
|
||||
|
|
|
|||
|
|
@ -74,9 +74,7 @@ fun StoriesScreen(
|
|||
}
|
||||
|
||||
val isPressed = remember { mutableStateOf(false) }
|
||||
val needsToBePaused =
|
||||
remember(homeState) { mutableStateOf(homeState.value.btnScanState.progressState == ProgressState.Loading) }
|
||||
val isPaused = isPressed.value || needsToBePaused.value
|
||||
val isPaused = isPressed.value || homeState.value.btnScanState.progressState == ProgressState.Loading
|
||||
|
||||
val hideContent = remember { mutableStateOf(true) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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,163 +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.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.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.any {
|
||||
it.token.contractAddress == contract.address && it.blockchain == contract.blockchain
|
||||
}
|
||||
} 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,60 @@
|
|||
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.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 }
|
||||
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)
|
||||
}
|
||||
|
|
@ -10,8 +10,8 @@ data class PendingTransaction(
|
|||
val type: PendingTransactionType,
|
||||
) {
|
||||
val address: String? = when (type) {
|
||||
PendingTransactionType.Incoming -> transactionData.destinationAddress
|
||||
PendingTransactionType.Outgoing -> transactionData.sourceAddress
|
||||
PendingTransactionType.Incoming -> transactionData.sourceAddress
|
||||
PendingTransactionType.Outgoing -> transactionData.destinationAddress
|
||||
PendingTransactionType.Unknown -> null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ sealed class WalletWarning(
|
|||
val showingPosition: Int,
|
||||
) {
|
||||
object TransactionInProgress : WalletWarning(10)
|
||||
object SolanaTokensUnsupported : WalletWarning(20)
|
||||
data class BalanceNotEnoughForFee(val blockchainFullName: String) : WalletWarning(30)
|
||||
data class Rent(val walletRent: WalletRent) : WalletWarning(40)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import com.tangem.blockchain.common.WalletManager
|
|||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.domain.common.extensions.canHandleToken
|
||||
import com.tangem.domain.common.extensions.toCoinId
|
||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
||||
import com.tangem.tap.common.entities.Button
|
||||
import com.tangem.tap.common.extensions.toQrCode
|
||||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
|
|
@ -395,19 +397,10 @@ data class WalletData(
|
|||
}
|
||||
|
||||
fun assembleWarnings(): List<WalletWarning> {
|
||||
val blockchain = currency.blockchain
|
||||
val walletWarnings = mutableListOf<WalletWarning>()
|
||||
if (currencyData.status == BalanceStatus.SameCurrencyTransactionInProgress) {
|
||||
walletWarnings.add(WalletWarning.TransactionInProgress)
|
||||
}
|
||||
if (currency.isBlockchain()) {
|
||||
if (blockchain == Blockchain.Solana || blockchain == Blockchain.SolanaTestnet) {
|
||||
val card = store.state.globalState.scanResponse?.card
|
||||
if (card?.canHandleToken(blockchain) == false) {
|
||||
walletWarnings.add(WalletWarning.SolanaTokensUnsupported)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (walletRent != null) {
|
||||
walletWarnings.add(WalletWarning.Rent(walletRent))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@ class WalletWarningConverter(
|
|||
message.blockchainFullName, message.blockchainFullName
|
||||
)
|
||||
}
|
||||
WalletWarning.SolanaTokensUnsupported -> {
|
||||
context.getString(R.string.warning_token_send_unsupported_message)
|
||||
}
|
||||
WalletWarning.TransactionInProgress -> {
|
||||
context.getString(R.string.wallet_pending_transaction_warning)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
package com.tangem.tap.features.wallet.ui.images
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapShader
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Paint
|
||||
import android.graphics.RectF
|
||||
import android.graphics.Shader
|
||||
import androidx.annotation.Px
|
||||
import androidx.core.graphics.applyCanvas
|
||||
import coil.size.Size
|
||||
import coil.size.pxOrElse
|
||||
import coil.transform.Transformation
|
||||
|
||||
class RoundedCornersCropTransformation(
|
||||
@Px val radiusPx: Float,
|
||||
) : Transformation {
|
||||
override val cacheKey: String = "${javaClass.name}-$radiusPx"
|
||||
|
||||
override suspend fun transform(input: Bitmap, size: Size): Bitmap {
|
||||
val outputWidth = size.width.pxOrElse { Int.MAX_VALUE }
|
||||
val outputHeight = size.height.pxOrElse { Int.MAX_VALUE }
|
||||
val outputSize = minOf(outputWidth, outputHeight)
|
||||
val output = Bitmap.createBitmap(outputSize, outputSize, Bitmap.Config.ARGB_8888)
|
||||
|
||||
val rect = RectF(
|
||||
/* left = */ 0f,
|
||||
/* top = */ 0f,
|
||||
/* right = */ outputWidth.toFloat(),
|
||||
/* bottom = */ outputHeight.toFloat()
|
||||
)
|
||||
val matrix = Matrix().apply {
|
||||
setTranslate(
|
||||
/* dx = */ (outputWidth - input.width) * .5f,
|
||||
/* dy = */ (outputHeight - input.height) * .5f
|
||||
)
|
||||
}
|
||||
val bitmapShader = BitmapShader(
|
||||
/* bitmap = */ input,
|
||||
/* tileX = */ Shader.TileMode.DECAL,
|
||||
/* tileY = */ Shader.TileMode.DECAL
|
||||
).apply {
|
||||
setLocalMatrix(matrix)
|
||||
}
|
||||
val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG).apply {
|
||||
shader = bitmapShader
|
||||
}
|
||||
|
||||
return output.applyCanvas {
|
||||
drawRoundRect(
|
||||
/* rect = */ rect,
|
||||
/* rx = */ radiusPx,
|
||||
/* ry = */ radiusPx,
|
||||
/* paint = */ paint
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -244,8 +244,8 @@
|
|||
<string name="onboarding_done_body">Ваша криптокарта активирована и готова к использованию</string>
|
||||
<string name="onboarding_done_button_continue">Продолжить</string>
|
||||
<string name="onboarding_balance_title">Баланс</string>
|
||||
<string name="address_qr_code_message_format">Отправляйте только %s (%s) на этот адрес. Отправка любой другой валюты приведет к ее безвозвратной потере.</string>
|
||||
<string name="address_qr_code_message_token_format">Отправляйте только %s (%s) из сети %s на этот адрес. Отправка любой другой валюты приведет к ее безвозвратной потере.</string>
|
||||
<string name="address_qr_code_message_format">Отправляйте только %s (%s) на этот адрес. Иначе это может привести к утрате средств.</string>
|
||||
<string name="address_qr_code_message_token_format">Отправляйте только %s (%s) из сети %s на этот адрес. Иначе это может привести к утрате средств.</string>
|
||||
<string name="onboarding_twins_interrupt_warning">Если процесс повторного создания кошелька каким-либо образом прервется, вам придется начать все сначала.</string>
|
||||
<string name="onboarding_twin_exit_warning">Процесс связывания карт частично завершен. Вы не можете выйти из него сейчас.</string>
|
||||
<string name="onboarding_error_create_primary_wallet">Внутренняя ошибка: не удается создать менеджер кошельков</string>
|
||||
|
|
|
|||
|
|
@ -205,8 +205,8 @@
|
|||
<string name="onboarding_done_body" translatable="false">Your crypto card is activated and ready to be used</string>
|
||||
<string name="onboarding_done_button_continue" translatable="false">Continue</string>
|
||||
<string name="onboarding_balance_title" translatable="false">Balance</string>
|
||||
<string name="address_qr_code_message_format" translatable="false">Send only %s (%s) to this address. Sending any other currency will result in its irreversible loss.</string>
|
||||
<string name="address_qr_code_message_token_format" translatable="false">Send only %s (%s) from %s network to this address. Sending any other currency will result in its irreversible loss.</string>
|
||||
<string name="address_qr_code_message_format" translatable="false">Send only %s (%s) to this address. Using other tokens and networks may result in loss of funds.</string>
|
||||
<string name="address_qr_code_message_token_format" translatable="false">Send only %s (%s) from %s network to this address. Using other tokens and networks may result in loss of funds.</string>
|
||||
|
||||
<string name="onboarding_twins_interrupt_warning" translatable="false">If the process of re-creating the wallet gets interrupted in any way, you\'ll have to start over.</string>
|
||||
<string name="onboarding_twin_exit_warning" translatable="false">The twinning process is partly complete. You can\'t exit it now.</string>
|
||||
|
|
|
|||
|
|
@ -85,4 +85,4 @@ dependencies {
|
|||
testImplementation "com.google.truth:truth:1.1.3"
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ package com.tangem.domain.features.addCustomToken.redux
|
|||
|
||||
import android.webkit.ValueCallback
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.domain.AddCustomTokenError
|
||||
|
|
@ -571,17 +570,11 @@ private class AddCustomTokenReducer(
|
|||
supportedTokenNetworkIds = supportedTokenNetworkIds
|
||||
)
|
||||
|
||||
var derivationPathState = state.screenState.derivationPath
|
||||
derivationPathState = when (card.derivationStyle) {
|
||||
DerivationStyle.LEGACY -> derivationPathState.copy(isVisible = true)
|
||||
null, DerivationStyle.NEW -> derivationPathState.copy(isVisible = false)
|
||||
}
|
||||
val form = Form(AddCustomTokenState.createFormFields(card, CustomTokenType.Blockchain))
|
||||
state.copy(
|
||||
cardDerivationStyle = card.derivationStyle,
|
||||
form = form,
|
||||
tangemTechServiceManager = tangemTechServiceManager,
|
||||
screenState = state.screenState.copy(derivationPath = derivationPathState)
|
||||
)
|
||||
}
|
||||
is OnDestroy -> {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ data class AddCustomTokenState(
|
|||
|
||||
fun blockchainToName(blockchain: Blockchain, isDerivationPath: Boolean = false): String? {
|
||||
return when {
|
||||
isDerivationPath -> blockchain.derivationPath(cardDerivationStyle)?.rawPath
|
||||
isDerivationPath -> blockchain.derivationPath(DerivationStyle.LEGACY)?.rawPath
|
||||
else -> {
|
||||
when (blockchain) {
|
||||
Blockchain.Unknown -> null
|
||||
|
|
@ -150,10 +150,21 @@ data class AddCustomTokenState(
|
|||
mainNetwork: Blockchain,
|
||||
derivationNetwork: Blockchain,
|
||||
derivationStyle: DerivationStyle?
|
||||
): com.tangem.common.hdWallet.DerivationPath? = when (derivationNetwork) {
|
||||
Blockchain.Unknown -> mainNetwork
|
||||
else -> derivationNetwork
|
||||
}.derivationPath(derivationStyle)
|
||||
): com.tangem.common.hdWallet.DerivationPath? {
|
||||
// If we allow user to select derivations, we need to provide different derivations
|
||||
// (Legacy style derivations).
|
||||
// But the mainNetwork derivation depends on whether a user has a card
|
||||
// with legacy derivations or new style derivations.
|
||||
val derivationStyleToUse = if (derivationNetwork == Blockchain.Unknown) {
|
||||
derivationStyle
|
||||
} else {
|
||||
DerivationStyle.LEGACY
|
||||
}
|
||||
return when (derivationNetwork) {
|
||||
Blockchain.Unknown -> mainNetwork
|
||||
else -> derivationNetwork
|
||||
}.derivationPath(derivationStyleToUse)
|
||||
}
|
||||
|
||||
internal fun createFormFields(card: Card, type: CustomTokenType): List<DataField<*>> {
|
||||
return listOf(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue