Updated on 2026-08-14
This commit is contained in:
parent
40b616868d
commit
2a0e8f78a6
22 changed files with 236 additions and 54 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<Currency, CryptoCurrency> {
|
||||
|
||||
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,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 -> {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -5,4 +5,8 @@ import androidx.fragment.app.Fragment
|
|||
interface TokenDetailsRouter {
|
||||
|
||||
fun getEntryFragment(): Fragment
|
||||
|
||||
companion object {
|
||||
const val SELECTED_CURRENCY_KEY = "selected_currency"
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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<InnerTokenDetailsRouter>()
|
||||
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -61,4 +61,5 @@ dependencies {
|
|||
|
||||
/** Feature Apis */
|
||||
implementation(projects.features.wallet.api)
|
||||
implementation(projects.features.tokendetails.api)
|
||||
}
|
||||
|
|
@ -100,6 +100,7 @@ internal object WalletPreviewData {
|
|||
type = PriceChangeConfig.Type.UP,
|
||||
),
|
||||
),
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +119,7 @@ internal object WalletPreviewData {
|
|||
type = PriceChangeConfig.Type.UP,
|
||||
),
|
||||
),
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ internal sealed interface TokenItemState {
|
|||
val amount: String,
|
||||
val hasPending: Boolean,
|
||||
val tokenOptions: TokenOptionsState,
|
||||
val onClick: () -> Unit,
|
||||
) : TokenItemState
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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<WalletViewModel>().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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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<AppCurrency>,
|
||||
private val isWalletContentHidden: Boolean,
|
||||
private val clickIntents: WalletClickIntents,
|
||||
) : Converter<CryptoCurrencyStatus, TokenItemState> {
|
||||
|
||||
private val CryptoCurrencyStatus.networkIconResId: Int?
|
||||
|
|
@ -61,6 +63,7 @@ internal class CryptoCurrencyStatusToTokenItemConverter(
|
|||
priceChange = getPriceChangeConfig(),
|
||||
)
|
||||
},
|
||||
onClick = { clickIntents.onTokenClick(currency) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ internal class TokenListToContentItemsConverter(
|
|||
private val tokenStatusConverter = CryptoCurrencyStatusToTokenItemConverter(
|
||||
isWalletContentHidden = isWalletContentHidden,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
override fun convert(value: TokenList): WalletTokensListState {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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<AppCurrency> {
|
||||
return getSelectedAppCurrencyUseCase()
|
||||
.map { maybeAppCurrency ->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue