Updated on 2026-08-14
This commit is contained in:
commit
1702c4f9b4
27 changed files with 502 additions and 144 deletions
|
|
@ -66,4 +66,11 @@ internal object NFTDomainModule {
|
|||
GetNFTNetworkStatusUseCase(
|
||||
networksRepository = networksRepository,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesGetNFTExploreUrlUseCase(nftRepository: NFTRepository): GetNFTExploreUrlUseCase =
|
||||
GetNFTExploreUrlUseCase(
|
||||
nftRepository = nftRepository,
|
||||
)
|
||||
}
|
||||
|
|
@ -534,6 +534,7 @@
|
|||
<string name="nft_wallet_receive_nft">Tap here to receive first NFT</string>
|
||||
<string name="nft_wallet_title">NFT collections</string>
|
||||
<string name="nft_wallet_unable_to_load">Unable to load the data</string>
|
||||
<string name="nft_no_collection">No collection</string>
|
||||
<string name="onboarding_access_code_feature_1_description">Set up a single access code to protect all your devices.</string>
|
||||
<string name="onboarding_access_code_feature_1_title">Protect</string>
|
||||
<string name="onboarding_access_code_feature_2_description">Set an individual access code for each card or ring later.</string>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.datasource.local.nft.converter.NFTSdkAssetIdentifierConverter
|
|||
import com.tangem.datasource.local.nft.converter.NFTSdkCollectionConverter
|
||||
import com.tangem.datasource.local.nft.converter.NFTSdkCollectionIdentifierConverter
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.nft.models.NFTAsset
|
||||
import com.tangem.domain.nft.models.NFTCollection
|
||||
import com.tangem.domain.nft.models.NFTCollections
|
||||
import com.tangem.domain.nft.models.NFTSalePrice
|
||||
|
|
@ -117,7 +118,7 @@ internal class DefaultNFTRepository @Inject constructor(
|
|||
assets.forEach {
|
||||
val assetId = NFTSdkAssetIdentifierConverter.convert(it.identifier)
|
||||
val price = getNFTRuntimeStore(userWalletId, network).getSalePriceSync(assetId)
|
||||
if (price is NFTSalePrice.Error) {
|
||||
if (price is NFTSalePrice.Empty || price is NFTSalePrice.Error) {
|
||||
refreshSalePrice(userWalletId, network, sdkCollectionId, it.identifier)
|
||||
}
|
||||
}
|
||||
|
|
@ -155,6 +156,12 @@ internal class DefaultNFTRepository @Inject constructor(
|
|||
|
||||
override suspend fun isNFTSupported(network: Network): Boolean = network.canHandleNFTs()
|
||||
|
||||
override suspend fun getNFTExploreUrl(network: Network, assetIdentifier: NFTAsset.Identifier): String? =
|
||||
walletManagersFacade.getNFTExploreUrl(
|
||||
network = network,
|
||||
assetIdentifier = NFTSdkAssetIdentifierConverter.convertBack(assetIdentifier),
|
||||
)
|
||||
|
||||
private suspend fun refreshSalePrice(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
|
|
|
|||
|
|
@ -709,6 +709,11 @@ class DefaultWalletManagersFacade(
|
|||
return walletManager.getSalePrice(collectionIdentifier, assetIdentifier)
|
||||
}
|
||||
|
||||
override suspend fun getNFTExploreUrl(network: Network, assetIdentifier: NFTAsset.Identifier): String? {
|
||||
val blockchain = Blockchain.fromId(network.id.value)
|
||||
return blockchain.getNFTExploreUrl(assetIdentifier)
|
||||
}
|
||||
|
||||
override suspend fun isAccountInitialized(userWalletId: UserWalletId, network: Network): Boolean {
|
||||
val walletManager = getOrCreateWalletManager(userWalletId = userWalletId, network = network)
|
||||
val initializableAccountWalletManger = walletManager as? InitializableAccount ?: return true
|
||||
|
|
|
|||
|
|
@ -273,6 +273,8 @@ interface WalletManagersFacade {
|
|||
assetIdentifier: NFTAsset.Identifier,
|
||||
): NFTAsset.SalePrice?
|
||||
|
||||
suspend fun getNFTExploreUrl(network: Network, assetIdentifier: NFTAsset.Identifier): String?
|
||||
|
||||
/**
|
||||
* If wallet manager implements [InitializableAccount] then returns [InitializableAccount.isAccountInitialized]
|
||||
* value. Otherwise always return true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.domain.nft
|
||||
|
||||
import arrow.core.raise.catch
|
||||
import com.tangem.domain.nft.models.NFTAsset
|
||||
import com.tangem.domain.nft.repository.NFTRepository
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
|
||||
class GetNFTExploreUrlUseCase(
|
||||
private val nftRepository: NFTRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(network: Network, assetIdentifier: NFTAsset.Identifier): String? = catch(
|
||||
block = {
|
||||
nftRepository.getNFTExploreUrl(
|
||||
network = network,
|
||||
assetIdentifier = assetIdentifier,
|
||||
)
|
||||
},
|
||||
catch = { null },
|
||||
)
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.domain.nft.repository
|
||||
|
||||
import com.tangem.domain.nft.models.NFTAsset
|
||||
import com.tangem.domain.nft.models.NFTCollection
|
||||
import com.tangem.domain.nft.models.NFTCollections
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
|
|
@ -14,4 +15,6 @@ interface NFTRepository {
|
|||
suspend fun refreshAssets(userWalletId: UserWalletId, network: Network, collectionId: NFTCollection.Identifier)
|
||||
|
||||
suspend fun isNFTSupported(network: Network): Boolean
|
||||
|
||||
suspend fun getNFTExploreUrl(network: Network, assetIdentifier: NFTAsset.Identifier): String?
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ dependencies {
|
|||
implementation(projects.core.datasource)
|
||||
|
||||
/** Domain modules */
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.nft)
|
||||
implementation(projects.domain.nft.models)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
|
||||
internal data class NFTCollectionUM(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val name: String?,
|
||||
@DrawableRes val networkIconId: Int,
|
||||
val logoUrl: String?,
|
||||
val description: TextReference,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ internal class UpdateDataStateTransformer(
|
|||
NFTCollectionUM(
|
||||
id = it.id.toString(),
|
||||
networkIconId = getActiveIconRes(it.network.id.value),
|
||||
name = it.name.orEmpty(),
|
||||
name = it.name,
|
||||
description = TextReference.PluralRes(
|
||||
R.plurals.nft_collections_count,
|
||||
it.count,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionAssetsListUM
|
||||
|
|
@ -89,7 +90,7 @@ private fun RowScope.Text(state: NFTCollectionUM) {
|
|||
) {
|
||||
Text(
|
||||
modifier = Modifier,
|
||||
text = state.name,
|
||||
text = state.name.takeUnless { it.isNullOrEmpty() } ?: stringResourceSafe(R.string.nft_no_collection),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
maxLines = 1,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import com.tangem.features.nft.collections.NFTCollectionsComponent
|
|||
import com.tangem.features.nft.common.ui.NFTContent
|
||||
import com.tangem.features.nft.component.NFTComponent
|
||||
import com.tangem.features.nft.details.NFTDetailsComponent
|
||||
import com.tangem.features.nft.details.info.NFTDetailsInfoComponent
|
||||
import com.tangem.features.nft.receive.NFTReceiveComponent
|
||||
import com.tangem.features.nft.traits.NFTAssetTraitsComponent
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -29,6 +30,7 @@ import kotlinx.coroutines.launch
|
|||
internal class DefaultNFTComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: NFTComponent.Params,
|
||||
private val nftDetailsInfoComponentFactory: NFTDetailsInfoComponent.Factory,
|
||||
) : NFTComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val stackNavigation = StackNavigation<NFTRoute>()
|
||||
|
|
@ -142,6 +144,7 @@ internal class DefaultNFTComponent @AssistedInject constructor(
|
|||
)
|
||||
},
|
||||
),
|
||||
nftDetailsInfoComponentFactory = nftDetailsInfoComponentFactory,
|
||||
)
|
||||
|
||||
private fun getAssetTraitsComponent(
|
||||
|
|
|
|||
|
|
@ -4,11 +4,19 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.nft.models.NFTAsset
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsBottomSheetConfig
|
||||
import com.tangem.features.nft.details.info.NFTDetailsInfoComponent
|
||||
import com.tangem.features.nft.details.model.NFTDetailsModel
|
||||
import com.tangem.features.nft.details.ui.NFTDetails
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -17,15 +25,40 @@ import dagger.assisted.AssistedInject
|
|||
internal class NFTDetailsComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted private val params: Params,
|
||||
private val nftDetailsInfoComponentFactory: NFTDetailsInfoComponent.Factory,
|
||||
) : ComposableContentComponent, AppComponentContext by context {
|
||||
|
||||
private val model: NFTDetailsModel = getOrCreateModel(params)
|
||||
|
||||
private val bottomSheetSlot = childSlot(
|
||||
source = model.bottomSheetNavigation,
|
||||
serializer = null,
|
||||
handleBackButton = false,
|
||||
childFactory = ::bottomSheetChild,
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
|
||||
NFTDetails(state, modifier)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
private fun bottomSheetChild(
|
||||
config: NFTDetailsBottomSheetConfig,
|
||||
componentContext: ComponentContext,
|
||||
): ComposableBottomSheetComponent = when (config) {
|
||||
is NFTDetailsBottomSheetConfig.Info -> nftDetailsInfoComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = NFTDetailsInfoComponent.Params(
|
||||
text = config.text,
|
||||
onDismiss = {
|
||||
model.bottomSheetNavigation.dismiss()
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
data class Params(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package com.tangem.features.nft.details.entity
|
|||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class NFTAssetUM(
|
||||
val name: String,
|
||||
|
|
@ -37,7 +39,13 @@ data class NFTAssetUM(
|
|||
sealed class SalePrice {
|
||||
data object Loading : SalePrice()
|
||||
data object Empty : SalePrice()
|
||||
data class Content(val value: String, val fiatValue: String) : SalePrice()
|
||||
data class Content(
|
||||
val value: BigDecimal,
|
||||
val symbol: String,
|
||||
val decimals: Int,
|
||||
val rate: BigDecimal?,
|
||||
val appCurrency: AppCurrency,
|
||||
) : SalePrice()
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.features.nft.details.entity
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal sealed interface NFTDetailsBottomSheetConfig {
|
||||
@Serializable
|
||||
data class Info(
|
||||
val text: TextReference,
|
||||
) : NFTDetailsBottomSheetConfig
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
package com.tangem.features.nft.details.entity
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
|
||||
internal data class NFTDetailsUM(
|
||||
val nftAsset: NFTAssetUM,
|
||||
val onBackClick: () -> Unit,
|
||||
|
|
@ -9,5 +7,4 @@ internal data class NFTDetailsUM(
|
|||
val onSeeAllTraitsClick: () -> Unit,
|
||||
val onExploreClick: () -> Unit,
|
||||
val onSendClick: () -> Unit,
|
||||
val bottomSheetConfig: TangemBottomSheetConfig?,
|
||||
)
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package com.tangem.features.nft.details.entity
|
||||
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class NFTInfoBottomSheetConfig(
|
||||
val title: TextReference,
|
||||
val text: TextReference,
|
||||
) : TangemBottomSheetConfigContent
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
package com.tangem.features.nft.details.entity.factory
|
||||
|
||||
import com.tangem.core.ui.components.atoms.text.TextEllipsis
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.nft.models.NFTAsset
|
||||
import com.tangem.domain.nft.models.NFTSalePrice
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsUM
|
||||
import com.tangem.features.nft.impl.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class NFTDetailsUMFactory(
|
||||
private val onBackClick: () -> Unit,
|
||||
private val onReadMoreClick: () -> Unit,
|
||||
private val onSeeAllTraitsClick: () -> Unit,
|
||||
private val onExploreClick: () -> Unit,
|
||||
private val onSendClick: () -> Unit,
|
||||
) {
|
||||
|
||||
fun getInitialState(nftAsset: NFTAsset): NFTDetailsUM = NFTDetailsUM(
|
||||
nftAsset = nftAsset.transform(),
|
||||
onBackClick = onBackClick,
|
||||
onReadMoreClick = onReadMoreClick,
|
||||
onSeeAllTraitsClick = onSeeAllTraitsClick,
|
||||
onExploreClick = onExploreClick,
|
||||
onSendClick = onSendClick,
|
||||
)
|
||||
|
||||
private fun NFTAsset.transform(): NFTAssetUM = NFTAssetUM(
|
||||
name = name.orEmpty(),
|
||||
media = media?.let {
|
||||
NFTAssetUM.Media.Content(
|
||||
mimetype = it.mimetype,
|
||||
url = it.url,
|
||||
)
|
||||
} ?: NFTAssetUM.Media.Empty,
|
||||
topInfo = when {
|
||||
!hasSalePrice() && description.isNullOrEmpty() && rarity == null -> {
|
||||
NFTAssetUM.TopInfo.Empty
|
||||
}
|
||||
else -> {
|
||||
val hasSalePrice = hasSalePrice()
|
||||
val hasDescription = !description.isNullOrEmpty()
|
||||
val rarity = rarity
|
||||
NFTAssetUM.TopInfo.Content(
|
||||
title = if (hasSalePrice) {
|
||||
resourceReference(R.string.nft_details_last_sale_price)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
salePrice = NFTAssetUM.SalePrice.Empty,
|
||||
description = description,
|
||||
rarity = if (rarity != null) {
|
||||
NFTAssetUM.Rarity.Content(
|
||||
rank = rarity.rank,
|
||||
label = rarity.label,
|
||||
showDivider = hasSalePrice || hasDescription,
|
||||
)
|
||||
} else {
|
||||
NFTAssetUM.Rarity.Empty
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
traits = traits.take(MAX_TRAITS_COUNT).map {
|
||||
NFTAssetUM.BlockItem(
|
||||
title = stringReference(it.name),
|
||||
value = it.value,
|
||||
)
|
||||
}.toImmutableList(),
|
||||
baseInfoItems = buildBaseInfoItems(),
|
||||
)
|
||||
|
||||
private fun NFTAsset.hasSalePrice() = salePrice !is NFTSalePrice.Empty && salePrice !is NFTSalePrice.Error
|
||||
|
||||
private fun NFTAsset.buildBaseInfoItems() = when (val id = id) {
|
||||
is NFTAsset.Identifier.EVM -> persistentListOf(
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_token_standard),
|
||||
value = contractType,
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_contract_address),
|
||||
value = id.tokenAddress,
|
||||
valueTextEllipsis = TextEllipsis.Middle,
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_token_id),
|
||||
value = id.tokenId,
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_chain),
|
||||
value = network.name,
|
||||
),
|
||||
)
|
||||
is NFTAsset.Identifier.TON -> persistentListOf(
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_token_address),
|
||||
value = id.tokenAddress,
|
||||
valueTextEllipsis = TextEllipsis.Middle,
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_chain),
|
||||
value = network.name,
|
||||
),
|
||||
)
|
||||
is NFTAsset.Identifier.Solana -> persistentListOf(
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_token_address),
|
||||
value = id.tokenAddress,
|
||||
valueTextEllipsis = TextEllipsis.Middle,
|
||||
),
|
||||
NFTAssetUM.BlockItem(
|
||||
title = resourceReference(R.string.nft_details_chain),
|
||||
value = network.name,
|
||||
),
|
||||
)
|
||||
is NFTAsset.Identifier.Unknown -> persistentListOf()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAX_TRAITS_COUNT = 6
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.tangem.features.nft.details.info
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.nft.details.info.ui.NFTInfoBottomSheet
|
||||
import com.tangem.features.nft.details.info.ui.NFTInfoBottomSheetContent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultNFTDetailsInfoComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted private val params: NFTDetailsInfoComponent.Params,
|
||||
) : NFTDetailsInfoComponent, AppComponentContext by context {
|
||||
|
||||
override fun dismiss() {
|
||||
params.onDismiss()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val bottomSheetConfig = remember(key1 = this) {
|
||||
TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = ::dismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
)
|
||||
}
|
||||
NFTInfoBottomSheet(
|
||||
config = bottomSheetConfig,
|
||||
content = {
|
||||
NFTInfoBottomSheetContent(
|
||||
text = params.text,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : NFTDetailsInfoComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: NFTDetailsInfoComponent.Params,
|
||||
): DefaultNFTDetailsInfoComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.features.nft.details.info
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal interface NFTDetailsInfoComponent : ComposableBottomSheetComponent {
|
||||
|
||||
data class Params(
|
||||
val text: TextReference,
|
||||
val onDismiss: () -> Unit,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, NFTDetailsInfoComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package com.tangem.features.nft.details.info.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.impl.R
|
||||
|
||||
@Composable
|
||||
internal fun NFTInfoBottomSheet(config: TangemBottomSheetConfig, content: @Composable () -> Unit) {
|
||||
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = config,
|
||||
titleText = resourceReference(R.string.nft_about_title),
|
||||
content = { content() },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun NFTInfoBottomSheetContent(text: TextReference, modifier: Modifier = Modifier) {
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier = modifier.verticalScroll(scrollState),
|
||||
) {
|
||||
Text(
|
||||
text = text.resolveReference(),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
style = TangemTheme.typography.body2,
|
||||
modifier = Modifier.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_NFTInfoBottomSheetContent() {
|
||||
TangemThemePreview {
|
||||
NFTInfoBottomSheetContent(
|
||||
text = stringReference(
|
||||
"""
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce varius neque vel ligula
|
||||
tincidunt, nec faucibus nulla ultricies. Maecenas euismod arcu in nunc volutpat,
|
||||
at bibendum eros lacinia. Proin hendrerit massa non velit congue,
|
||||
in volutpat nisi consequat. Sed vitae justo nec orci tincidunt malesuada.
|
||||
Nullam feugiat purus vel lectus efficitur, vel fringilla urna volutpat.
|
||||
Donec sagittis enim in metus lacinia, vel tempor nunc bibendum.
|
||||
""".trimIndent(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.features.nft.details.model
|
||||
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
|
|
@ -7,13 +9,18 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.domain.nft.analytics.NFTAnalyticsEvent
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.nft.GetNFTExploreUrlUseCase
|
||||
import com.tangem.features.nft.details.NFTDetailsComponent
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsBottomSheetConfig
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsUM
|
||||
import com.tangem.features.nft.details.entity.factory.NFTDetailsUMFactory
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
|
|
@ -21,45 +28,57 @@ internal class NFTDetailsModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val router: Router,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val getNFTExploreUrlUseCase: GetNFTExploreUrlUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private val params: NFTDetailsComponent.Params = paramsContainer.require()
|
||||
|
||||
val state: StateFlow<NFTDetailsUM> get() = _state
|
||||
|
||||
private val _state = MutableStateFlow(
|
||||
value = NFTDetailsUM(
|
||||
nftAsset = NFTAssetUM(
|
||||
name = "",
|
||||
media = NFTAssetUM.Media.Empty,
|
||||
topInfo = NFTAssetUM.TopInfo.Empty,
|
||||
traits = persistentListOf(),
|
||||
baseInfoItems = persistentListOf(),
|
||||
),
|
||||
onBackClick = params.onBackClick,
|
||||
onReadMoreClick = ::onReadMoreClick,
|
||||
onSeeAllTraitsClick = {
|
||||
analyticsEventHandler.send(NFTAnalyticsEvent.Details.ButtonSeeAll)
|
||||
params.onAllTraitsClick()
|
||||
},
|
||||
onExploreClick = ::onExploreClick,
|
||||
onSendClick = ::onSendClick,
|
||||
bottomSheetConfig = null,
|
||||
),
|
||||
private val stateFactory: NFTDetailsUMFactory = NFTDetailsUMFactory(
|
||||
onBackClick = { params.onBackClick() },
|
||||
onReadMoreClick = ::onReadMoreClick,
|
||||
onSeeAllTraitsClick = { params.onAllTraitsClick() },
|
||||
onExploreClick = ::onExploreClick,
|
||||
onSendClick = ::onSendClick,
|
||||
)
|
||||
|
||||
private val _state = MutableStateFlow(
|
||||
value = stateFactory.getInitialState(params.nftAsset),
|
||||
)
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<NFTDetailsBottomSheetConfig> = SlotNavigation()
|
||||
init {
|
||||
analyticsEventHandler.send(NFTAnalyticsEvent.Details.ScreenOpened(params.nftAsset.network.name))
|
||||
}
|
||||
|
||||
private fun onReadMoreClick() {
|
||||
analyticsEventHandler.send(NFTAnalyticsEvent.Details.ButtonReadMore)
|
||||
when (val topInfo = _state.value.nftAsset.topInfo) {
|
||||
is NFTAssetUM.TopInfo.Empty -> Unit
|
||||
is NFTAssetUM.TopInfo.Content -> {
|
||||
bottomSheetNavigation.activate(
|
||||
NFTDetailsBottomSheetConfig.Info(
|
||||
text = stringReference(topInfo.description.orEmpty()),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onExploreClick() {
|
||||
analyticsEventHandler.send(NFTAnalyticsEvent.Details.ButtonExplore)
|
||||
modelScope.launch {
|
||||
val url = getNFTExploreUrlUseCase.invoke(
|
||||
network = params.nftAsset.network,
|
||||
assetIdentifier = params.nftAsset.id,
|
||||
)
|
||||
if (url != null) {
|
||||
urlOpener.openUrl(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSendClick() {
|
||||
|
|
|
|||
|
|
@ -11,12 +11,9 @@ import androidx.compose.ui.Modifier
|
|||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.appbar.TangemTopAppBar
|
||||
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.nft.details.entity.NFTDetailsUM
|
||||
import com.tangem.features.nft.details.entity.NFTInfoBottomSheetConfig
|
||||
import com.tangem.features.nft.details.ui.bottomsheet.NFTInfoBottomSheet
|
||||
import com.tangem.features.nft.impl.R
|
||||
|
||||
@Composable
|
||||
|
|
@ -45,7 +42,6 @@ internal fun NFTDetails(state: NFTDetailsUM, modifier: Modifier = Modifier) {
|
|||
modifier = Modifier
|
||||
.padding(innerPadding),
|
||||
)
|
||||
ShowBottomSheet(state.bottomSheetConfig)
|
||||
},
|
||||
floatingActionButtonPosition = FabPosition.Center,
|
||||
floatingActionButton = {
|
||||
|
|
@ -58,12 +54,4 @@ internal fun NFTDetails(state: NFTDetailsUM, modifier: Modifier = Modifier) {
|
|||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShowBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
|
||||
if (bottomSheetConfig == null) return
|
||||
when (bottomSheetConfig.content) {
|
||||
is NFTInfoBottomSheetConfig -> NFTInfoBottomSheet(bottomSheetConfig)
|
||||
}
|
||||
}
|
||||
|
|
@ -16,9 +16,11 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.impl.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Composable
|
||||
internal fun NFTDetailsAsset(
|
||||
|
|
@ -120,7 +122,13 @@ private class NFTAssetProvider : CollectionPreviewParameterProvider<NFTAssetUM>(
|
|||
),
|
||||
topInfo = NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(value = "0,012 ETH", fiatValue = "32.34$"),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
),
|
||||
description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3),
|
||||
rarity = NFTAssetUM.Rarity.Content(
|
||||
rank = "Top 1% rarity",
|
||||
|
|
|
|||
|
|
@ -3,24 +3,34 @@ package com.tangem.features.nft.details.ui
|
|||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.amountScreen.utils.getFiatString
|
||||
import com.tangem.core.ui.components.TextShimmer
|
||||
import com.tangem.core.ui.components.atoms.text.EllipsisText
|
||||
import com.tangem.core.ui.components.atoms.text.ReadMoreText
|
||||
import com.tangem.core.ui.components.block.information.InformationBlock
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.features.nft.details.entity.NFTAssetUM
|
||||
import com.tangem.features.nft.impl.R
|
||||
import java.math.BigDecimal
|
||||
|
||||
private const val READ_MORE_MAX_LINES = 3
|
||||
|
||||
@Composable
|
||||
internal fun NFTDetailsInfoGroup(
|
||||
|
|
@ -41,7 +51,10 @@ internal fun NFTDetailsInfoGroup(
|
|||
contentHorizontalPadding = 0.dp,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
bottom = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
) {
|
||||
SalePrice(state.salePrice)
|
||||
Description(state.description, onReadMoreClick)
|
||||
|
|
@ -68,7 +81,6 @@ private fun SalePrice(state: NFTAssetUM.SalePrice, modifier: Modifier = Modifier
|
|||
.padding(
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
end = TangemTheme.dimens.spacing12,
|
||||
bottom = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
) {
|
||||
TextShimmer(
|
||||
|
|
@ -92,19 +104,23 @@ private fun SalePrice(state: NFTAssetUM.SalePrice, modifier: Modifier = Modifier
|
|||
.padding(
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
end = TangemTheme.dimens.spacing12,
|
||||
bottom = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
verticalArrangement = Arrangement.SpaceAround,
|
||||
) {
|
||||
Text(
|
||||
text = state.value,
|
||||
text = state.value.format {
|
||||
crypto(
|
||||
symbol = state.symbol,
|
||||
decimals = state.decimals,
|
||||
)
|
||||
},
|
||||
style = TangemTheme.typography.head,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing4),
|
||||
text = state.fiatValue,
|
||||
text = getFiatString(state.value, state.rate, state.appCurrency),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
|
|
@ -117,18 +133,29 @@ private fun SalePrice(state: NFTAssetUM.SalePrice, modifier: Modifier = Modifier
|
|||
@Composable
|
||||
private fun Description(description: String?, onReadMoreClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
if (!description.isNullOrEmpty()) {
|
||||
// TODO configure right way to display 3 rows and "Read more" label
|
||||
EllipsisText(
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
ReadMoreText(
|
||||
modifier = modifier
|
||||
.clickable { onReadMoreClick() }
|
||||
.clickable(
|
||||
interactionSource = interactionSource,
|
||||
indication = null,
|
||||
onClick = onReadMoreClick,
|
||||
)
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
vertical = TangemTheme.dimens.spacing8,
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
top = TangemTheme.dimens.spacing12,
|
||||
end = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
expanded = false,
|
||||
text = description,
|
||||
style = TangemTheme.typography.body2.copy(
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
),
|
||||
readMoreText = resourceReference(R.string.common_read_more).resolveReference(),
|
||||
readMoreMaxLines = READ_MORE_MAX_LINES,
|
||||
readMoreStyle = TangemTheme.typography.body2.copy(
|
||||
color = TangemTheme.colors.text.accent,
|
||||
).toSpanStyle(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -141,7 +168,9 @@ private fun Rarity(state: NFTAssetUM.Rarity, modifier: Modifier = Modifier) {
|
|||
if (state.showDivider) {
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = TangemTheme.dimens.spacing12,
|
||||
start = TangemTheme.dimens.spacing12,
|
||||
top = TangemTheme.dimens.spacing8,
|
||||
end = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
color = TangemTheme.colors.stroke.primary,
|
||||
)
|
||||
|
|
@ -150,8 +179,9 @@ private fun Rarity(state: NFTAssetUM.Rarity, modifier: Modifier = Modifier) {
|
|||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing6,
|
||||
vertical = TangemTheme.dimens.spacing8,
|
||||
start = TangemTheme.dimens.spacing6,
|
||||
top = TangemTheme.dimens.spacing12,
|
||||
end = TangemTheme.dimens.spacing6,
|
||||
),
|
||||
) {
|
||||
NFTDetailsGroupBlock(
|
||||
|
|
@ -159,7 +189,6 @@ private fun Rarity(state: NFTAssetUM.Rarity, modifier: Modifier = Modifier) {
|
|||
.weight(1f)
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing6,
|
||||
vertical = TangemTheme.dimens.spacing4,
|
||||
),
|
||||
title = resourceReference(R.string.nft_details_rarity_label),
|
||||
value = stringReference(state.label),
|
||||
|
|
@ -169,7 +198,6 @@ private fun Rarity(state: NFTAssetUM.Rarity, modifier: Modifier = Modifier) {
|
|||
.weight(1f)
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing6,
|
||||
vertical = TangemTheme.dimens.spacing4,
|
||||
),
|
||||
title = resourceReference(R.string.nft_details_rarity_rank),
|
||||
value = stringReference(state.rank),
|
||||
|
|
@ -196,7 +224,13 @@ private class NFTAssetInfoProvider : CollectionPreviewParameterProvider<NFTAsset
|
|||
collection = listOf(
|
||||
NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(value = "0,012 ETH", fiatValue = "32.34$"),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
),
|
||||
description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3),
|
||||
rarity = NFTAssetUM.Rarity.Content(
|
||||
rank = "Top 1% rarity",
|
||||
|
|
@ -216,7 +250,13 @@ private class NFTAssetInfoProvider : CollectionPreviewParameterProvider<NFTAsset
|
|||
),
|
||||
NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(value = "0,012 ETH", fiatValue = "32.34$"),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
),
|
||||
description = null,
|
||||
rarity = NFTAssetUM.Rarity.Content(
|
||||
rank = "Top 1% rarity",
|
||||
|
|
@ -226,13 +266,25 @@ private class NFTAssetInfoProvider : CollectionPreviewParameterProvider<NFTAsset
|
|||
),
|
||||
NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(value = "0,012 ETH", fiatValue = "32.34$"),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
),
|
||||
description = "Base edition by Piux. An illustration of Crypto Robot #7804".repeat(3),
|
||||
rarity = NFTAssetUM.Rarity.Empty,
|
||||
),
|
||||
NFTAssetUM.TopInfo.Content(
|
||||
title = resourceReference(R.string.nft_details_last_sale_price),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(value = "0,012 ETH", fiatValue = "32.34$"),
|
||||
salePrice = NFTAssetUM.SalePrice.Content(
|
||||
value = BigDecimal("18.75"),
|
||||
symbol = "ETH",
|
||||
decimals = 18,
|
||||
rate = BigDecimal("1"),
|
||||
appCurrency = AppCurrency.Default,
|
||||
),
|
||||
description = null,
|
||||
rarity = NFTAssetUM.Rarity.Empty,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,73 +0,0 @@
|
|||
package com.tangem.features.nft.details.ui.bottomsheet
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheetTitle
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.nft.details.entity.NFTInfoBottomSheetConfig
|
||||
|
||||
@Composable
|
||||
fun NFTInfoBottomSheet(config: TangemBottomSheetConfig) {
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
TangemBottomSheet<NFTInfoBottomSheetConfig>(
|
||||
config = config,
|
||||
title = { content ->
|
||||
TangemBottomSheetTitle(title = content.title)
|
||||
},
|
||||
) { content ->
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(scrollState),
|
||||
) {
|
||||
Text(
|
||||
text = content.text.resolveReference(),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
style = TangemTheme.typography.body2,
|
||||
modifier = Modifier.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_StakingInfoBottomSheet() {
|
||||
TangemThemePreview {
|
||||
NFTInfoBottomSheet(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = {},
|
||||
content = NFTInfoBottomSheetConfig(
|
||||
title = stringReference("Title"),
|
||||
text = stringReference(
|
||||
"""
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce varius neque vel ligula
|
||||
tincidunt, nec faucibus nulla ultricies. Maecenas euismod arcu in nunc volutpat,
|
||||
at bibendum eros lacinia. Proin hendrerit massa non velit congue,
|
||||
in volutpat nisi consequat. Sed vitae justo nec orci tincidunt malesuada.
|
||||
Nullam feugiat purus vel lectus efficitur, vel fringilla urna volutpat.
|
||||
Donec sagittis enim in metus lacinia, vel tempor nunc bibendum.
|
||||
""".trimIndent(),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,8 @@ import com.tangem.features.nft.collections.model.NFTCollectionsModel
|
|||
import com.tangem.features.nft.common.DefaultNFTComponent
|
||||
import com.tangem.features.nft.component.*
|
||||
import com.tangem.features.nft.details.block.DefaultNFTDetailsBlockComponent
|
||||
import com.tangem.features.nft.details.info.DefaultNFTDetailsInfoComponent
|
||||
import com.tangem.features.nft.details.info.NFTDetailsInfoComponent
|
||||
import com.tangem.features.nft.details.model.NFTDetailsModel
|
||||
import com.tangem.features.nft.receive.model.NFTReceiveModel
|
||||
import com.tangem.features.nft.traits.model.NFTAssetTraitsModel
|
||||
|
|
@ -34,6 +36,12 @@ internal object NFTFeatureModule {
|
|||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface NFTFeatureModuleBinds {
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindNFTDetailsInfoComponentFactory(
|
||||
factory: DefaultNFTDetailsInfoComponent.Factory,
|
||||
): NFTDetailsInfoComponent.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindNFTComponentFactory(impl: DefaultNFTComponent.Factory): NFTComponent.Factory
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue