From c215778788f4fdbfe3c20cf439a54f5a14f51789 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 26 Sep 2023 18:14:45 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/di/domain/TokensDomainModule.kt | 6 ++ .../middlewares/MultiWalletMiddleware.kt | 24 +++++++- domain/tokens/models/build.gradle.kts | 8 ++- .../domain/tokens/model/CryptoCurrency.kt | 60 ++++++++++--------- .../com/tangem/domain/tokens/model/Network.kt | 10 +--- .../domain/tokens/GetCryptoCurrencyUseCase.kt | 56 +++++++++++++++++ features/tokendetails/api/build.gradle.kts | 3 + .../navigation/TokenDetailsArguments.kt | 30 ++++++++++ .../navigation/TokenDetailsRouter.kt | 2 +- .../tokendetails/TokenDetailsPreviewData.kt | 8 +-- .../tokendetails/state/TokenInfoBlockState.kt | 9 +-- .../TokenDetailsSkeletonStateConverter.kt | 32 ++++------ .../state/factory/TokenDetailsStateFactory.kt | 19 +++--- .../ui/components/TokenInfoBlock.kt | 2 +- .../viewmodels/TokenDetailsViewModel.kt | 30 +++++++--- .../router/DefaultWalletRouter.kt | 19 +++++- 16 files changed, 230 insertions(+), 88 deletions(-) create mode 100644 domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyUseCase.kt create mode 100644 features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsArguments.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt index 42546775f3..b2f6fa50eb 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt @@ -103,6 +103,12 @@ internal object TokensDomainModule { return FetchCurrencyStatusUseCase(currenciesRepository, networksRepository, quotesRepository) } + @Provides + @ViewModelScoped + fun provideGetCryptoCurrencyUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrencyUseCase { + return GetCryptoCurrencyUseCase(currenciesRepository) + } + @Provides @ViewModelScoped fun provideToggleTokenListGroupingUseCase( 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 91fa88858c..1e42d1a91f 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 @@ -7,7 +7,10 @@ import com.tangem.common.flatMap import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction +import com.tangem.core.ui.extensions.networkIconResId +import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWallet +import com.tangem.features.tokendetails.navigation.TokenDetailsArguments import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken @@ -17,6 +20,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.models.Currency import com.tangem.tap.features.wallet.converters.CryptoCurrencyConverter import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState @@ -40,8 +44,7 @@ class MultiWalletMiddleware { is WalletAction.MultiWallet.SelectWallet -> { if (action.currency != null) { val bundle = bundleOf( - // TODO: [REDACTED_JIRA] - TokenDetailsRouter.SELECTED_CURRENCY_KEY to cryptoCurrencyConverter.convert(action.currency), + TokenDetailsRouter.TOKEN_DETAILS_ARGS to createTokenDetailsArgument(action.currency), ) store.dispatch(NavigationAction.NavigateTo(screen = AppScreen.WalletDetails, bundle = bundle)) } @@ -130,4 +133,21 @@ class MultiWalletMiddleware { store.state.globalState.tapWalletManager.loadData(updatedUserWallet, refresh = true) } } + + private fun createTokenDetailsArgument(currency: Currency): TokenDetailsArguments { + val cryptoCurrency = cryptoCurrencyConverter.convert(currency) + return TokenDetailsArguments( + currencyId = cryptoCurrency.id, + currencyName = cryptoCurrency.name, + iconUrl = cryptoCurrency.iconUrl, + coinType = when (cryptoCurrency) { + is CryptoCurrency.Coin -> TokenDetailsArguments.CoinType.Native + is CryptoCurrency.Token -> TokenDetailsArguments.CoinType.Token( + standardName = cryptoCurrency.network.standardType.name, + networkName = cryptoCurrency.network.name, + networkIcon = cryptoCurrency.networkIconResId, + ) + }, + ) + } } \ No newline at end of file diff --git a/domain/tokens/models/build.gradle.kts b/domain/tokens/models/build.gradle.kts index 7efdd44423..0e4d43a1fc 100644 --- a/domain/tokens/models/build.gradle.kts +++ b/domain/tokens/models/build.gradle.kts @@ -1,8 +1,14 @@ plugins { - alias(deps.plugins.kotlin.jvm) + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + id("kotlin-parcelize") id("configuration") } +android { + namespace = "com.tangem.domain.tokens.model" +} + dependencies { implementation(projects.domain.txhistory.models) } \ No newline at end of file diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrency.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrency.kt index b32c9ef6cc..161c9cb1cc 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrency.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/CryptoCurrency.kt @@ -1,6 +1,7 @@ package com.tangem.domain.tokens.model -import java.io.Serializable +import android.os.Parcelable +import kotlinx.parcelize.Parcelize /** * Represents a generic cryptocurrency. @@ -13,8 +14,7 @@ import java.io.Serializable * @property iconUrl Optional URL of the cryptocurrency icon. `null` if not found. * @property isCustom Indicates whether the currency is a custom user-added currency or not. */ -// FIXME: Remove serialization [REDACTED_JIRA] -sealed class CryptoCurrency : Serializable { +sealed class CryptoCurrency { abstract val id: ID abstract val network: Network @@ -74,29 +74,31 @@ sealed class CryptoCurrency : Serializable { * @property rawCurrencyId Represents not unique currency ID from the blockchain network. `null` if * its ID of the custom token. */ - // FIXME: Remove serialization [REDACTED_JIRA] + @Parcelize data class ID( private val prefix: Prefix, private val body: Body, private val suffix: Suffix, - ) : Serializable { + ) : Parcelable { - val value: String = buildString { - append(prefix.value) - append(PREFIX_DELIMITER) - append(body.value) - append(SUFFIX_DELIMITER) - append(suffix.value) - } + val value: String + get() = buildString { + append(prefix.value) + append(PREFIX_DELIMITER) + append(body.value) + append(SUFFIX_DELIMITER) + append(suffix.value) + } /** Represents a raw cryptocurrency ID. If it is a custom token, the value will be `null`. */ - val rawCurrencyId: String? = (suffix as? Suffix.RawID)?.rawId + val rawCurrencyId: String? get() = (suffix as? Suffix.RawID)?.rawId /** Represents a raw cryptocurrency's network ID. */ - val rawNetworkId: String = when (body) { - is Body.NetworkId -> body.rawId - is Body.NetworkIdWithDerivationPath -> body.rawId - } + val rawNetworkId: String + get() = when (body) { + is Body.NetworkId -> body.rawId + is Body.NetworkIdWithDerivationPath -> body.rawId + } /** * Represents the different types of prefixes that can be associated with a cryptocurrency ID. @@ -116,14 +118,15 @@ sealed class CryptoCurrency : Serializable { * * The body can be either a raw network ID or a raw network ID with a network derivation path. */ - sealed class Body : Serializable { + @Parcelize + sealed class Body : Parcelable { /** The value of the body. */ abstract val value: String /** Represents a raw network ID. */ data class NetworkId(val rawId: String) : Body() { - override val value: String = rawId + override val value: String get() = rawId } /** @@ -135,11 +138,12 @@ sealed class CryptoCurrency : Serializable { val rawId: String, val derivationPath: String, ) : Body() { - override val value: String = buildString { - append(rawId) - append(DERIVATION_PATH_DELIMITER) - append(derivationPath.hashCode()) - } + override val value: String + get() = buildString { + append(rawId) + append(DERIVATION_PATH_DELIMITER) + append(derivationPath.hashCode()) + } } } @@ -148,20 +152,20 @@ sealed class CryptoCurrency : Serializable { * * The suffix can either be a raw ID or a contract address. */ - // FIXME: Remove serialization [REDACTED_JIRA] - sealed class Suffix : Serializable { + @Parcelize + sealed class Suffix : Parcelable { /** The value of the suffix, which could be either a raw ID or a contract address. */ abstract val value: String /** Represents a raw ID suffix. */ data class RawID(val rawId: String) : Suffix() { - override val value: String = rawId + override val value: String get() = rawId } /** Represents a contract address suffix. */ data class ContractAddress(val contractAddress: String) : Suffix() { - override val value: String = contractAddress + override val value: String get() = contractAddress } } diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt index a161d9c3ca..03bfac5ee6 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt @@ -1,7 +1,5 @@ package com.tangem.domain.tokens.model -import java.io.Serializable - /** * Represents a blockchain network, identified by a unique ID, a human-readable name, and its standard type. * @@ -15,14 +13,13 @@ import java.io.Serializable * @property isTestnet Indicates whether the network is a test network or a main network. * @property standardType The type of blockchain standard the network adheres to. */ -// FIXME: Remove serialization [REDACTED_JIRA] data class Network( val id: ID, val name: String, val derivationPath: DerivationPath, val isTestnet: Boolean, val standardType: StandardType, -) : Serializable { +) { init { require(name.isNotBlank()) { "Network name must not be blank" } @@ -47,7 +44,7 @@ data class Network( * This class represents such paths in a generic manner, allowing for predefined card-based paths, * custom paths, or even no derivation path at all. */ - sealed class DerivationPath : Serializable { + sealed class DerivationPath { /** The actual derivation path value, if any. */ abstract val value: String? @@ -83,8 +80,7 @@ data class Network( * * @property name The human-readable name of the standard type. */ - // FIXME: Remove serialization [REDACTED_JIRA] - sealed class StandardType : Serializable { + sealed class StandardType { abstract val name: String /** Represents the ERC20 token standard, common on the Ethereum network. */ diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyUseCase.kt new file mode 100644 index 0000000000..194ffc0416 --- /dev/null +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyUseCase.kt @@ -0,0 +1,56 @@ +package com.tangem.domain.tokens + +import arrow.core.Either +import arrow.core.raise.Raise +import arrow.core.raise.catch +import arrow.core.raise.either +import com.tangem.domain.tokens.error.CurrencyStatusError +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.repository.CurrenciesRepository +import com.tangem.domain.wallets.models.UserWalletId + +class GetCryptoCurrencyUseCase( + private val currenciesRepository: CurrenciesRepository, +) { + + /** + * Returns specific cryptocurrency for a given user wallet. + * + * @param userWalletId The ID of the user's wallet. + * @param id The ID of the cryptocurrency. + * @return An [Either] representing success (Right) or an error (Left) in fetching the status. + */ + suspend operator fun invoke( + userWalletId: UserWalletId, + id: CryptoCurrency.ID, + ): Either { + return either { getCurrency(userWalletId, id) } + } + + /** + * Returns the primary cryptocurrency for a given user wallet. + * + * @param userWalletId The ID of the user's wallet. + * @return An [Either] representing success (Right) or an error (Left) in fetching the status. + */ + suspend operator fun invoke(userWalletId: UserWalletId): Either { + return either { getPrimaryCurrency(userWalletId) } + } + + private suspend fun Raise.getCurrency( + userWalletId: UserWalletId, + id: CryptoCurrency.ID, + ): CryptoCurrency { + return catch( + block = { currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, id) }, + catch = { raise(CurrencyStatusError.DataError(it)) }, + ) + } + + private suspend fun Raise.getPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency { + return catch( + block = { currenciesRepository.getSingleCurrencyWalletPrimaryCurrency(userWalletId) }, + catch = { raise(CurrencyStatusError.DataError(it)) }, + ) + } +} \ No newline at end of file diff --git a/features/tokendetails/api/build.gradle.kts b/features/tokendetails/api/build.gradle.kts index b7c1f22eeb..26d2527cd2 100644 --- a/features/tokendetails/api/build.gradle.kts +++ b/features/tokendetails/api/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(deps.plugins.android.library) alias(deps.plugins.kotlin.android) + id("kotlin-parcelize") id("configuration") } @@ -9,6 +10,8 @@ android { } dependencies { + implementation(projects.domain.tokens.models) + /** AndroidX */ implementation(deps.androidx.fragment.ktx) } \ No newline at end of file diff --git a/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsArguments.kt b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsArguments.kt new file mode 100644 index 0000000000..30c0ecc912 --- /dev/null +++ b/features/tokendetails/api/src/main/kotlin/com/tangem/features/tokendetails/navigation/TokenDetailsArguments.kt @@ -0,0 +1,30 @@ +package com.tangem.features.tokendetails.navigation + +import android.os.Parcelable +import androidx.annotation.DrawableRes +import com.tangem.domain.tokens.model.CryptoCurrency +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TokenDetailsArguments( + val currencyId: CryptoCurrency.ID, + val currencyName: String, + val iconUrl: String?, + val coinType: CoinType, +) : Parcelable { + + @Parcelize + sealed class CoinType : Parcelable { + object Native : CoinType() + + /** + * @param standardName - token standard. Samples: ERC20, BEP20, BEP2, TRC20 and etc. + * @param networkName - token's blockchain name. Ethereum, Tron and etc. + */ + data class Token( + val standardName: String, + val networkName: String, + @DrawableRes val networkIcon: Int, + ) : CoinType() + } +} \ No newline at end of file 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 81dbc9eb69..b0130e64cf 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 @@ -7,6 +7,6 @@ interface TokenDetailsRouter { fun getEntryFragment(): Fragment companion object { - const val SELECTED_CURRENCY_KEY = "selected_currency" + const val TOKEN_DETAILS_ARGS = "token_details_args" } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt index e3b2eca4d0..2fb3b9b125 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/TokenDetailsPreviewData.kt @@ -39,9 +39,9 @@ internal object TokenDetailsPreviewData { name = "Tether (USDT) with long name test", iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/stellar.png", currency = TokenInfoBlockState.Currency.Token( - networkName = "ERC20", + standardName = "ERC20", networkIcon = R.drawable.img_eth_22, - blockchainName = "Ethereum", + networkName = "Ethereum", ), ) @@ -49,9 +49,9 @@ internal object TokenDetailsPreviewData { name = "Tether USDT", iconUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/tether.png", currency = TokenInfoBlockState.Currency.Token( - networkName = "ERC20", + standardName = "ERC20", networkIcon = R.drawable.img_eth_22, - blockchainName = "Ethereum", + networkName = "Ethereum", ), ) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenInfoBlockState.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenInfoBlockState.kt index f6bec38a44..10bdfe2821 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenInfoBlockState.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/TokenInfoBlockState.kt @@ -4,19 +4,20 @@ import androidx.annotation.DrawableRes internal data class TokenInfoBlockState( val name: String, - val iconUrl: String, + val iconUrl: String?, val currency: Currency, ) { sealed class Currency { object Native : Currency() /** - * @param networkName - token standard. Samples: ERC20, BEP20, BEP2, TRC20 and etc. - * @param blockchainName - token's blockchain name. Ethereum, Tron and etc. + * @param standardName - token standard. Samples: ERC20, BEP20, BEP2, TRC20 and etc. + * @param networkName - token's network name. + * @param networkIcon - token's network icon. */ data class Token( + val standardName: String, val networkName: String, - val blockchainName: String, @DrawableRes val networkIcon: Int, ) : Currency() } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt index ff5e00b4f4..3cd81399df 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSkeletonStateConverter.kt @@ -3,15 +3,13 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory import com.tangem.core.ui.components.marketprice.MarketPriceBlockState import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.extensions.TextReference -import com.tangem.core.ui.extensions.networkIconResId import com.tangem.core.ui.res.TangemTheme -import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.feature.tokendetails.presentation.tokendetails.state.* import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsActionButton import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsPullToRefreshConfig -import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsSkeletonStateConverter.SkeletonModel import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents import com.tangem.features.tokendetails.impl.R +import com.tangem.features.tokendetails.navigation.TokenDetailsArguments import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -19,30 +17,28 @@ import kotlinx.coroutines.flow.MutableStateFlow internal class TokenDetailsSkeletonStateConverter( private val clickIntents: TokenDetailsClickIntents, -) : Converter { +) : Converter { - override fun convert(value: SkeletonModel): TokenDetailsState { + override fun convert(value: TokenDetailsArguments): TokenDetailsState { return TokenDetailsState( topAppBarConfig = TokenDetailsTopAppBarConfig( onBackClick = clickIntents::onBackClick, tokenDetailsAppBarMenuConfig = createMenu(), ), tokenInfoBlockState = TokenInfoBlockState( - name = value.cryptoCurrency.name, - iconUrl = requireNotNull(value.cryptoCurrency.iconUrl), - currency = when (val currency = value.cryptoCurrency) { - is CryptoCurrency.Coin -> TokenInfoBlockState.Currency.Native - is CryptoCurrency.Token -> TokenInfoBlockState.Currency.Token( - networkName = currency.network.standardType.name, - blockchainName = currency.network.name, - networkIcon = currency.networkIconResId, + name = value.currencyName, + iconUrl = value.iconUrl, + currency = when (val coinType = value.coinType) { + TokenDetailsArguments.CoinType.Native -> TokenInfoBlockState.Currency.Native + is TokenDetailsArguments.CoinType.Token -> TokenInfoBlockState.Currency.Token( + standardName = coinType.networkName, + networkName = coinType.networkName, + networkIcon = coinType.networkIcon, ) }, ), - tokenBalanceBlockState = TokenDetailsBalanceBlockState.Loading( - actionButtons = createButtons(), - ), - marketPriceBlockState = MarketPriceBlockState.Loading(value.cryptoCurrency.name), + tokenBalanceBlockState = TokenDetailsBalanceBlockState.Loading(actionButtons = createButtons()), + marketPriceBlockState = MarketPriceBlockState.Loading(value.currencyName), notifications = persistentListOf(), pendingTxs = persistentListOf(), txHistoryState = TxHistoryState.Content( @@ -80,6 +76,4 @@ internal class TokenDetailsSkeletonStateConverter( isRefreshing = false, onRefresh = clickIntents::onRefreshSwipe, ) - - data class SkeletonModel(val cryptoCurrency: CryptoCurrency) } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt index ea24b9d9f5..606c36974f 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt @@ -23,6 +23,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.component import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadedTxHistoryConverter import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents +import com.tangem.features.tokendetails.navigation.TokenDetailsArguments import kotlinx.coroutines.flow.Flow internal class TokenDetailsStateFactory( @@ -30,8 +31,8 @@ internal class TokenDetailsStateFactory( private val appCurrencyProvider: Provider, private val isBalanceHiddenProvider: Provider, private val clickIntents: TokenDetailsClickIntents, - symbol: String, - decimals: Int, + currencySymbolProvider: Provider, + currencyDecimalsProvider: Provider, ) { private val skeletonStateConverter by lazy { @@ -47,8 +48,8 @@ internal class TokenDetailsStateFactory( currentStateProvider = currentStateProvider, appCurrencyProvider = appCurrencyProvider, isBalanceHiddenProvider = isBalanceHiddenProvider, - symbol = symbol, - decimals = decimals, + symbol = currencySymbolProvider(), + decimals = currencyDecimalsProvider(), ) } @@ -67,8 +68,8 @@ internal class TokenDetailsStateFactory( TokenDetailsLoadedTxHistoryConverter( currentStateProvider = currentStateProvider, clickIntents = clickIntents, - symbol = symbol, - decimals = decimals, + symbol = currencySymbolProvider(), + decimals = currencyDecimalsProvider(), ) } @@ -78,10 +79,8 @@ internal class TokenDetailsStateFactory( ) } - fun getInitialState(cryptoCurrency: CryptoCurrency): TokenDetailsState { - return skeletonStateConverter.convert( - TokenDetailsSkeletonStateConverter.SkeletonModel(cryptoCurrency = cryptoCurrency), - ) + fun getInitialState(screenArgument: TokenDetailsArguments): TokenDetailsState { + return skeletonStateConverter.convert(value = screenArgument) } fun getCurrencyLoadedBalanceState( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenInfoBlock.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenInfoBlock.kt index 96ac8f6bf3..a4dd5c2b9e 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenInfoBlock.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/ui/components/TokenInfoBlock.kt @@ -95,8 +95,8 @@ private fun extractNetwork(tokenCurrency: TokenInfoBlockState.Currency.Token): E val splitString = stringResource( id = R.string.token_details_token_type_subtitle, formatArgs = arrayOf( + tokenCurrency.standardName, tokenCurrency.networkName, - tokenCurrency.blockchainName, ), ).split(SEPARATOR) 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 f36c50c61a..e848594478 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 @@ -27,6 +27,7 @@ import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsStateFactory +import com.tangem.features.tokendetails.navigation.TokenDetailsArguments import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder @@ -55,13 +56,14 @@ internal class TokenDetailsViewModel @Inject constructor( private val isBalanceHiddenUseCase: IsBalanceHiddenUseCase, private val listenToFlipsUseCase: ListenToFlipsUseCase, private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase, + private val getCryptoCurrencyUseCase: GetCryptoCurrencyUseCase, private val walletManagersFacade: WalletManagersFacade, private val reduxStateHolder: ReduxStateHolder, savedStateHandle: SavedStateHandle, ) : ViewModel(), DefaultLifecycleObserver, TokenDetailsClickIntents { - private val cryptoCurrency: CryptoCurrency = savedStateHandle[TokenDetailsRouter.SELECTED_CURRENCY_KEY] - ?: error("no expected parameter CryptoCurrency found") + private val screenArgument: TokenDetailsArguments = savedStateHandle[TokenDetailsRouter.TOKEN_DETAILS_ARGS] + ?: error("This screen can't open without TokenDetailsArgument") var router by Delegates.notNull() @@ -69,6 +71,7 @@ internal class TokenDetailsViewModel @Inject constructor( private val refreshStateJobHolder = JobHolder() private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null private var wallet by Delegates.notNull() + private var cryptoCurrency by Delegates.notNull() private val selectedAppCurrencyFlow: StateFlow = createSelectedAppCurrencyFlow() private var isBalanceHidden = true @@ -78,25 +81,34 @@ internal class TokenDetailsViewModel @Inject constructor( appCurrencyProvider = Provider(selectedAppCurrencyFlow::value), isBalanceHiddenProvider = Provider { isBalanceHidden }, clickIntents = this, - symbol = cryptoCurrency.symbol, - decimals = cryptoCurrency.decimals, + currencySymbolProvider = Provider { cryptoCurrency.symbol }, + currencyDecimalsProvider = Provider { cryptoCurrency.decimals }, ) - var uiState: TokenDetailsState by mutableStateOf(stateFactory.getInitialState(cryptoCurrency)) + var uiState: TokenDetailsState by mutableStateOf(stateFactory.getInitialState(screenArgument)) private set override fun onCreate(owner: LifecycleOwner) { - getWallet() - updateContent(selectedWallet = wallet) + initRequiredFields() handleBalanceHiding(owner) } - private fun getWallet() { - return getSelectedWalletUseCase() + private fun initRequiredFields() { + getSelectedWalletUseCase() .fold( ifLeft = { error("Can not get selected wallet $it") }, ifRight = { wallet = it }, ) + viewModelScope.launch { + getCryptoCurrencyUseCase.invoke(userWalletId = wallet.walletId, id = screenArgument.currencyId) + .fold( + ifLeft = { error("Can not get cryptoCurrency with given ID: screenArgument.currencyId. $it") }, + ifRight = { + cryptoCurrency = it + updateContent(selectedWallet = wallet) + }, + ) + } } private fun updateContent(selectedWallet: UserWallet) { 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 c4bfb43ead..2e5be36d4a 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 @@ -19,6 +19,7 @@ import androidx.navigation.navArgument import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.core.navigation.ReduxNavController +import com.tangem.core.ui.extensions.networkIconResId import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.wallet.presentation.WalletFragment @@ -26,6 +27,7 @@ import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensScree 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.TokenDetailsArguments import com.tangem.features.tokendetails.navigation.TokenDetailsRouter import kotlin.properties.Delegates @@ -111,8 +113,21 @@ internal class DefaultWalletRouter(private val reduxNavController: ReduxNavContr reduxNavController.navigate( action = NavigationAction.NavigateTo( screen = AppScreen.WalletDetails, - // TODO: [REDACTED_JIRA] - bundle = bundleOf(TokenDetailsRouter.SELECTED_CURRENCY_KEY to currency), + bundle = bundleOf( + TokenDetailsRouter.TOKEN_DETAILS_ARGS to TokenDetailsArguments( + currencyId = currency.id, + currencyName = currency.name, + iconUrl = currency.iconUrl, + coinType = when (currency) { + is CryptoCurrency.Coin -> TokenDetailsArguments.CoinType.Native + is CryptoCurrency.Token -> TokenDetailsArguments.CoinType.Token( + standardName = currency.network.standardType.name, + networkName = currency.network.name, + networkIcon = currency.networkIconResId, + ) + }, + ), + ), ), ) }