Updated on 2026-08-14
This commit is contained in:
parent
6ddf9a25ae
commit
e8f2ed8517
22 changed files with 463 additions and 81 deletions
|
|
@ -1,10 +1,9 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.nft.FetchNFTCollectionAssetsUseCase
|
||||
import com.tangem.domain.nft.FetchNFTCollectionsUseCase
|
||||
import com.tangem.domain.nft.GetNFTCollectionsUseCase
|
||||
import com.tangem.domain.nft.*
|
||||
import com.tangem.domain.nft.repository.NFTRepository
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -20,30 +19,43 @@ internal object NFTDomainModule {
|
|||
fun providesGetNFTCollectionsUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
nftRepository: NFTRepository,
|
||||
): GetNFTCollectionsUseCase {
|
||||
return GetNFTCollectionsUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
nftRepository = nftRepository,
|
||||
)
|
||||
}
|
||||
): GetNFTCollectionsUseCase = GetNFTCollectionsUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
nftRepository = nftRepository,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesFetchNFTCollectionsUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
nftRepository: NFTRepository,
|
||||
): FetchNFTCollectionsUseCase {
|
||||
return FetchNFTCollectionsUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
nftRepository = nftRepository,
|
||||
)
|
||||
}
|
||||
): FetchNFTCollectionsUseCase = FetchNFTCollectionsUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
nftRepository = nftRepository,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesFetchNFTCollectionAssetsUseCase(nftRepository: NFTRepository): FetchNFTCollectionAssetsUseCase {
|
||||
return FetchNFTCollectionAssetsUseCase(
|
||||
fun providesFetchNFTCollectionAssetsUseCase(nftRepository: NFTRepository): FetchNFTCollectionAssetsUseCase =
|
||||
FetchNFTCollectionAssetsUseCase(
|
||||
nftRepository = nftRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesGetNFTAvailableNetworksUseCase(
|
||||
nftRepository: NFTRepository,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
): GetNFTAvailableNetworksUseCase = GetNFTAvailableNetworksUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
nftRepository = nftRepository,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesFilterNFTAvailableNetworksUseCase(
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): FilterNFTAvailableNetworksUseCase = FilterNFTAvailableNetworksUseCase(
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import com.tangem.features.managetokens.component.ManageTokensComponent
|
|||
import com.tangem.features.managetokens.component.ManageTokensSource
|
||||
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
|
||||
import com.tangem.features.nft.component.NFTCollectionsComponent
|
||||
import com.tangem.features.nft.component.NFTReceiveComponent
|
||||
import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent
|
||||
import com.tangem.features.onramp.component.*
|
||||
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
|
||||
|
|
@ -82,6 +83,7 @@ internal class ChildFactory @Inject constructor(
|
|||
private val sendFeatureToggles: SendFeatureToggles,
|
||||
private val redesignedWalletConnectComponentFactory: RedisegnedWalletConnectComponent.Factory,
|
||||
private val nftCollectionsComponentFactory: NFTCollectionsComponent.Factory,
|
||||
private val nftReceiveComponentFactory: NFTReceiveComponent.Factory,
|
||||
private val testerRouter: TesterRouter,
|
||||
private val routingFeatureToggles: RoutingFeatureToggles,
|
||||
private val walletConnectFeatureToggles: WalletConnectFeatureToggles,
|
||||
|
|
@ -405,6 +407,12 @@ internal class ChildFactory @Inject constructor(
|
|||
params = NFTCollectionsComponent.Params(userWalletId = route.userWalletId),
|
||||
componentFactory = nftCollectionsComponentFactory,
|
||||
)
|
||||
is AppRoute.NFTReceive ->
|
||||
createComponentChild(
|
||||
context = context,
|
||||
params = NFTReceiveComponent.Params(userWalletId = route.userWalletId),
|
||||
componentFactory = nftReceiveComponentFactory,
|
||||
)
|
||||
is AppRoute.OnboardingNote,
|
||||
is AppRoute.SaveWallet,
|
||||
is AppRoute.OnboardingOther,
|
||||
|
|
@ -743,6 +751,12 @@ internal class ChildFactory @Inject constructor(
|
|||
params = NFTCollectionsComponent.Params(userWalletId = route.userWalletId),
|
||||
componentFactory = nftCollectionsComponentFactory,
|
||||
)
|
||||
is AppRoute.NFTReceive ->
|
||||
route.asComponentChild(
|
||||
contextProvider = contextProvider(route, contextFactory),
|
||||
params = NFTReceiveComponent.Params(userWalletId = route.userWalletId),
|
||||
componentFactory = nftReceiveComponentFactory,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,4 +282,9 @@ sealed class AppRoute(val path: String) : Route {
|
|||
data class NFTCollections(
|
||||
val userWalletId: UserWalletId,
|
||||
) : AppRoute(path = "/nft_collections/${userWalletId.stringValue}")
|
||||
|
||||
@Serializable
|
||||
data class NFTReceive(
|
||||
val userWalletId: UserWalletId,
|
||||
) : AppRoute(path = "/nft_receive/${userWalletId.stringValue}")
|
||||
}
|
||||
|
|
@ -510,6 +510,9 @@
|
|||
<string name="nft_collections_title">NFT collections</string>
|
||||
<string name="nft_collections_warning_subtitle">Some data may not load</string>
|
||||
<string name="nft_collections_warning_title">Temporary loading problems</string>
|
||||
<string name="nft_empty_search">No results. Please try another request.</string>
|
||||
<string name="nft_receive_title">Receive NFT</string>
|
||||
<string name="nft_receive_subtitle">To My wallet</string>
|
||||
<string name="nft_wallet_count">%1$d NFTs in %2$d collection</string>
|
||||
<string name="nft_wallet_receive_nft">Tap here to receive first NFT</string>
|
||||
<string name="nft_wallet_title">NFT collections</string>
|
||||
|
|
|
|||
|
|
@ -153,6 +153,8 @@ internal class DefaultNFTRepository @Inject constructor(
|
|||
}.saveIn(getCollectionJobHolder(collectionId)).join()
|
||||
}
|
||||
|
||||
override suspend fun isNFTSupported(network: Network): Boolean = network.canHandleNFTs()
|
||||
|
||||
private suspend fun refreshSalePrice(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ dependencies {
|
|||
implementation(deps.arrow.core)
|
||||
implementation(deps.kotlin.coroutines)
|
||||
|
||||
implementation(projects.core.utils)
|
||||
|
||||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.nft.models)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.domain.nft
|
||||
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class FilterNFTAvailableNetworksUseCase(
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
suspend operator fun invoke(networks: List<Network>, searchQuery: String): List<Network> =
|
||||
withContext(dispatchers.default) {
|
||||
networks.filter {
|
||||
it.name.contains(searchQuery, ignoreCase = true) ||
|
||||
it.currencySymbol.contains(searchQuery, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.domain.nft
|
||||
|
||||
import com.tangem.domain.nft.repository.NFTRepository
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class GetNFTAvailableNetworksUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val nftRepository: NFTRepository,
|
||||
) {
|
||||
operator fun invoke(userWalletId: UserWalletId): Flow<List<Network>> = currenciesRepository
|
||||
.getWalletCurrenciesUpdates(userWalletId)
|
||||
.map { cryptoCurrencies ->
|
||||
cryptoCurrencies
|
||||
.map { cryptoCurrency -> cryptoCurrency.network }
|
||||
.distinct()
|
||||
.filter { nftRepository.isNFTSupported(it) }
|
||||
}
|
||||
}
|
||||
|
|
@ -12,4 +12,6 @@ interface NFTRepository {
|
|||
suspend fun refreshCollections(userWalletId: UserWalletId, networks: List<Network>)
|
||||
|
||||
suspend fun refreshAssets(userWalletId: UserWalletId, network: Network, collectionId: NFTCollection.Identifier)
|
||||
|
||||
suspend fun isNFTSupported(network: Network): Boolean
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.features.nft.component
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface NFTReceiveComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, NFTReceiveComponent>
|
||||
}
|
||||
|
|
@ -5,6 +5,9 @@ import com.tangem.core.decompose.model.Model
|
|||
import com.tangem.features.nft.collections.DefaultNFTCollectionsComponent
|
||||
import com.tangem.features.nft.collections.model.NFTCollectionsModel
|
||||
import com.tangem.features.nft.component.NFTCollectionsComponent
|
||||
import com.tangem.features.nft.component.NFTReceiveComponent
|
||||
import com.tangem.features.nft.receive.DefaultNFTReceiveComponent
|
||||
import com.tangem.features.nft.receive.model.NFTReceiveModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -30,10 +33,21 @@ internal object NFTFeatureModule {
|
|||
internal interface NFTFeatureModuleBinds {
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindComponentFactory(impl: DefaultNFTCollectionsComponent.Factory): NFTCollectionsComponent.Factory
|
||||
fun bindNFTCollectionsComponentFactory(
|
||||
impl: DefaultNFTCollectionsComponent.Factory,
|
||||
): NFTCollectionsComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(NFTCollectionsModel::class)
|
||||
fun bindModel(model: NFTCollectionsModel): Model
|
||||
fun bindNFTCollectionsModel(model: NFTCollectionsModel): Model
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindNFTReceiveComponentFactory(impl: DefaultNFTReceiveComponent.Factory): NFTReceiveComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(NFTReceiveModel::class)
|
||||
fun bindNFTReceiveModel(model: NFTReceiveModel): Model
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.nft.collections.model
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -11,7 +12,8 @@ import com.tangem.domain.nft.FetchNFTCollectionAssetsUseCase
|
|||
import com.tangem.domain.nft.GetNFTCollectionsUseCase
|
||||
import com.tangem.domain.nft.models.NFTAsset
|
||||
import com.tangem.domain.nft.models.NFTCollection
|
||||
import com.tangem.features.nft.collections.entity.*
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsStateUM
|
||||
import com.tangem.features.nft.collections.entity.NFTCollectionsUM
|
||||
import com.tangem.features.nft.collections.entity.transformer.ChangeCollectionExpandedStateTransformer
|
||||
import com.tangem.features.nft.collections.entity.transformer.ToggleSearchBarTransformer
|
||||
import com.tangem.features.nft.collections.entity.transformer.UpdateDataStateTransformer
|
||||
|
|
@ -119,7 +121,11 @@ internal class NFTCollectionsModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onReceiveClick() {
|
||||
// TODO move to receive
|
||||
router.push(
|
||||
AppRoute.NFTReceive(
|
||||
userWalletId = params.userWalletId,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun navigateBack() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.features.nft.receive
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.features.nft.component.NFTReceiveComponent
|
||||
import com.tangem.features.nft.receive.model.NFTReceiveModel
|
||||
import com.tangem.features.nft.receive.ui.NFTReceive
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultNFTReceiveComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted private val params: NFTReceiveComponent.Params,
|
||||
) : NFTReceiveComponent, AppComponentContext by context {
|
||||
|
||||
private val model: NFTReceiveModel = getOrCreateModel(params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
|
||||
NFTReceive(state, modifier)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : NFTReceiveComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: NFTReceiveComponent.Params,
|
||||
): DefaultNFTReceiveComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package com.tangem.features.nft.receive.entity
|
||||
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
internal data class NFTReceiveNetworksUM(
|
||||
val searchBar: SearchBarUM,
|
||||
val networks: ImmutableList<NFTNetworkUM>,
|
||||
)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.features.nft.receive.entity
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
internal data class NFTReceiveUM(
|
||||
val onBackClick: () -> Unit,
|
||||
val search: SearchBarUM,
|
||||
val networks: Networks,
|
||||
val bottomSheetConfig: TangemBottomSheetConfig?,
|
||||
) {
|
||||
|
||||
@Immutable
|
||||
sealed class Networks {
|
||||
data object Empty : Networks()
|
||||
|
||||
data class Content(
|
||||
val items: ImmutableList<NFTNetworkUM>,
|
||||
) : Networks()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.features.nft.receive.entity.transformer
|
||||
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class ToggleSearchBarTransformer(private val isActive: Boolean) : Transformer<NFTReceiveUM> {
|
||||
|
||||
override fun transform(prevState: NFTReceiveUM): NFTReceiveUM = prevState.copy(
|
||||
search = prevState.search.copy(
|
||||
isActive = isActive,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.features.nft.receive.entity.transformer
|
||||
|
||||
import com.tangem.core.ui.extensions.getActiveIconRes
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.features.nft.receive.entity.NFTNetworkUM
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class UpdateDataStateTransformer(
|
||||
private val networks: List<Network>,
|
||||
private val onNetworkClick: (Network) -> Unit,
|
||||
) : Transformer<NFTReceiveUM> {
|
||||
|
||||
override fun transform(prevState: NFTReceiveUM): NFTReceiveUM = prevState.copy(
|
||||
networks = when {
|
||||
networks.isEmpty() -> NFTReceiveUM.Networks.Empty
|
||||
else -> NFTReceiveUM.Networks.Content(
|
||||
items = networks
|
||||
.map { it.transform() }
|
||||
.toPersistentList(),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
private fun Network.transform(): NFTNetworkUM = NFTNetworkUM(
|
||||
id = id.value,
|
||||
iconRes = getActiveIconRes(id.value),
|
||||
name = name,
|
||||
onItemClick = {
|
||||
onNetworkClick(this)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.features.nft.receive.entity.transformer
|
||||
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class UpdateSearchQueryTransformer(private val newQuery: String) : Transformer<NFTReceiveUM> {
|
||||
|
||||
override fun transform(prevState: NFTReceiveUM): NFTReceiveUM = prevState.copy(
|
||||
search = prevState.search.copy(
|
||||
query = newQuery,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package com.tangem.features.nft.receive.model
|
||||
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.ui.components.fields.InputManager
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.nft.FilterNFTAvailableNetworksUseCase
|
||||
import com.tangem.domain.nft.GetNFTAvailableNetworksUseCase
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.features.nft.component.NFTReceiveComponent
|
||||
import com.tangem.features.nft.impl.R
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
import com.tangem.features.nft.receive.entity.transformer.ToggleSearchBarTransformer
|
||||
import com.tangem.features.nft.receive.entity.transformer.UpdateDataStateTransformer
|
||||
import com.tangem.features.nft.receive.entity.transformer.UpdateSearchQueryTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class NFTReceiveModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val router: Router,
|
||||
private val searchManager: InputManager,
|
||||
private val getNFTAvailableNetworksUseCase: GetNFTAvailableNetworksUseCase,
|
||||
private val filterNFTAvailableNetworksUseCase: FilterNFTAvailableNetworksUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
val state: StateFlow<NFTReceiveUM> get() = _state
|
||||
|
||||
private val _state = MutableStateFlow(
|
||||
value = NFTReceiveUM(
|
||||
onBackClick = ::navigateBack,
|
||||
search = getInitialSearchBar(),
|
||||
networks = NFTReceiveUM.Networks.Content(persistentListOf()),
|
||||
bottomSheetConfig = null,
|
||||
),
|
||||
)
|
||||
|
||||
private val params: NFTReceiveComponent.Params = paramsContainer.require()
|
||||
|
||||
init {
|
||||
subscribeToNFTAvailableNetworks()
|
||||
}
|
||||
|
||||
private fun subscribeToNFTAvailableNetworks() {
|
||||
combine(
|
||||
flow = getNFTAvailableNetworksUseCase(params.userWalletId),
|
||||
flow2 = searchManager.query.distinctUntilChanged(),
|
||||
) { networks, query ->
|
||||
filterNFTAvailableNetworksUseCase(networks, query)
|
||||
}
|
||||
.onEach { filteredNetworks ->
|
||||
_state.update {
|
||||
UpdateDataStateTransformer(
|
||||
networks = filteredNetworks,
|
||||
onNetworkClick = ::onNetworkClick,
|
||||
).transform(it)
|
||||
}
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun onSearchQueryChange(newQuery: String) {
|
||||
modelScope.launch {
|
||||
_state.update { UpdateSearchQueryTransformer(newQuery).transform(it) }
|
||||
|
||||
searchManager.update(newQuery)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInitialSearchBar(): SearchBarUM = SearchBarUM(
|
||||
placeholderText = resourceReference(R.string.common_search),
|
||||
query = "",
|
||||
isActive = false,
|
||||
onQueryChange = ::onSearchQueryChange,
|
||||
onActiveChange = ::toggleSearchBar,
|
||||
)
|
||||
|
||||
private fun toggleSearchBar(isActive: Boolean) {
|
||||
_state.update {
|
||||
ToggleSearchBarTransformer(isActive).transform(it)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private fun onNetworkClick(network: Network) {
|
||||
// TODO show receive bottom sheet
|
||||
}
|
||||
|
||||
private fun navigateBack() {
|
||||
router.pop()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.features.nft.receive.ui
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.components.appbar.TangemTopAppBar
|
||||
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
|
||||
import com.tangem.core.ui.components.fields.SearchBar
|
||||
import com.tangem.core.ui.components.fields.TangemSearchBarDefaults
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.nft.impl.R
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
|
||||
@Composable
|
||||
internal fun NFTReceive(state: NFTReceiveUM, modifier: Modifier = Modifier) {
|
||||
BackHandler(onBack = state.onBackClick)
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
topBar = {
|
||||
TangemTopAppBar(
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
startButton = TopAppBarButtonUM(
|
||||
iconRes = R.drawable.ic_close_24,
|
||||
onIconClicked = state.onBackClick,
|
||||
),
|
||||
title = stringResourceSafe(id = R.string.nft_receive_title),
|
||||
subtitle = stringResourceSafe(id = R.string.nft_receive_subtitle),
|
||||
)
|
||||
},
|
||||
content = { innerPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
SearchBar(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
state = state.search,
|
||||
colors = TangemSearchBarDefaults.secondaryTextFieldColors,
|
||||
)
|
||||
|
||||
val contentModifier = Modifier
|
||||
.padding(TangemTheme.dimens.spacing16)
|
||||
|
||||
AnimatedContent(
|
||||
targetState = state.networks,
|
||||
contentKey = { it::class },
|
||||
label = "NFT Receive",
|
||||
) {
|
||||
when (val networks = it) {
|
||||
is NFTReceiveUM.Networks.Content -> NFTReceiveNetworksContent(networks, contentModifier)
|
||||
is NFTReceiveUM.Networks.Empty -> NFTReceiveNetworksEmpty(contentModifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
package com.tangem.features.nft.receive.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
|
|
@ -14,57 +13,39 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.components.fields.SearchBar
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
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.impl.R
|
||||
import com.tangem.features.nft.receive.entity.NFTNetworkUM
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveNetworksUM
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
internal fun NFTReceiveNetworks(state: NFTReceiveNetworksUM, modifier: Modifier = Modifier) {
|
||||
internal fun NFTReceiveNetworksContent(state: NFTReceiveUM.Networks.Content, modifier: Modifier = Modifier) {
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
Column(
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(TangemTheme.colors.background.secondary)
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing16,
|
||||
),
|
||||
.fillMaxWidth()
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.animateContentSize(),
|
||||
state = listState,
|
||||
) {
|
||||
SearchBar(
|
||||
state = state.searchBar,
|
||||
// TODO fix colors after merging [REDACTED_TASK_KEY]
|
||||
)
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
vertical = TangemTheme.dimens.spacing16,
|
||||
)
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
state = listState,
|
||||
item(
|
||||
key = "title",
|
||||
) {
|
||||
item(
|
||||
key = "title",
|
||||
) {
|
||||
Title()
|
||||
}
|
||||
items(
|
||||
items = state.networks,
|
||||
key = NFTNetworkUM::id,
|
||||
) { network ->
|
||||
NFTNetwork(state = network)
|
||||
}
|
||||
Title()
|
||||
}
|
||||
items(
|
||||
items = state.items,
|
||||
key = NFTNetworkUM::id,
|
||||
) { network ->
|
||||
NFTNetwork(
|
||||
state = network,
|
||||
modifier = Modifier.animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -91,16 +72,9 @@ private fun Title(modifier: Modifier = Modifier) {
|
|||
@Composable
|
||||
private fun Preview_NFTReceiveNetworksUM() {
|
||||
TangemThemePreview {
|
||||
NFTReceiveNetworks(
|
||||
state = NFTReceiveNetworksUM(
|
||||
searchBar = SearchBarUM(
|
||||
placeholderText = resourceReference(R.string.common_search),
|
||||
query = "",
|
||||
onQueryChange = { },
|
||||
isActive = false,
|
||||
onActiveChange = { },
|
||||
),
|
||||
networks = persistentListOf(
|
||||
NFTReceiveNetworksContent(
|
||||
state = NFTReceiveUM.Networks.Content(
|
||||
items = persistentListOf(
|
||||
NFTNetworkUM(
|
||||
id = "item1",
|
||||
name = "Ethereum",
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.features.nft.receive.ui
|
||||
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.nft.impl.R
|
||||
|
||||
@Composable
|
||||
internal fun NFTReceiveNetworksEmpty(modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
modifier = modifier,
|
||||
text = stringResourceSafe(id = R.string.nft_empty_search),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue