diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt index e53e1effbe..5e10f11f1d 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Blockchain.kt @@ -5,39 +5,6 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.remove import com.tangem.wallet.R -@DrawableRes -fun Blockchain.getRoundIconRes(): Int { - return when (this) { - Blockchain.Arbitrum, Blockchain.ArbitrumTestnet -> R.drawable.ic_arbitrum_round - Blockchain.Ducatus -> R.drawable.ic_ducatus - Blockchain.Bitcoin, Blockchain.BitcoinTestnet,-> R.drawable.ic_bitcoin_round - Blockchain.BitcoinCash -> R.drawable.ic_bitcoin_cash_round - Blockchain.Litecoin -> R.drawable.ic_litecoin_round - Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth_round - Blockchain.EthereumClassic, Blockchain.EthereumClassicTestnet -> R.drawable.ic_eth_round - Blockchain.RSK -> R.drawable.ic_rsk_round - Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano_round - Blockchain.Tezos -> R.drawable.ic_tezos_round - Blockchain.XRP -> R.drawable.ic_xrp_round - Blockchain.Stellar -> R.drawable.ic_stellar_round - Blockchain.Avalanche, Blockchain.AvalancheTestnet -> R.drawable.ic_avalanche_round - Blockchain.Polygon, Blockchain.PolygonTestnet -> R.drawable.ic_polygon_round - Blockchain.Solana, Blockchain.SolanaTestnet -> R.drawable.ic_solana_round - Blockchain.Fantom, Blockchain.FantomTestnet -> R.drawable.ic_fantom_round - Blockchain.BSC, Blockchain.BSCTestnet, Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_bsc_round - Blockchain.Dogecoin -> R.drawable.ic_dogecoin_round - Blockchain.Tron, Blockchain.TronTestnet -> R.drawable.ic_tron_round - Blockchain.Gnosis -> R.drawable.ic_gnosis_round - Blockchain.EthereumPow, Blockchain.EthereumPowTestnet -> R.drawable.ic_ethereumpow_round - Blockchain.EthereumFair -> R.drawable.ic_ethereumfair_round - Blockchain.Polkadot, Blockchain.PolkadotTestnet -> R.drawable.ic_polkadot_round - Blockchain.Kusama -> R.drawable.ic_kusama_round - Blockchain.Optimism, Blockchain.OptimismTestnet -> R.drawable.ic_optimism - Blockchain.Dash -> R.drawable.ic_dash - else -> R.drawable.ic_tangem_logo - } -} - @DrawableRes fun Blockchain.getGreyedOutIconRes(): Int { return when (this) { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemHeader.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemHeader.kt index b029341439..32c6c7b329 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemHeader.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/CurrencyItemHeader.kt @@ -31,9 +31,9 @@ import androidx.compose.ui.unit.sp import coil.compose.SubcomposeAsyncImage import coil.request.ImageRequest import com.tangem.blockchain.common.Blockchain +import com.tangem.core.ui.extensions.getActiveIconRes 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 @@ -142,7 +142,7 @@ private fun NetworksRow( } else { val isAdded = addedTokens.map { it.token.contractAddress }.contains(contract.address) val iconResId = if (isAdded) { - contract.blockchain.getRoundIconRes() + getActiveIconRes(contract.blockchain.id) } else { contract.blockchain.getGreyedOutIconRes() } @@ -173,7 +173,7 @@ private fun BlockchainNetworkItem( addedBlockchains: List, ) { val added = addedBlockchains.contains(blockchain) - val icon = if (added) blockchain?.getRoundIconRes() else blockchain?.getGreyedOutIconRes() + val icon = if (added) blockchain?.let { getActiveIconRes(it.id) } else blockchain?.getGreyedOutIconRes() if (icon != null) { Box( Modifier diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt index 2928ace0d8..494cbc8553 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/currencyItem/NetworkItem.kt @@ -31,10 +31,10 @@ import androidx.compose.ui.unit.sp import coil.compose.SubcomposeAsyncImage import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Token +import com.tangem.core.ui.extensions.getActiveIconRes import com.tangem.tap.common.extensions.fullNameWithoutTestnet import com.tangem.tap.common.extensions.getGreyedOutIconRes import com.tangem.tap.common.extensions.getNetworkName -import com.tangem.tap.common.extensions.getRoundIconRes import com.tangem.tap.domain.tokens.Contract import com.tangem.tap.domain.tokens.Currency import com.tangem.tap.features.tokens.redux.ContractAddress @@ -85,7 +85,7 @@ fun NetworkItem( .align(Alignment.CenterVertically), ) { SubcomposeAsyncImage( - model = if (added) blockchain.getRoundIconRes() else blockchain.getGreyedOutIconRes(), + model = if (added) getActiveIconRes(blockchain.id) else blockchain.getGreyedOutIconRes(), contentDescription = blockchain.fullName, loading = { CurrencyPlaceholderIcon(blockchain.id) }, error = { CurrencyPlaceholderIcon(blockchain.id) }, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconRequest.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconRequest.kt index 729bfe3fcc..b02511017c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconRequest.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/images/CurrencyIconRequest.kt @@ -8,9 +8,9 @@ import coil.request.ImageRequest import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.IconsUtil import com.tangem.blockchain.common.Token +import com.tangem.core.ui.extensions.getActiveIconRes import com.tangem.domain.common.extensions.toNetworkId import com.tangem.tap.common.extensions.getColor -import com.tangem.tap.common.extensions.getRoundIconRes import com.tangem.tap.common.extensions.getTextColor import com.tangem.tap.domain.extensions.getCustomIconUrl import com.tangem.tap.domain.tokens.getIconUrl @@ -85,8 +85,8 @@ class CurrencyIconRequest( crossinline onError: (Blockchain) -> Unit = {}, ) { currencyImageView.loadIcon( - data = if (getLocalImage) blockchain.getRoundIconRes() else getIconUrl(blockchain.toNetworkId()), - placeholderRes = blockchain.getRoundIconRes(), + data = if (getLocalImage) getActiveIconRes(blockchain.id) else getIconUrl(blockchain.toNetworkId()), + placeholderRes = getActiveIconRes(blockchain.id), onStart = { onStart(blockchain) }, onSuccess = { onSuccess(blockchain) }, onError = { onError(blockchain) }, diff --git a/app/src/main/res/drawable/ic_arbitrum_round.xml b/app/src/main/res/drawable/ic_arbitrum_round.xml deleted file mode 100644 index 632ea33dae..0000000000 --- a/app/src/main/res/drawable/ic_arbitrum_round.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_avalanche_round.xml b/app/src/main/res/drawable/ic_avalanche_round.xml deleted file mode 100644 index ac2c5623a1..0000000000 --- a/app/src/main/res/drawable/ic_avalanche_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_binance_round.xml b/app/src/main/res/drawable/ic_binance_round.xml deleted file mode 100644 index 6b399342e0..0000000000 --- a/app/src/main/res/drawable/ic_binance_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_bitcoin_cash_round.xml b/app/src/main/res/drawable/ic_bitcoin_cash_round.xml deleted file mode 100644 index 704b9c7c96..0000000000 --- a/app/src/main/res/drawable/ic_bitcoin_cash_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_bitcoin_round.xml b/app/src/main/res/drawable/ic_bitcoin_round.xml deleted file mode 100644 index ab0c448c23..0000000000 --- a/app/src/main/res/drawable/ic_bitcoin_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_bsc_round.xml b/app/src/main/res/drawable/ic_bsc_round.xml deleted file mode 100644 index cca406ef7b..0000000000 --- a/app/src/main/res/drawable/ic_bsc_round.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/ic_cardano_round.xml b/app/src/main/res/drawable/ic_cardano_round.xml deleted file mode 100644 index 6764bbb9e8..0000000000 --- a/app/src/main/res/drawable/ic_cardano_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_dogecoin_round.xml b/app/src/main/res/drawable/ic_dogecoin_round.xml deleted file mode 100644 index 8a89a70dcf..0000000000 --- a/app/src/main/res/drawable/ic_dogecoin_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_eth_round.xml b/app/src/main/res/drawable/ic_eth_round.xml deleted file mode 100644 index b62152ede8..0000000000 --- a/app/src/main/res/drawable/ic_eth_round.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_ethc_round.xml b/app/src/main/res/drawable/ic_ethc_round.xml deleted file mode 100644 index 31f3dbacd8..0000000000 --- a/app/src/main/res/drawable/ic_ethc_round.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/ic_fantom_round.xml b/app/src/main/res/drawable/ic_fantom_round.xml deleted file mode 100644 index e970acee86..0000000000 --- a/app/src/main/res/drawable/ic_fantom_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_gnosis_round.xml b/app/src/main/res/drawable/ic_gnosis_round.xml deleted file mode 100644 index 8734b7177b..0000000000 --- a/app/src/main/res/drawable/ic_gnosis_round.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/ic_kusama_round.xml b/app/src/main/res/drawable/ic_kusama_round.xml deleted file mode 100644 index f620ae3130..0000000000 --- a/app/src/main/res/drawable/ic_kusama_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_litecoin_round.xml b/app/src/main/res/drawable/ic_litecoin_round.xml deleted file mode 100644 index 018f6f35bc..0000000000 --- a/app/src/main/res/drawable/ic_litecoin_round.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/ic_optimism.xml b/app/src/main/res/drawable/ic_optimism.xml deleted file mode 100644 index fb8ce845a1..0000000000 --- a/app/src/main/res/drawable/ic_optimism.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/ic_polkadot_round.xml b/app/src/main/res/drawable/ic_polkadot_round.xml deleted file mode 100644 index 346f130d82..0000000000 --- a/app/src/main/res/drawable/ic_polkadot_round.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_polygon_round.xml b/app/src/main/res/drawable/ic_polygon_round.xml deleted file mode 100644 index d8e57f8f97..0000000000 --- a/app/src/main/res/drawable/ic_polygon_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_rsk_round.xml b/app/src/main/res/drawable/ic_rsk_round.xml deleted file mode 100644 index f4a6e92bde..0000000000 --- a/app/src/main/res/drawable/ic_rsk_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_solana_round.xml b/app/src/main/res/drawable/ic_solana_round.xml deleted file mode 100644 index 49659278ae..0000000000 --- a/app/src/main/res/drawable/ic_solana_round.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_stellar_round.xml b/app/src/main/res/drawable/ic_stellar_round.xml deleted file mode 100644 index f7ae98231f..0000000000 --- a/app/src/main/res/drawable/ic_stellar_round.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_tezos_round.xml b/app/src/main/res/drawable/ic_tezos_round.xml deleted file mode 100644 index 4976e634e3..0000000000 --- a/app/src/main/res/drawable/ic_tezos_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_tron_round.xml b/app/src/main/res/drawable/ic_tron_round.xml deleted file mode 100644 index 9eaf6cfc9b..0000000000 --- a/app/src/main/res/drawable/ic_tron_round.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/ic_xrp_round.xml b/app/src/main/res/drawable/ic_xrp_round.xml deleted file mode 100644 index 6e29010df6..0000000000 --- a/app/src/main/res/drawable/ic_xrp_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 2ed6276780..8696a129c5 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -191,6 +191,8 @@ Share Copy Erfolg + You Send + You Receive Give Permission To continue you need to allow 1inch smart contracts to use your %s Amount %s diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 5c7572747e..160175b03b 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -191,6 +191,8 @@ Share Copy Avec succès + You Send + You Receive Give Permission To continue you need to allow 1inch smart contracts to use your %s Amount %s diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index 2b7d521568..3f70ed2bb4 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -191,6 +191,8 @@ Share Copy Con successo + You Send + You Receive Give Permission To continue you need to allow 1inch smart contracts to use your %s Amount %s diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 95b3fc88e0..59ada270a7 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -191,6 +191,8 @@ Поделиться Копировать Успешно + Вы отправляете + Вы получаете Дать разрешение Чтобы продолжить, вам нужно разрешить смарт-контракту 1inch использовать ваш %s Количество %s diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 6bfdbb64e0..db70283a4c 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -191,6 +191,8 @@ Share Copy Success + You Send + You Receive Give Permission To continue you need to allow 1inch smart contracts to use your %s Amount %s diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Cards.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Cards.kt index 8eb31f6669..2f513195bb 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Cards.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Cards.kt @@ -268,10 +268,11 @@ private fun CardInfoBox( if (isLoading) { Box( modifier = Modifier + .size(width = TangemTheme.dimens.size40, height = TangemTheme.dimens.size12) .shimmer() - .size( - width = TangemTheme.dimens.size80, - height = TangemTheme.dimens.size20, + .background( + color = TangemTheme.colors.button.secondary, + shape = RoundedCornerShape(TangemTheme.dimens.radius3), ), ) } else { diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/CurrencyPlaceholderIcon.kt b/core/ui/src/main/java/com/tangem/core/ui/components/CurrencyPlaceholderIcon.kt new file mode 100644 index 0000000000..418f0692ed --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/CurrencyPlaceholderIcon.kt @@ -0,0 +1,59 @@ +package com.tangem.core.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +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.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.sp +import com.tangem.core.ui.res.TangemTheme + +@Composable +fun CurrencyPlaceholderIcon(modifier: Modifier = Modifier, id: String) { + + val letterColor: Color = TangemTheme.colors.text.primary2 + val circleColor: Color = TangemTheme.colors.icon.secondary + + Box( + contentAlignment = Alignment.Center, + modifier = modifier + .background(circleColor, shape = CircleShape), + ) + { + Text( + text = id.firstOrNull()?.titlecase() ?: "", + textAlign = TextAlign.Center, + color = letterColor, + modifier = Modifier.padding(TangemTheme.dimens.spacing4), + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + ) + } +} + +// region preview + +@Preview(showBackground = true, heightDp = 40, widthDp = 40) +@Composable +fun Preview_CurrencyPlaceholderIcon_InLightTheme() { + TangemTheme(isDark = false) { + CurrencyPlaceholderIcon(id = "DAI") + } +} + +@Preview(showBackground = true, heightDp = 40, widthDp = 40) +@Composable +fun Preview_CurrencyPlaceholderIcon_InDarkTheme() { + TangemTheme(isDark = true) { + CurrencyPlaceholderIcon(id = "DAI") + } +} + +// endregion preview \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt b/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt new file mode 100644 index 0000000000..4b7fe2c1ac --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/ResizableText.kt @@ -0,0 +1,69 @@ +package com.tangem.core.ui.components + +import androidx.compose.material.LocalTextStyle +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.sp + +@Composable +fun ResizableText( + text: String, + modifier: Modifier = Modifier, + color: Color = Color.Unspecified, + style: TextStyle = LocalTextStyle.current, + fontSizeRange: FontSizeRange, +) { + val fontSizeValue = remember { mutableStateOf(fontSizeRange.max.value) } + val readyToDraw = remember { mutableStateOf(false) } + + val textState = remember { mutableStateOf(text) } + if (textState.value != text) { + readyToDraw.value = false + fontSizeValue.value = fontSizeRange.max.value + textState.value = text + } + + Text( + modifier = modifier.drawWithContent { if (readyToDraw.value) drawContent() }, + text = text, + color = color, + softWrap = false, + style = style, + fontSize = fontSizeValue.value.sp, + onTextLayout = { + if (it.hasVisualOverflow) { + val nextFontSizeValue = fontSizeValue.value - fontSizeRange.step.value + if (nextFontSizeValue <= fontSizeRange.min.value) { + fontSizeValue.value = fontSizeRange.min.value + readyToDraw.value = true + } else { + fontSizeValue.value = nextFontSizeValue * 0.8f + } + } else { + readyToDraw.value = true + } + }, + ) +} + +data class FontSizeRange( + val min: TextUnit, + val max: TextUnit, + val step: TextUnit = DEFAULT_TEXT_STEP, +) { + init { + require(min < max) { "min should be less than max, $this" } + require(step.value > 0) { "step should be greater than 0, $this" } + } + + companion object { + private val DEFAULT_TEXT_STEP = 1.sp + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt b/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt index c0f603db45..9464d4355c 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/SuccessScreen.kt @@ -44,7 +44,7 @@ fun SuccessScreenContent( modifier = modifier .fillMaxSize() .verticalScroll(rememberScrollState()) - .background(TangemTheme.colors.background.secondary) + .background(TangemTheme.colors.background.primary) .padding( horizontal = TangemTheme.dimens.spacing16, vertical = TangemTheme.dimens.spacing32, diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/Blockchain.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/Blockchain.kt new file mode 100644 index 0000000000..052f2f26b6 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/Blockchain.kt @@ -0,0 +1,37 @@ +package com.tangem.core.ui.extensions + +import androidx.annotation.DrawableRes +import com.tangem.core.ui.R + +@DrawableRes +fun getActiveIconRes(blockchainId: String): Int { + return when (blockchainId) { + "ARBITRUM-ONE", "ARBITRUM/test" -> R.drawable.img_arbitrum_22 + "BTC", "BTC/test" -> R.drawable.img_btc_22 + "BCH" -> R.drawable.img_btc_cash_22 + "LTC" -> R.drawable.img_litecoin_22 + "ETH", "ETH/test" -> R.drawable.img_eth_22 + "ETC", "ETC/test" -> R.drawable.img_eth_classic_22 + "RSK" -> R.drawable.img_rsk_22 + "CARDANO", "CARDANO-S" -> R.drawable.img_cardano_22 + "XTZ" -> R.drawable.img_tezos_22 + "XRP" -> R.drawable.img_xrp_22 + "XLM", "XLM/test" -> R.drawable.img_stellar_22 + "AVALANCHE", "AVALANCHE/test" -> R.drawable.img_avalanche_22 + "POLYGON", "POLYGON/test" -> R.drawable.img_polygon_22 + "SOLANA", "SOLANA/test" -> R.drawable.img_solana_22 + "FTM", "FTM/test" -> R.drawable.img_fantom_22 + "BSC", "BSC/test", "BINANCE", "BINANCE/test" -> R.drawable.img_bsc_22 + "DOGE" -> R.drawable.img_dogecoin_22 + "TRON", "TRON/test" -> R.drawable.img_tron_22 + "GNO" -> R.drawable.img_gnosis_22 + "ETH-Pow", "ETH-Pow/test" -> R.drawable.img_eth_pow_22 + "ETH-Fair" -> R.drawable.img_eth_fair_22 + "Polkadot", "Polkadot/test" -> R.drawable.img_polkadot_22 + "Kusama" -> R.drawable.img_kusama_22 + "OPTIMISM", "OPTIMISM/test" -> R.drawable.img_optimism_22 + "DASH" -> R.drawable.img_dash_22 + else -> R.drawable.ic_alert_24 + } +} + diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt index 061e1f81c6..e5cf24728b 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt @@ -20,6 +20,7 @@ data class TangemDimens internal constructor( // endregion Elevation // region Radius val radius2: Dp = 2.dp, + val radius3: Dp = 3.dp, val radius4: Dp = 4.dp, val radius6: Dp = 6.dp, val radius8: Dp = 8.dp, @@ -61,6 +62,7 @@ data class TangemDimens internal constructor( val size200: Dp = 200.dp, // endregion Size // region Spacing + val spacing0_5: Dp = 0.5.dp, val spacing2: Dp = 2.dp, val spacing4: Dp = 4.dp, val spacing8: Dp = 8.dp, diff --git a/core/ui/src/main/res/drawable/img_arbitrum_22.xml b/core/ui/src/main/res/drawable/img_arbitrum_22.xml new file mode 100644 index 0000000000..db6401d732 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_arbitrum_22.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/core/ui/src/main/res/drawable/img_avalanche_22.xml b/core/ui/src/main/res/drawable/img_avalanche_22.xml new file mode 100644 index 0000000000..ce6d69f6c0 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_avalanche_22.xml @@ -0,0 +1,14 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_binance_22.xml b/core/ui/src/main/res/drawable/img_binance_22.xml new file mode 100644 index 0000000000..e54d84d8a5 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_binance_22.xml @@ -0,0 +1,14 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_bsc_22.xml b/core/ui/src/main/res/drawable/img_bsc_22.xml new file mode 100644 index 0000000000..4aa4221fd0 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_bsc_22.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/core/ui/src/main/res/drawable/img_btc_22.xml b/core/ui/src/main/res/drawable/img_btc_22.xml new file mode 100644 index 0000000000..7624b7c1ad --- /dev/null +++ b/core/ui/src/main/res/drawable/img_btc_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_btc_cash_22.xml b/core/ui/src/main/res/drawable/img_btc_cash_22.xml new file mode 100644 index 0000000000..4b64ee0ba3 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_btc_cash_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_cardano_22.xml b/core/ui/src/main/res/drawable/img_cardano_22.xml new file mode 100644 index 0000000000..bda1a6ce6b --- /dev/null +++ b/core/ui/src/main/res/drawable/img_cardano_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_dash_22.xml b/core/ui/src/main/res/drawable/img_dash_22.xml new file mode 100644 index 0000000000..3e52aa86b1 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_dash_22.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/core/ui/src/main/res/drawable/img_dogecoin_22.xml b/core/ui/src/main/res/drawable/img_dogecoin_22.xml new file mode 100644 index 0000000000..2f083f774a --- /dev/null +++ b/core/ui/src/main/res/drawable/img_dogecoin_22.xml @@ -0,0 +1,14 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_eth_22.xml b/core/ui/src/main/res/drawable/img_eth_22.xml new file mode 100644 index 0000000000..0c8469373e --- /dev/null +++ b/core/ui/src/main/res/drawable/img_eth_22.xml @@ -0,0 +1,28 @@ + + + + + + + + + diff --git a/core/ui/src/main/res/drawable/img_eth_classic_22.xml b/core/ui/src/main/res/drawable/img_eth_classic_22.xml new file mode 100644 index 0000000000..99bdcffe57 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_eth_classic_22.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_ethereumfair_round.xml b/core/ui/src/main/res/drawable/img_eth_fair_22.xml similarity index 100% rename from app/src/main/res/drawable/ic_ethereumfair_round.xml rename to core/ui/src/main/res/drawable/img_eth_fair_22.xml diff --git a/app/src/main/res/drawable/ic_ethereumpow_round.xml b/core/ui/src/main/res/drawable/img_eth_pow_22.xml similarity index 100% rename from app/src/main/res/drawable/ic_ethereumpow_round.xml rename to core/ui/src/main/res/drawable/img_eth_pow_22.xml diff --git a/core/ui/src/main/res/drawable/img_fantom_22.xml b/core/ui/src/main/res/drawable/img_fantom_22.xml new file mode 100644 index 0000000000..3327ab40ae --- /dev/null +++ b/core/ui/src/main/res/drawable/img_fantom_22.xml @@ -0,0 +1,14 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_gnosis_22.xml b/core/ui/src/main/res/drawable/img_gnosis_22.xml new file mode 100644 index 0000000000..222aa994d2 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_gnosis_22.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/core/ui/src/main/res/drawable/img_kusama_22.xml b/core/ui/src/main/res/drawable/img_kusama_22.xml new file mode 100644 index 0000000000..f3d98bd342 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_kusama_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_litecoin_22.xml b/core/ui/src/main/res/drawable/img_litecoin_22.xml new file mode 100644 index 0000000000..5354cc63be --- /dev/null +++ b/core/ui/src/main/res/drawable/img_litecoin_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_optimism_22.xml b/core/ui/src/main/res/drawable/img_optimism_22.xml new file mode 100644 index 0000000000..5ce92be0bc --- /dev/null +++ b/core/ui/src/main/res/drawable/img_optimism_22.xml @@ -0,0 +1,14 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_polkadot_22.xml b/core/ui/src/main/res/drawable/img_polkadot_22.xml new file mode 100644 index 0000000000..9c4c5e7f4b --- /dev/null +++ b/core/ui/src/main/res/drawable/img_polkadot_22.xml @@ -0,0 +1,14 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_rsk_22.xml b/core/ui/src/main/res/drawable/img_rsk_22.xml new file mode 100644 index 0000000000..d8ae9d522f --- /dev/null +++ b/core/ui/src/main/res/drawable/img_rsk_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_solana_22.xml b/core/ui/src/main/res/drawable/img_solana_22.xml new file mode 100644 index 0000000000..8948b33621 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_solana_22.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + diff --git a/core/ui/src/main/res/drawable/img_stellar_22.xml b/core/ui/src/main/res/drawable/img_stellar_22.xml new file mode 100644 index 0000000000..a87e860293 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_stellar_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_tezos_22.xml b/core/ui/src/main/res/drawable/img_tezos_22.xml new file mode 100644 index 0000000000..cf9c1d5100 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_tezos_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_tron_22.xml b/core/ui/src/main/res/drawable/img_tron_22.xml new file mode 100644 index 0000000000..f1dfceca1f --- /dev/null +++ b/core/ui/src/main/res/drawable/img_tron_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core/ui/src/main/res/drawable/img_xrp_22.xml b/core/ui/src/main/res/drawable/img_xrp_22.xml new file mode 100644 index 0000000000..41fed91f22 --- /dev/null +++ b/core/ui/src/main/res/drawable/img_xrp_22.xml @@ -0,0 +1,13 @@ + + + + diff --git a/features/swap/presentation/build.gradle.kts b/features/swap/presentation/build.gradle.kts index fc127f077b..be71e61c6d 100644 --- a/features/swap/presentation/build.gradle.kts +++ b/features/swap/presentation/build.gradle.kts @@ -60,6 +60,7 @@ dependencies { implementation(Compose.foundation) implementation(Compose.material) implementation(Compose.uiTooling) + implementation(Compose.coil) /** Domain */ implementation(project(":features:swap:domain")) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapPermissionStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapPermissionStateHolder.kt new file mode 100644 index 0000000000..76d4ee8587 --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapPermissionStateHolder.kt @@ -0,0 +1,22 @@ +package com.tangem.feature.swap.models + +data class SwapPermissionStateHolder( + val currency: String, + val amount: String, + val walletAddress: String, + val spenderAddress: String, + val fee: String, + val approveButton: ApprovePermissionButton, + val cancelButton: CancelPermissionButton, +) + +data class ApprovePermissionButton( + val enabled: Boolean, + val loading: Boolean = false, + val onClick: () -> Unit, +) + +data class CancelPermissionButton( + val enabled: Boolean, + val onClick: () -> Unit, +) \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt new file mode 100644 index 0000000000..0f12e3010b --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSelectTokenStateHolder.kt @@ -0,0 +1,7 @@ +package com.tangem.feature.swap.models + +data class SwapSelectTokenStateHolder( + val tokens: List, + val onSearchEntered: (String) -> Unit, + val onTokenSelected: (String) -> Unit, +) \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt new file mode 100644 index 0000000000..19e2b2d63f --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt @@ -0,0 +1,79 @@ +package com.tangem.feature.swap.models + +import androidx.annotation.DrawableRes + +data class SwapStateHolder( + val sendCardData: SwapCardData, + val receiveCardData: SwapCardData, + val networkCurrency: String, + val fee: FeeState = FeeState.Loaded(), + val warnings: List = emptyList(), + + val permissionState: SwapPermissionStateHolder? = null, + val successState: SwapSuccessStateHolder? = null, + val selectTokenState: SwapSelectTokenStateHolder? = null, + + val swapButton: SwapButton, + + val onRefresh: () -> Unit, + val onBackClicked: () -> Unit, + val onChangeCardsClicked: () -> Unit, + val onSelectTokenClick: (() -> Unit)? = null, + val onSuccess: (() -> Unit)? = null, +) + +data class TokenToSelect( + val id: String, + val name: String, + val symbol: String, + val addedTokenBalanceData: TokenBalanceData? = null, +) + +data class TokenBalanceData( + val amount: String?, + val amountEquivalent: String?, +) + +data class SwapCardData( + val type: TransactionCardType, + val amount: String?, + val amountEquivalent: String?, + val tokenIconUrl: String, + val tokenCurrency: String, + @DrawableRes val networkIconRes: Int? = null, + val canSelectAnotherToken: Boolean = false, +) + +data class SwapButton( + val enabled: Boolean, + val loading: Boolean = false, + val onClick: () -> Unit, +) + +sealed interface FeeState { + data class Loaded( + val fee: String = "", + ) : FeeState + + object Loading : FeeState + + data class NotEnoughFundsWarning(val fee: String) : FeeState +} + +sealed interface TransactionCardType { + + data class SendCard( + val balance: String, + val permissionIsGiven: Boolean, + ) : TransactionCardType + + data class ReceiveCard( + val highPriceImpact: String? = null, + ) : TransactionCardType +} + +sealed interface SwapWarning { + data class PermissionNeeded(val tokenCurrency: String) : SwapWarning + // data class RateExpired(val onClick: () -> Unit) : SwapWarning + // object HighPriceImpact : SwapWarning +} \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt new file mode 100644 index 0000000000..9fad250c3a --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapSuccessStateHolder.kt @@ -0,0 +1,5 @@ +package com.tangem.feature.swap.models + +data class SwapSuccessStateHolder( + val message: String, +) \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt index cc841afcb7..acedb67519 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/presentation/SwapFragment.kt @@ -1,16 +1,21 @@ package com.tangem.feature.swap.presentation import android.os.Bundle -import android.transition.TransitionInflater import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.animation.Crossfade import androidx.compose.ui.platform.ComposeView import androidx.core.view.WindowCompat import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import com.tangem.feature.swap.router.SwapRouter +import com.tangem.feature.swap.router.SwapScreen +import com.tangem.feature.swap.ui.SwapScreen +import com.tangem.feature.swap.ui.SwapSuccessScreen import com.tangem.feature.swap.viewmodels.SwapViewModel import dagger.hilt.android.AndroidEntryPoint +import java.lang.ref.WeakReference @AndroidEntryPoint class SwapFragment : Fragment() { @@ -19,10 +24,24 @@ class SwapFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) } - viewModel + viewModel.setRouter(SwapRouter(fragmentManager = WeakReference(parentFragmentManager))) return ComposeView(inflater.context).apply { setContent { - //todo add compose screen here + Crossfade(targetState = viewModel.currentScreen) { screen -> + when (screen) { + SwapScreen.Main -> SwapScreen(stateHolder = viewModel.uiState) + SwapScreen.Success -> { + val successState = viewModel.uiState.successState + if (successState != null) { + SwapSuccessScreen(state = successState, viewModel.uiState.onBackClicked) + } else { + SwapScreen(stateHolder = viewModel.uiState) + } + } + SwapScreen.SelectToken -> SwapScreen(stateHolder = viewModel.uiState)// TODO: use proper screen + } + } + } } } diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/router/SwapRouter.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/router/SwapRouter.kt new file mode 100644 index 0000000000..bf3f7446fd --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/router/SwapRouter.kt @@ -0,0 +1,31 @@ +package com.tangem.feature.swap.router + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.fragment.app.FragmentManager +import java.lang.ref.WeakReference + +internal class SwapRouter( + private val fragmentManager: WeakReference, +) { + + var currentScreen by mutableStateOf(SwapScreen.Main) + private set + + fun openScreen(screen: SwapScreen) { + currentScreen = screen + } + + fun back() { + if (currentScreen == SwapScreen.SelectToken) { + currentScreen = SwapScreen.Main + } else { + fragmentManager.get()?.popBackStack() + } + } +} + +enum class SwapScreen { + Main, Success, SelectToken +} \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheetContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheetContent.kt new file mode 100644 index 0000000000..90082105f4 --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapPermissionBottomSheetContent.kt @@ -0,0 +1,219 @@ +package com.tangem.feature.swap.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +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.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.PrimaryButtonIconRight +import com.tangem.core.ui.components.SecondaryButton +import com.tangem.core.ui.components.SpacerH10 +import com.tangem.core.ui.components.SpacerH12 +import com.tangem.core.ui.components.SpacerH16 +import com.tangem.core.ui.components.SpacerH28 +import com.tangem.core.ui.components.SpacerH32 +import com.tangem.core.ui.components.atoms.Hand +import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.swap.models.ApprovePermissionButton +import com.tangem.feature.swap.models.CancelPermissionButton +import com.tangem.feature.swap.models.SwapPermissionStateHolder +import com.tangem.feature.swap.presentation.R + +@Composable +fun SwapPermissionBottomSheetContent( + data: SwapPermissionStateHolder, + onCancel: () -> Unit, +) { + Column( + modifier = Modifier + .background(color = TangemTheme.colors.background.primary) + .fillMaxWidth() + .padding(horizontal = TangemTheme.dimens.spacing16), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Hand() + + SpacerH10() + + Text( + text = stringResource(id = R.string.swapping_permission_header), + color = TangemTheme.colors.text.primary1, + style = TangemTheme.typography.subtitle1, + ) + + SpacerH10() + + Text( + text = stringResource(id = R.string.swapping_permission_subheader, data.currency), + color = TangemTheme.colors.text.secondary, + style = TangemTheme.typography.body2, + textAlign = TextAlign.Center, + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing8), + ) + + SpacerH16() + + ApprovalBottomSheetInfo( + currency = data.currency, + amount = data.amount, + walletAddress = data.walletAddress, + spenderAddress = data.spenderAddress, + fee = data.fee, + ) + + SpacerH28() + + PrimaryButtonIconRight( + text = stringResource(id = R.string.swapping_permission_buttons_approve), + icon = painterResource(id = R.drawable.ic_tangem_24), + modifier = Modifier.fillMaxWidth(), + onClick = data.approveButton.onClick, + ) + + SpacerH12() + + SecondaryButton( + text = stringResource(id = R.string.common_cancel), + modifier = Modifier.fillMaxWidth(), + ) { + data.cancelButton.onClick() + onCancel() + } + + SpacerH32() + + } +} + +@Composable +private fun ApprovalBottomSheetInfo( + currency: String, amount: String, walletAddress: String, spenderAddress: String, fee: String, +) { + Column( + modifier = Modifier + .background(color = TangemTheme.colors.background.primary) + .fillMaxWidth() + .padding( + start = TangemTheme.dimens.spacing12, + end = TangemTheme.dimens.spacing16, + ), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + + AmountItem(currency = currency, amount = amount) + DividerBottomSheet() + WalletAddressItem(walletAddress = walletAddress) + DividerBottomSheet() + SpenderItem(spenderAddress = spenderAddress) + DividerBottomSheet() + FeeItem(fee = fee) + } +} + +@Composable +private fun DividerBottomSheet() { + Divider( + color = TangemTheme.colors.stroke.primary, + thickness = TangemTheme.dimens.size0_5, + ) +} + +@Composable +private fun InformationItem(subtitle: String, value: String) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .padding(TangemTheme.dimens.spacing16), + ) { + + Text( + text = subtitle, + color = TangemTheme.colors.text.primary1, + style = TangemTheme.typography.subtitle1, + maxLines = 1, + ) + + SpacerH16() + + Text( + text = value, + color = TangemTheme.colors.text.tertiary, + style = TangemTheme.typography.body2, + maxLines = 1, + ) + } +} + +@Composable +private fun AmountItem(currency: String, amount: String) { + InformationItem( + subtitle = stringResource(id = R.string.swapping_permission_rows_amount, currency), + value = amount, + ) +} + +@Composable +private fun WalletAddressItem(walletAddress: String) { + InformationItem( + subtitle = stringResource(id = R.string.swapping_permission_rows_your_wallet), + value = walletAddress, + ) +} + +@Composable +private fun SpenderItem(spenderAddress: String) { + InformationItem( + subtitle = stringResource(id = R.string.swapping_permission_rows_spender), + value = spenderAddress, + ) +} + +@Composable +private fun FeeItem(fee: String) { + InformationItem( + subtitle = stringResource(id = R.string.send_fee_label), + value = fee, + ) +} + +// region preview + +@Preview +@Composable +fun Preview_AgreementBottomSheet_InLightTheme() { + TangemTheme(isDark = false) { + SwapPermissionBottomSheetContent(data = previewData) {} + } +} + +@Preview +@Composable +fun Preview_AgreementBottomSheet_InDarkTheme() { + TangemTheme(isDark = true) { + SwapPermissionBottomSheetContent(data = previewData) {} + } +} + +private val previewData = SwapPermissionStateHolder( + currency = "DAI", + amount = "∞", + walletAddress = "", + spenderAddress = "", + fee = "2,14$", + approveButton = ApprovePermissionButton(true) {}, + cancelButton = CancelPermissionButton(true) {}, +) + +//endregion preview \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt new file mode 100644 index 0000000000..5011b9ec33 --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreen.kt @@ -0,0 +1,66 @@ +package com.tangem.feature.swap.ui + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.BottomSheetScaffold +import androidx.compose.material.BottomSheetState +import androidx.compose.material.BottomSheetValue +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.rememberBottomSheetScaffoldState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.res.stringResource +import com.tangem.core.ui.components.appbar.AppBarWithBackButton +import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.swap.models.SwapStateHolder +import com.tangem.feature.swap.presentation.R +import kotlinx.coroutines.launch + +@OptIn(ExperimentalMaterialApi::class) +@Composable +internal fun SwapScreen(stateHolder: SwapStateHolder) { + val coroutineScope = rememberCoroutineScope() + val bottomSheetScaffoldState = rememberBottomSheetScaffoldState( + bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed), + ) + + TangemTheme { + BottomSheetScaffold( + topBar = { + AppBarWithBackButton( + text = stringResource(R.string.swapping_swap), + onBackClick = stateHolder.onBackClicked, + iconRes = R.drawable.ic_close_24, + ) + }, + sheetContent = { + if (stateHolder.permissionState != null) { + SwapPermissionBottomSheetContent( + data = stateHolder.permissionState, + onCancel = { coroutineScope.launch { bottomSheetScaffoldState.bottomSheetState.collapse() } }, + ) + } + }, + scaffoldState = bottomSheetScaffoldState, + sheetShape = RoundedCornerShape( + topStart = TangemTheme.dimens.radius16, + topEnd = TangemTheme.dimens.radius16, + ), + sheetElevation = TangemTheme.dimens.elevation24, + sheetPeekHeight = TangemTheme.dimens.size0, + content = { + SwapScreenContent( + state = stateHolder, + onPermissionWarningClick = { + coroutineScope.launch { + if (bottomSheetScaffoldState.bottomSheetState.isCollapsed) { + bottomSheetScaffoldState.bottomSheetState.expand() + } else { + bottomSheetScaffoldState.bottomSheetState.collapse() + } + } + }, + ) + }, + ) + } +} \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt new file mode 100644 index 0000000000..03249e7a4a --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt @@ -0,0 +1,226 @@ +package com.tangem.feature.swap.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Card +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.ClickableWarningCard +import com.tangem.core.ui.components.PrimaryButtonIconRight +import com.tangem.core.ui.components.SmallInfoCard +import com.tangem.core.ui.components.SmallInfoCardWithWarning +import com.tangem.core.ui.components.SpacerH16 +import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.swap.models.FeeState +import com.tangem.feature.swap.models.SwapButton +import com.tangem.feature.swap.models.SwapCardData +import com.tangem.feature.swap.models.SwapStateHolder +import com.tangem.feature.swap.models.SwapWarning +import com.tangem.feature.swap.models.TransactionCardType +import com.tangem.feature.swap.presentation.R + +@Composable +internal fun SwapScreenContent( + modifier: Modifier = Modifier, + state: SwapStateHolder, + onPermissionWarningClick: () -> Unit, +) { + Column( + modifier = modifier + .fillMaxWidth() + .background(color = TangemTheme.colors.background.primary) + .verticalScroll(rememberScrollState()) + .padding( + start = TangemTheme.dimens.spacing16, + end = TangemTheme.dimens.spacing16, + top = TangemTheme.dimens.spacing16, + bottom = TangemTheme.dimens.spacing32, + ), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16), + ) { + + MainInfo(state) + + FeeItem(feeState = state.fee, currency = state.networkCurrency) + + if (state.warnings.isNotEmpty()) { + SwapWarnings( + warnings = state.warnings, + onApproveWarningClick = onPermissionWarningClick, + ) + } + + PrimaryButtonIconRight( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.swapping_swap), + icon = painterResource(id = R.drawable.ic_tangem_24), + enabled = state.swapButton.enabled, + showProgress = state.swapButton.loading, + onClick = state.swapButton.onClick, + ) + } +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +private fun MainInfo(state: SwapStateHolder) { + Box( + modifier = Modifier + .fillMaxWidth(), + contentAlignment = Alignment.Center, + ) { + Column { + TransactionCard( + type = state.sendCardData.type, + amount = state.sendCardData.amount, + amountEquivalent = state.sendCardData.amountEquivalent, + tokenIconUrl = state.sendCardData.tokenIconUrl, + tokenCurrency = state.sendCardData.tokenCurrency, + networkIconRes = state.sendCardData.networkIconRes, + onChangeTokenClick = if (state.sendCardData.canSelectAnotherToken) state.onSelectTokenClick else null, + ) + SpacerH16() + TransactionCard( + type = state.receiveCardData.type, + amount = state.receiveCardData.amount, + amountEquivalent = state.receiveCardData.amountEquivalent, + tokenIconUrl = state.receiveCardData.tokenIconUrl, + tokenCurrency = state.receiveCardData.tokenCurrency, + networkIconRes = state.receiveCardData.networkIconRes, + onChangeTokenClick = if (state.receiveCardData.canSelectAnotherToken) state.onSelectTokenClick else null, + ) + } + Card( + elevation = TangemTheme.dimens.elevation3, + shape = CircleShape, + backgroundColor = TangemTheme.colors.background.plain, + contentColor = TangemTheme.colors.text.primary1, + modifier = Modifier + .size(TangemTheme.dimens.size48), + onClick = state.onChangeCardsClicked, + ) { + Icon( + painter = painterResource(id = com.tangem.core.ui.R.drawable.ic_exchange_vertical_24), + contentDescription = null, + tint = TangemTheme.colors.text.primary1, + modifier = Modifier + .padding(TangemTheme.dimens.spacing12), + ) + } + } +} + +@Composable +private fun FeeItem(feeState: FeeState, currency: String) { + + val titleString = stringResource(id = R.string.send_fee_label) + when (feeState) { + is FeeState.Loaded -> { + SmallInfoCard(startText = titleString, endText = feeState.fee, isLoading = false) + } + FeeState.Loading -> { + SmallInfoCard(startText = titleString, endText = "", isLoading = true) + } + is FeeState.NotEnoughFundsWarning -> { + SmallInfoCardWithWarning( + startText = titleString, + endText = feeState.fee, + warningText = stringResource(id = R.string.token_details_send_blocked_fee_format, currency), + ) + } + } +} + +@Composable +private fun SwapWarnings( + warnings: List, onApproveWarningClick: () -> Unit, +) { + Column( + modifier = Modifier + .background(color = MaterialTheme.colors.primary) + .fillMaxWidth(), + ) { + warnings.forEach { warning -> + when (warning) { + // SwapWarning.HighPriceImpact -> { + // WarningCard(title = stringResource(id = R.string.), description = stringResource(id = R.string.)) + // } + is SwapWarning.PermissionNeeded -> { + ClickableWarningCard( + title = stringResource(id = R.string.swapping_permission_header), + description = stringResource( + id = R.string.swapping_permission_subheader, + warning.tokenCurrency, + ), + onClick = onApproveWarningClick, + ) + } + // is SwapWarning.RateExpired -> { + // RefreshableWaringCard( + // title = stringResource(id = R.string.), + // description = stringResource(id = R.string.), + // onClick = warning.onClick, + // ) + // } + } + } + } +} + +// region preview + +private val sendCard = SwapCardData( + type = TransactionCardType.SendCard("123", false), + amount = "1 000 000", + amountEquivalent = "1 000 000", + tokenIconUrl = "", + tokenCurrency = "DAI", + networkIconRes = R.drawable.img_polygon_22, + canSelectAnotherToken = false, +) + +private val receiveCard = SwapCardData( + type = TransactionCardType.ReceiveCard(), + amount = "1 000 000", + amountEquivalent = "1 000 000", + tokenIconUrl = "", + tokenCurrency = "DAI", + networkIconRes = R.drawable.img_polygon_22, + canSelectAnotherToken = true, +) + +private val state = SwapStateHolder( + sendCardData = sendCard, + receiveCardData = receiveCard, + fee = FeeState.Loaded(fee = "0.155 MATIC (0.14 $)"), + warnings = emptyList(), + networkCurrency = "MATIC", + swapButton = SwapButton(enabled = true, loading = false, onClick = {}), + onRefresh = {}, onBackClicked = {}, onChangeCardsClicked = {}, +) + +@Preview +@Composable +fun SwapScreenContentPreview() { + TangemTheme(isDark = false) { + SwapScreenContent(state = state) {} + } +} + +// endregion preview diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt new file mode 100644 index 0000000000..2311562db4 --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapSuccessScreen.kt @@ -0,0 +1,31 @@ +package com.tangem.feature.swap.ui + +import androidx.compose.material.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.tangem.core.ui.components.SuccessScreenContent +import com.tangem.core.ui.components.appbar.AppBarWithBackButton +import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.swap.models.SwapSuccessStateHolder +import com.tangem.feature.swap.presentation.R + +@Composable +fun SwapSuccessScreen(state: SwapSuccessStateHolder, onBack: () -> Unit) { + TangemTheme { + Scaffold( + content = { + SuccessScreenContent( + successMessage = state.message, + onButtonClick = onBack, + ) + }, + topBar = { + AppBarWithBackButton( + text = stringResource(R.string.swapping_swap), + onBackClick = onBack, + iconRes = R.drawable.ic_close_24, + ) + }, + ) + } +} \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt new file mode 100644 index 0000000000..d780d7e126 --- /dev/null +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/TransactionCard.kt @@ -0,0 +1,378 @@ +package com.tangem.feature.swap.ui + +import androidx.annotation.DrawableRes +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +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.defaultMinSize +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +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.Card +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import coil.compose.SubcomposeAsyncImage +import coil.request.ImageRequest +import com.tangem.core.ui.R +import com.tangem.core.ui.components.CurrencyPlaceholderIcon +import com.tangem.core.ui.components.FontSizeRange +import com.tangem.core.ui.components.ResizableText +import com.tangem.core.ui.components.SpacerH4 +import com.tangem.core.ui.components.SpacerW12 +import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.swap.models.TransactionCardType +import com.valentinilk.shimmer.shimmer + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun TransactionCard( + type: TransactionCardType, + amount: String?, + amountEquivalent: String?, + tokenIconUrl: String, + tokenCurrency: String, + @DrawableRes networkIconRes: Int? = null, + onChangeTokenClick: (() -> Unit)? = null, + modifier: Modifier = Modifier, +) { + Card( + modifier = modifier, + shape = RoundedCornerShape(TangemTheme.dimens.radius12), + backgroundColor = TangemTheme.colors.background.primary, + elevation = TangemTheme.dimens.elevation2, + onClick = onChangeTokenClick ?: {}, + enabled = onChangeTokenClick != null, + ) { + Box(modifier = Modifier.fillMaxSize()) { + Column( + modifier = Modifier + .fillMaxWidth() + .height(TangemTheme.dimens.size116), + verticalArrangement = Arrangement.SpaceBetween, + horizontalAlignment = Alignment.Start, + ) { + + Header(type = type) + + Content( + type = type, + amount = amount, + amountEquivalent = amountEquivalent, + ) + } + + Box(modifier = Modifier.align(Alignment.BottomEnd)) { + Token( + tokenIconUrl = tokenIconUrl, + tokenCurrency = tokenCurrency, + networkIconRes = networkIconRes, + ) + } + + if (onChangeTokenClick != null) { + Box(modifier = Modifier.align(Alignment.CenterEnd)) { + ChangeTokenSelector() + } + } + } + + } +} + +@Composable +private fun Header( + type: TransactionCardType, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier + .fillMaxWidth() + .padding( + bottom = dimensionResource(id = R.dimen.spacing8), + start = TangemTheme.dimens.spacing16, + end = TangemTheme.dimens.spacing16, + ), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + val title = when (type) { + is TransactionCardType.ReceiveCard -> R.string.exchange_receive_view_header + is TransactionCardType.SendCard -> R.string.exchange_send_view_header + } + Text( + text = stringResource(id = title), + color = TangemTheme.colors.text.tertiary, + maxLines = 1, + style = MaterialTheme.typography.subtitle2, + modifier = Modifier.padding(top = TangemTheme.dimens.spacing12), + ) + if (type is TransactionCardType.SendCard) { + Text( + text = stringResource(R.string.common_balance, type.balance), + color = TangemTheme.colors.text.tertiary, + maxLines = 1, + style = MaterialTheme.typography.body2, + modifier = Modifier.padding(top = TangemTheme.dimens.spacing12), + ) + } + } +} + +@Composable +private fun Content( + type: TransactionCardType, + amount: String?, + amountEquivalent: String?, +) { + Row( + modifier = Modifier + .padding( + top = TangemTheme.dimens.spacing8, + start = TangemTheme.dimens.spacing16, + bottom = TangemTheme.dimens.spacing16, + ), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.Bottom, + ) { + + if (type is TransactionCardType.SendCard && !type.permissionIsGiven) { + Box( + modifier = Modifier + .size(TangemTheme.dimens.size56) + .background( + color = TangemTheme.colors.button.secondary, + shape = RoundedCornerShape(TangemTheme.dimens.size12), + ), + contentAlignment = Alignment.Center, + ) { + Icon( + painter = painterResource(id = R.drawable.ic_locked_24), + contentDescription = null, + tint = TangemTheme.colors.icon.primary1, + ) + } + + SpacerW12() + } + + Column( + modifier = Modifier + .padding( + end = TangemTheme.dimens.spacing92, + ), + verticalArrangement = Arrangement.SpaceBetween, + horizontalAlignment = Alignment.Start, + ) { + + if (amount != null) { + ResizableText( + text = amount, + color = TangemTheme.colors.text.primary1, + style = TangemTheme.typography.h2, + fontSizeRange = + FontSizeRange(min = 16.sp, max = TangemTheme.typography.h2.fontSize), + ) + } else { + Box( + modifier = Modifier + .size(width = TangemTheme.dimens.size102, height = TangemTheme.dimens.size24) + .shimmer() + .background( + color = TangemTheme.colors.button.secondary, + shape = RoundedCornerShape(TangemTheme.dimens.radius6), + ), + ) + } + + Spacer( + modifier = Modifier + .size(TangemTheme.dimens.size4) + .weight(1f), + ) + + if (amountEquivalent != null) { + Text( + text = amountEquivalent, + color = TangemTheme.colors.text.tertiary, + maxLines = 1, + style = TangemTheme.typography.body2, + ) + } else { + Box( + modifier = Modifier + .size(width = TangemTheme.dimens.size40, height = TangemTheme.dimens.size12) + .shimmer() + .background( + color = TangemTheme.colors.button.secondary, + shape = RoundedCornerShape(TangemTheme.dimens.radius3), + ), + ) + } + } + + } +} + +@Composable +fun Token( + tokenIconUrl: String, + tokenCurrency: String, + @DrawableRes networkIconRes: Int? = null, +) { + Column( + modifier = Modifier + .padding( + end = TangemTheme.dimens.spacing12, + bottom = TangemTheme.dimens.spacing12, + ), + verticalArrangement = Arrangement.Bottom, + horizontalAlignment = Alignment.End, + ) { + + Box( + modifier = Modifier + .padding( + end = TangemTheme.dimens.spacing16, + ) + .size(TangemTheme.dimens.size42), + ) { + val tokenImageModifier = Modifier + .align(Alignment.BottomStart) + .size(TangemTheme.dimens.size36) + + SubcomposeAsyncImage( + modifier = tokenImageModifier, + model = ImageRequest.Builder(LocalContext.current) + .data(tokenIconUrl) + .crossfade(true) + .build(), + loading = { TokenImageShimmer(modifier = tokenImageModifier) }, + error = { CurrencyPlaceholderIcon(modifier = tokenImageModifier, tokenCurrency) }, + contentDescription = null, + ) + + if (networkIconRes != null) { + Box( + modifier = Modifier + .align(Alignment.TopEnd) + .size(TangemTheme.dimens.size18) + .background( + color = Color.White, + shape = CircleShape, + ), + contentAlignment = Alignment.Center, + ) { + Image( + modifier = Modifier.padding(all = (0.5).dp), + painter = painterResource(id = networkIconRes), + contentDescription = null, + ) + } + } + } + + SpacerH4() + + Text( + text = tokenCurrency, + color = TangemTheme.colors.text.primary1, + maxLines = 1, + style = TangemTheme.typography.subtitle2, + textAlign = TextAlign.Center, + modifier = Modifier + .defaultMinSize(minWidth = TangemTheme.dimens.size80), + ) + } +} + +@Composable +fun ChangeTokenSelector() { + Box( + modifier = Modifier + .fillMaxHeight() + .padding( + top = TangemTheme.dimens.spacing12, + start = TangemTheme.dimens.spacing24, + end = TangemTheme.dimens.spacing12, + ), + contentAlignment = Alignment.CenterEnd, + ) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size20), + painter = painterResource(id = R.drawable.ic_chevron_24), + contentDescription = null, + ) + } +} + +@Composable +private fun TokenImageShimmer( + modifier: Modifier = Modifier, +) { + Box(modifier = modifier.shimmer()) { + Box( + modifier = Modifier + .matchParentSize() + .background( + color = TangemTheme.colors.button.secondary, + shape = CircleShape, + ), + ) + } +} + +// region preview + +@Preview(widthDp = 328, heightDp = 116, showBackground = true) +@Composable +fun Preview_SwapMainCard_InLightTheme() { + TangemTheme(isDark = false) { + TransactionCardPreview() + } +} + +@Preview(widthDp = 328, heightDp = 116, showBackground = true) +@Composable +fun Preview_SwapMainCard_InDarkTheme() { + TangemTheme(isDark = true) { + TransactionCardPreview() + } +} + +@Composable +private fun TransactionCardPreview() { + TransactionCard( + type = TransactionCardType.SendCard("123", false), + amount = "1 000 000", + amountEquivalent = "1 000 000", + tokenIconUrl = "", + tokenCurrency = "DAI", + networkIconRes = R.drawable.img_polygon_22, + onChangeTokenClick = {}, + ) +} + +// endregion preview \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index fd8a40070f..245d7b404b 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -1,14 +1,31 @@ package com.tangem.feature.swap.viewmodels import android.util.Log +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.tangem.feature.swap.domain.SwapInteractor import com.tangem.feature.swap.domain.models.data.Currency +import com.tangem.feature.swap.models.ApprovePermissionButton +import com.tangem.feature.swap.models.CancelPermissionButton +import com.tangem.feature.swap.models.FeeState +import com.tangem.feature.swap.models.SwapButton +import com.tangem.feature.swap.models.SwapCardData +import com.tangem.feature.swap.models.SwapPermissionStateHolder +import com.tangem.feature.swap.models.SwapStateHolder +import com.tangem.feature.swap.models.SwapSuccessStateHolder +import com.tangem.feature.swap.models.SwapWarning +import com.tangem.feature.swap.models.TransactionCardType +import com.tangem.feature.swap.presentation.R +import com.tangem.feature.swap.router.SwapRouter +import com.tangem.feature.swap.router.SwapScreen import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject +import kotlin.properties.Delegates @HiltViewModel internal class SwapViewModel @Inject constructor( @@ -16,6 +33,27 @@ internal class SwapViewModel @Inject constructor( private val dispatchers: CoroutineDispatcherProvider, ) : ViewModel() { + var uiState: SwapStateHolder by mutableStateOf(createInitialUiState()) + private set + + private var swapRouter: SwapRouter by Delegates.notNull() + + var currentScreen = SwapScreen.Main + get() = swapRouter.currentScreen + + fun setRouter(router: SwapRouter) { + swapRouter = router + uiState = uiState.copy( + onBackClicked = router::back, + onSelectTokenClick = { router.openScreen(SwapScreen.Success) }, + onSuccess = { router.openScreen(SwapScreen.Success) }, + ) + } + + private fun createInitialUiState(): SwapStateHolder { // TODO: create using real state + return createTestUiState() + } + // region temp for test init { viewModelScope.launch { @@ -39,5 +77,48 @@ internal class SwapViewModel @Inject constructor( "1", ) } + + private fun createTestUiState(): SwapStateHolder { + val sendCard = SwapCardData( + type = TransactionCardType.SendCard("123", false), + amount = "1 000 000 000 000 000 000", + amountEquivalent = "1 000 000 000 000 000 000", + tokenIconUrl = "", + tokenCurrency = "DAI", + networkIconRes = R.drawable.img_polygon_22, + ) + + val receiveCard = SwapCardData( + type = TransactionCardType.ReceiveCard(), + amount = "1 000 000", + amountEquivalent = "1 000 000", + tokenIconUrl = "", + tokenCurrency = "DAI", + networkIconRes = R.drawable.img_polygon_22, + canSelectAnotherToken = true, + ) + + val permissionState = SwapPermissionStateHolder( + currency = "DAI", + amount = "∞", + walletAddress = "", + spenderAddress = "", + fee = "2,14$", + approveButton = ApprovePermissionButton(true) {}, + cancelButton = CancelPermissionButton(true) {}, + ) + + return SwapStateHolder( + sendCardData = sendCard, + receiveCardData = receiveCard, + fee = FeeState.Loaded(fee = "0.155 MATIC (0.14 $)"), + warnings = listOf(SwapWarning.PermissionNeeded("DAI")), + networkCurrency = "MATIC", + swapButton = SwapButton(enabled = true, loading = false, onClick = {}), + onRefresh = {}, onBackClicked = {}, onChangeCardsClicked = {}, + permissionState = permissionState, + successState = SwapSuccessStateHolder("Success"), + ) + } // endregion temp for test } \ No newline at end of file