From 2a0e8f78a6612c2e1b9ac25529af83efc16ac25e Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 15 Aug 2023 15:59:41 +0500 Subject: [PATCH] Updated on 2026-08-14 --- app/build.gradle.kts | 1 + .../converters/CryptoCurrencyConverter.kt | 43 +++++++++++++++ .../middlewares/MultiWalletMiddleware.kt | 12 ++++- .../tokens/utils/CardCurrenciesFactory.kt | 53 ++----------------- .../tokens/utils/CryptoCurrencyFactory.kt | 53 +++++++++++++++++++ .../tokens/utils/ResponseCurrenciesFactory.kt | 2 + .../data/tokens/utils/TokensOperations.kt | 11 ++++ .../domain/tokens/models/CryptoCurrency.kt | 26 ++++++++- .../tangem/domain/tokens/mock/MockTokens.kt | 14 +++++ .../navigation/TokenDetailsRouter.kt | 4 ++ features/tokendetails/impl/build.gradle.kts | 1 + .../viewmodels/TokenDetailsViewModel.kt | 27 +++++++++- features/wallet/impl/build.gradle.kts | 1 + .../presentation/common/WalletPreviewData.kt | 2 + .../common/component/TokenItem.kt | 7 ++- .../common/state/TokenItemState.kt | 1 + .../router/DefaultWalletRouter.kt | 15 +++++- .../presentation/router/InnerWalletRouter.kt | 4 ++ ...ryptoCurrencyStatusToTokenItemConverter.kt | 3 ++ .../utils/TokenListToContentItemsConverter.kt | 1 + .../wallet/viewmodels/WalletClickIntents.kt | 4 ++ .../wallet/viewmodels/WalletViewModel.kt | 5 ++ 22 files changed, 236 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/features/wallet/converters/CryptoCurrencyConverter.kt create mode 100644 data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/CryptoCurrencyFactory.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 38e1d9c644..5e5e70656a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation(project(":domain:wallets:models")) implementation(projects.domain.settings) implementation(projects.domain.tokens) + implementation(projects.domain.tokens.models) implementation(projects.domain.txhistory) implementation(projects.domain.appCurrency) implementation(projects.domain.appCurrency.models) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/converters/CryptoCurrencyConverter.kt b/app/src/main/java/com/tangem/tap/features/wallet/converters/CryptoCurrencyConverter.kt new file mode 100644 index 0000000000..1cf1515b01 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/features/wallet/converters/CryptoCurrencyConverter.kt @@ -0,0 +1,43 @@ +package com.tangem.tap.features.wallet.converters + +import com.tangem.data.tokens.utils.CryptoCurrencyFactory +import com.tangem.domain.common.util.derivationStyleProvider +import com.tangem.domain.tokens.models.CryptoCurrency +import com.tangem.tap.features.wallet.models.Currency +import com.tangem.tap.store +import com.tangem.utils.converter.Converter + +class CryptoCurrencyConverter : Converter { + + private val cryptoCurrencyFactory by lazy { CryptoCurrencyFactory() } + + override fun convert(value: Currency): CryptoCurrency { + return when (value) { + is Currency.Blockchain -> requireNotNull( + cryptoCurrencyFactory.createCoin( + blockchain = value.blockchain, + derivationStyleProvider = requireNotNull( + store.state.globalState + .userWalletsListManager + ?.selectedUserWalletSync + ?.scanResponse + ?.derivationStyleProvider, + ), + ), + ) + is Currency.Token -> requireNotNull( + cryptoCurrencyFactory.createToken( + sdkToken = value.token, + blockchain = value.blockchain, + derivationStyleProvider = requireNotNull( + store.state.globalState + .userWalletsListManager + ?.selectedUserWalletSync + ?.scanResponse + ?.derivationStyleProvider, + ), + ), + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 3f080d645a..91fa88858c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.wallet.redux.middlewares +import androidx.core.os.bundleOf import com.tangem.common.doOnSuccess import com.tangem.common.extensions.guard import com.tangem.common.flatMap @@ -7,6 +8,7 @@ import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.domain.wallets.models.UserWallet +import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken import com.tangem.tap.common.extensions.addContext @@ -15,6 +17,7 @@ import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchWithMain import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TapError +import com.tangem.tap.features.wallet.converters.CryptoCurrencyConverter import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState import com.tangem.tap.features.wallet.redux.models.WalletDialog @@ -28,12 +31,19 @@ import kotlinx.coroutines.launch import timber.log.Timber class MultiWalletMiddleware { + + private val cryptoCurrencyConverter by lazy { CryptoCurrencyConverter() } + @Suppress("LongMethod", "ComplexMethod") fun handle(action: WalletAction.MultiWallet, walletState: WalletState?) { when (action) { is WalletAction.MultiWallet.SelectWallet -> { if (action.currency != null) { - store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletDetails)) + val bundle = bundleOf( + // TODO: [REDACTED_JIRA] + TokenDetailsRouter.SELECTED_CURRENCY_KEY to cryptoCurrencyConverter.convert(action.currency), + ) + store.dispatch(NavigationAction.NavigateTo(screen = AppScreen.WalletDetails, bundle = bundle)) } } is WalletAction.MultiWallet.TryToRemoveWallet -> { diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/CardCurrenciesFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/CardCurrenciesFactory.kt index a98f9b0d8e..269c65e9f7 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/CardCurrenciesFactory.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/CardCurrenciesFactory.kt @@ -9,11 +9,11 @@ import com.tangem.domain.demo.DemoConfig import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.tokens.models.CryptoCurrency -import timber.log.Timber -import com.tangem.blockchain.common.Token as SdkToken internal class CardCurrenciesFactory(private val demoConfig: DemoConfig) { + private val cryptoCurrencyFactory by lazy { CryptoCurrencyFactory() } + fun createDefaultCoinsForMultiCurrencyCard( card: CardDTO, derivationStyleProvider: DerivationStyleProvider, @@ -28,7 +28,7 @@ internal class CardCurrenciesFactory(private val demoConfig: DemoConfig) { blockchains = blockchains.mapNotNull { it.getTestnetVersion() } } - return blockchains.mapNotNull { createCoin(it, derivationStyleProvider) } + return blockchains.mapNotNull { cryptoCurrencyFactory.createCoin(it, derivationStyleProvider) } } fun createPrimaryCurrencyForSingleCurrencyCard(scanResponse: ScanResponse): CryptoCurrency { @@ -36,56 +36,13 @@ internal class CardCurrenciesFactory(private val demoConfig: DemoConfig) { val resolver = scanResponse.cardTypesResolver val blockchain = resolver.getBlockchain() - val coin = requireNotNull(createCoin(blockchain, derivationStyleProvider)) { + val coin = requireNotNull(cryptoCurrencyFactory.createCoin(blockchain, derivationStyleProvider)) { "Coin for the single currency card cannot be null" } val primaryToken = resolver.getPrimaryToken()?.let { token -> - createToken(token, blockchain, derivationStyleProvider) + cryptoCurrencyFactory.createToken(token, blockchain, derivationStyleProvider) } return primaryToken ?: coin } - - private fun createToken( - sdkToken: SdkToken, - blockchain: Blockchain, - derivationStyleProvider: DerivationStyleProvider, - ): CryptoCurrency.Token? { - if (blockchain != Blockchain.Unknown) { - Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain") - return null - } - - return CryptoCurrency.Token( - id = getTokenId(blockchain, sdkToken), - networkId = getNetworkId(blockchain), - name = sdkToken.name, - symbol = sdkToken.symbol, - iconUrl = getTokenIconUrl(blockchain, sdkToken), - decimals = sdkToken.decimals, - isCustom = false, - contractAddress = sdkToken.contractAddress, - derivationPath = getDerivationPath(blockchain, derivationStyleProvider), - ) - } - - private fun createCoin( - blockchain: Blockchain, - derivationStyleProvider: DerivationStyleProvider, - ): CryptoCurrency.Coin? { - if (blockchain == Blockchain.Unknown) { - Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain") - return null - } - - return CryptoCurrency.Coin( - id = getCoinId(blockchain), - networkId = getNetworkId(blockchain), - name = blockchain.fullName, - symbol = blockchain.currency, - iconUrl = getCoinIconUrl(blockchain), - decimals = blockchain.decimals(), - derivationPath = getDerivationPath(blockchain, derivationStyleProvider), - ) - } } \ No newline at end of file diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/CryptoCurrencyFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/CryptoCurrencyFactory.kt new file mode 100644 index 0000000000..f4e0148b34 --- /dev/null +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/CryptoCurrencyFactory.kt @@ -0,0 +1,53 @@ +package com.tangem.data.tokens.utils + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token as SdkToken +import com.tangem.domain.common.DerivationStyleProvider +import com.tangem.domain.tokens.models.CryptoCurrency +import timber.log.Timber + +class CryptoCurrencyFactory { + + fun createToken( + sdkToken: SdkToken, + blockchain: Blockchain, + derivationStyleProvider: DerivationStyleProvider, + ): CryptoCurrency.Token? { + if (blockchain == Blockchain.Unknown) { + Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain") + return null + } + + val id = getTokenId(blockchain, sdkToken) + return CryptoCurrency.Token( + id = id, + networkId = getNetworkId(blockchain), + name = sdkToken.name, + symbol = sdkToken.symbol, + iconUrl = getTokenIconUrl(blockchain, sdkToken), + decimals = sdkToken.decimals, + isCustom = isCustomToken(id), + contractAddress = sdkToken.contractAddress, + derivationPath = getDerivationPath(blockchain, derivationStyleProvider), + blockchainName = blockchain.fullName, + standardType = getTokenStandardType(blockchain, sdkToken), + ) + } + + fun createCoin(blockchain: Blockchain, derivationStyleProvider: DerivationStyleProvider): CryptoCurrency.Coin? { + if (blockchain == Blockchain.Unknown) { + Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain") + return null + } + + return CryptoCurrency.Coin( + id = getCoinId(blockchain), + networkId = getNetworkId(blockchain), + name = blockchain.fullName, + symbol = blockchain.currency, + iconUrl = getCoinIconUrl(blockchain), + decimals = blockchain.decimals(), + derivationPath = getDerivationPath(blockchain, derivationStyleProvider), + ) + } +} \ No newline at end of file diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCurrenciesFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCurrenciesFactory.kt index 89d6bfec27..b79f32f515 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCurrenciesFactory.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/ResponseCurrenciesFactory.kt @@ -84,6 +84,8 @@ internal class ResponseCurrenciesFactory(private val demoConfig: DemoConfig) { iconUrl = getTokenIconUrl(blockchain, sdkToken), contractAddress = sdkToken.contractAddress, isCustom = isCustomToken(id), + blockchainName = blockchain.fullName, + standardType = getTokenStandardType(blockchain, sdkToken), ) } } \ No newline at end of file diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/TokensOperations.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/TokensOperations.kt index cbc158d2fc..b047d19e32 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/TokensOperations.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/TokensOperations.kt @@ -6,6 +6,7 @@ import com.tangem.domain.common.DerivationStyleProvider import com.tangem.domain.common.extensions.derivationPath import com.tangem.domain.common.extensions.toCoinId import com.tangem.domain.common.extensions.toNetworkId +import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.tokens.models.CryptoCurrency.ID import com.tangem.domain.tokens.models.Network import com.tangem.blockchain.common.Token as SdkToken @@ -45,6 +46,16 @@ internal fun getTokenId(blockchain: Blockchain, token: SdkToken): ID { return getTokenOrCoinId(blockchain, token) } +internal fun getTokenStandardType(blockchain: Blockchain, token: SdkToken): CryptoCurrency.StandardType { + return when (blockchain) { + Blockchain.Ethereum, Blockchain.EthereumTestnet -> CryptoCurrency.StandardType.ERC20 + Blockchain.BSC, Blockchain.BSCTestnet -> CryptoCurrency.StandardType.BEP20 + Blockchain.Binance, Blockchain.BinanceTestnet -> CryptoCurrency.StandardType.BEP2 + Blockchain.Tron, Blockchain.TronTestnet -> CryptoCurrency.StandardType.TRC20 + else -> CryptoCurrency.StandardType.Unspecified(token.name) + } +} + internal fun getTokenIconUrl(blockchain: Blockchain, token: SdkToken): String? { val tokenId = token.id diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/CryptoCurrency.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/CryptoCurrency.kt index d31577a3a9..83d1d65eb0 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/CryptoCurrency.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/models/CryptoCurrency.kt @@ -1,5 +1,7 @@ package com.tangem.domain.tokens.models +import java.io.Serializable + /** * Represents a generic cryptocurrency. * @@ -12,7 +14,7 @@ package com.tangem.domain.tokens.models * @property derivationPath Optional path used for key derivation. `null` if the wallet does not support the * [HD Wallet](https://coinsutra.com/hd-wallets-deterministic-wallet/) feature. */ -sealed class CryptoCurrency { +sealed class CryptoCurrency : Serializable { abstract val id: ID abstract val networkId: Network.ID @@ -56,6 +58,8 @@ sealed class CryptoCurrency { override val derivationPath: String?, val contractAddress: String, val isCustom: Boolean, + val blockchainName: String, // TODO: Move this field to proper entity + val standardType: StandardType, // TODO: Move this field to proper entity ) : CryptoCurrency() { init { @@ -130,6 +134,26 @@ sealed class CryptoCurrency { } } + sealed class StandardType { + abstract val name: String + + object ERC20 : StandardType() { + override val name: String = "ERC20" + } + object TRC20 : StandardType() { + override val name: String = "TRC20" + } + object BEP20 : StandardType() { + override val name: String = "BEP20" + } + object BEP2 : StandardType() { + override val name: String = "BEP2" + } + class Unspecified(val tokenName: String) : StandardType() { + override val name: String = tokenName + } + } + protected fun checkProperties() { require(name.isNotBlank()) { "Crypto currency name must not be blank" } require(symbol.isNotBlank()) { "Crypto currency symbol must not be blank" } diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokens.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokens.kt index 7e22b04347..6e3749a46f 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokens.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokens.kt @@ -26,6 +26,8 @@ internal object MockTokens { iconUrl = null, contractAddress = "address", derivationPath = null, + blockchainName = "Ethereum", + standardType = CryptoCurrency.StandardType.ERC20, ) val token3 get() = CryptoCurrency.Token( @@ -38,6 +40,8 @@ internal object MockTokens { iconUrl = null, contractAddress = "address", derivationPath = null, + blockchainName = "Ethereum", + standardType = CryptoCurrency.StandardType.ERC20, ) val token4 get() = CryptoCurrency.Coin( @@ -60,6 +64,8 @@ internal object MockTokens { iconUrl = null, contractAddress = "address", derivationPath = null, + blockchainName = "Ethereum", + standardType = CryptoCurrency.StandardType.ERC20, ) val token6 get() = CryptoCurrency.Token( @@ -72,6 +78,8 @@ internal object MockTokens { iconUrl = null, contractAddress = "address", derivationPath = null, + blockchainName = "Ethereum", + standardType = CryptoCurrency.StandardType.ERC20, ) val token7 get() = CryptoCurrency.Coin( @@ -94,6 +102,8 @@ internal object MockTokens { iconUrl = null, contractAddress = "address", derivationPath = null, + blockchainName = "Ethereum", + standardType = CryptoCurrency.StandardType.ERC20, ) val token9 get() = CryptoCurrency.Token( @@ -106,6 +116,8 @@ internal object MockTokens { iconUrl = null, contractAddress = "address", derivationPath = null, + blockchainName = "Ethereum", + standardType = CryptoCurrency.StandardType.ERC20, ) val token10 get() = CryptoCurrency.Token( @@ -118,6 +130,8 @@ internal object MockTokens { iconUrl = null, contractAddress = "address", derivationPath = null, + blockchainName = "Ethereum", + standardType = CryptoCurrency.StandardType.ERC20, ) val tokens = listOf(token1, token2, token3, token4, token5, token6, token7, token8, token9, token10) diff --git a/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsRouter.kt b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsRouter.kt index a361d75438..81dbc9eb69 100644 --- a/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsRouter.kt +++ b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsRouter.kt @@ -5,4 +5,8 @@ import androidx.fragment.app.Fragment interface TokenDetailsRouter { fun getEntryFragment(): Fragment + + companion object { + const val SELECTED_CURRENCY_KEY = "selected_currency" + } } \ No newline at end of file diff --git a/features/tokendetails/impl/build.gradle.kts b/features/tokendetails/impl/build.gradle.kts index e37da473bc..a7c6440862 100644 --- a/features/tokendetails/impl/build.gradle.kts +++ b/features/tokendetails/impl/build.gradle.kts @@ -38,6 +38,7 @@ dependencies { implementation(projects.core.ui) implementation(projects.core.navigation) + implementation(projects.domain.tokens.models) implementation(projects.domain.txhistory) implementation(projects.domain.txhistory.models) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index 4a75d46fb5..5dfeaf2b82 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -3,10 +3,15 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter import com.tangem.feature.tokendetails.presentation.tokendetails.TokenDetailsPreviewData +import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenInfoBlockState +import com.tangem.features.tokendetails.impl.R +import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -16,9 +21,14 @@ import kotlin.properties.Delegates private const val LOADING_DELAY = 4_000L @HiltViewModel -internal class TokenDetailsViewModel @Inject constructor() : ViewModel() { +internal class TokenDetailsViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, +) : ViewModel() { - var router: InnerTokenDetailsRouter by Delegates.notNull() + private val cryptoCurrency: CryptoCurrency = savedStateHandle[TokenDetailsRouter.SELECTED_CURRENCY_KEY] + ?: error("no expected parameter CryptoCurrency found") + + var router by Delegates.notNull() var uiState by mutableStateOf(getInitialState()) private set @@ -38,6 +48,19 @@ internal class TokenDetailsViewModel @Inject constructor() : ViewModel() { topAppBarConfig = TokenDetailsPreviewData.tokenDetailsTopAppBarConfig.copy( onBackClick = ::onBackClick, ), + tokenInfoBlockState = TokenInfoBlockState( + name = cryptoCurrency.name, + iconUrl = requireNotNull(cryptoCurrency.iconUrl), + currency = when (cryptoCurrency) { + is CryptoCurrency.Coin -> TokenInfoBlockState.Currency.Native + is CryptoCurrency.Token -> TokenInfoBlockState.Currency.Token( + networkName = cryptoCurrency.standardType.name, + blockchainName = cryptoCurrency.blockchainName, + // TODO: [REDACTED_JIRA] + networkIcon = R.drawable.img_eth_22, + ) + }, + ), ) private fun onBackClick() { diff --git a/features/wallet/impl/build.gradle.kts b/features/wallet/impl/build.gradle.kts index ed9a84d4f4..cc22ff78e4 100644 --- a/features/wallet/impl/build.gradle.kts +++ b/features/wallet/impl/build.gradle.kts @@ -61,4 +61,5 @@ dependencies { /** Feature Apis */ implementation(projects.features.wallet.api) + implementation(projects.features.tokendetails.api) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt index 03fbc388d2..d0bb5cc8e7 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt @@ -100,6 +100,7 @@ internal object WalletPreviewData { type = PriceChangeConfig.Type.UP, ), ), + onClick = {}, ) } @@ -118,6 +119,7 @@ internal object WalletPreviewData { type = PriceChangeConfig.Type.UP, ), ), + onClick = {}, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/TokenItem.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/TokenItem.kt index 8effab7dad..0e9751d451 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/TokenItem.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/TokenItem.kt @@ -61,6 +61,7 @@ internal fun TokenItem(state: TokenItemState, modifier: Modifier = Modifier) { private fun ContentTokenItem(content: TokenItemState.Content, modifier: Modifier = Modifier) { InternalTokenItem( modifier = modifier, + onClick = content.onClick, name = content.name, tokenIconUrl = content.tokenIconUrl, tokenIconResId = content.tokenIconResId, @@ -217,8 +218,12 @@ private fun InternalTokenItem( hasPending: Boolean, options: @Composable ConstraintLayoutScope.(ref: ConstrainedLayoutReference) -> Unit, modifier: Modifier = Modifier, + onClick: (() -> Unit)? = null, ) { - BaseSurface(modifier) { + BaseSurface( + modifier = modifier, + onClick = onClick, + ) { ConstraintLayout( modifier = Modifier .fillMaxWidth() diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/state/TokenItemState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/state/TokenItemState.kt index b53c7458b8..bb2883ed5f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/state/TokenItemState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/state/TokenItemState.kt @@ -35,6 +35,7 @@ internal sealed interface TokenItemState { val amount: String, val hasPending: Boolean, val tokenOptions: TokenOptionsState, + val onClick: () -> Unit, ) : TokenItemState /** diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index 397a39c2ae..aa8edc6a9c 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.hilt.navigation.compose.hiltViewModel @@ -16,12 +17,14 @@ import androidx.navigation.navArgument import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.core.navigation.NavigationStateHolder +import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.wallet.presentation.WalletFragment import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensScreen import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensViewModel import com.tangem.feature.wallet.presentation.wallet.ui.WalletScreen import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletViewModel +import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import kotlin.properties.Delegates /** Default implementation of wallet feature router */ @@ -42,7 +45,7 @@ internal class DefaultWalletRouter(private val navigationStateHolder: Navigation ) { composable(WalletRoute.Wallet.route) { val viewModel = hiltViewModel().apply { router = this@DefaultWalletRouter } - LocalLifecycleOwner.current.lifecycle.addObserver(observer = viewModel) + LocalLifecycleOwner.current.lifecycle.addObserver(viewModel) WalletScreen(state = viewModel.uiState) } @@ -96,6 +99,16 @@ internal class DefaultWalletRouter(private val navigationStateHolder: Navigation navigationStateHolder.navigate(action = NavigationAction.OpenUrl(url)) } + override fun openTokenDetails(currency: CryptoCurrency) { + navigationStateHolder.navigate( + action = NavigationAction.NavigateTo( + screen = AppScreen.WalletDetails, + // TODO: [REDACTED_JIRA] + bundle = bundleOf(TokenDetailsRouter.SELECTED_CURRENCY_KEY to currency), + ), + ) + } + private companion object { const val BACKSTACK_ENTRY_COUNT_TO_CLOSE_WALLET_SCREEN = 2 } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt index 5fab6367de..4a0d24bbaa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/InnerWalletRouter.kt @@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.router import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.fragment.app.FragmentManager +import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.wallet.navigation.WalletRouter @@ -40,4 +41,7 @@ internal interface InnerWalletRouter : WalletRouter { /** Open transaction history website by [url] */ fun openTxHistoryWebsite(url: String) + + /** Open token details screen */ + fun openTokenDetails(currency: CryptoCurrency) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt index 1790a50da4..4c9c49ed14 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt @@ -9,12 +9,14 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.presentation.common.state.TokenItemState +import com.tangem.feature.wallet.presentation.wallet.viewmodels.WalletClickIntents import com.tangem.utils.converter.Converter import java.math.BigDecimal internal class CryptoCurrencyStatusToTokenItemConverter( private val appCurrencyProvider: Provider, private val isWalletContentHidden: Boolean, + private val clickIntents: WalletClickIntents, ) : Converter { private val CryptoCurrencyStatus.networkIconResId: Int? @@ -61,6 +63,7 @@ internal class CryptoCurrencyStatusToTokenItemConverter( priceChange = getPriceChangeConfig(), ) }, + onClick = { clickIntents.onTokenClick(currency) }, ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToContentItemsConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToContentItemsConverter.kt index 8bef92141f..ca50986a37 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToContentItemsConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/TokenListToContentItemsConverter.kt @@ -24,6 +24,7 @@ internal class TokenListToContentItemsConverter( private val tokenStatusConverter = CryptoCurrencyStatusToTokenItemConverter( isWalletContentHidden = isWalletContentHidden, appCurrencyProvider = appCurrencyProvider, + clickIntents = clickIntents, ) override fun convert(value: TokenList): WalletTokensListState { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt index e38b9bd0f3..2dcc2ddc06 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletClickIntents.kt @@ -1,5 +1,7 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels +import com.tangem.domain.tokens.models.CryptoCurrency + internal interface WalletClickIntents { fun onBackClick() @@ -37,4 +39,6 @@ internal interface WalletClickIntents { fun onUnlockWalletNotificationClick() fun onBottomSheetDismiss() + + fun onTokenClick(currency: CryptoCurrency) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index 3745757446..866dfadf62 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -22,6 +22,7 @@ import com.tangem.domain.settings.IsUserAlreadyRateAppUseCase import com.tangem.domain.tokens.GetPrimaryCurrencyUseCase import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.domain.tokens.model.TokenList +import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.tokens.models.Network import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase @@ -439,6 +440,10 @@ internal class WalletViewModel @Inject constructor( uiState = stateFactory.getStateWithClosedBottomSheet() } + override fun onTokenClick(currency: CryptoCurrency) { + router.openTokenDetails(currency = currency) + } + private fun createSelectedAppCurrencyFlow(): StateFlow { return getSelectedAppCurrencyUseCase() .map { maybeAppCurrency ->