diff --git a/app/src/main/java/com/tangem/tap/di/domain/NFTDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/NFTDomainModule.kt
index f9972a842d..b9cfccbc58 100644
--- a/app/src/main/java/com/tangem/tap/di/domain/NFTDomainModule.kt
+++ b/app/src/main/java/com/tangem/tap/di/domain/NFTDomainModule.kt
@@ -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,
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
index b68f419f3f..dd951b0a53 100644
--- a/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
+++ b/app/src/main/java/com/tangem/tap/routing/utils/ChildFactory.kt
@@ -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
}
diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt
index 60e5d50f16..2a77d9fd2b 100644
--- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt
+++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt
@@ -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}")
}
\ No newline at end of file
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 9966613b6c..22cf05d7e5 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -510,6 +510,9 @@
NFT collections
Some data may not load
Temporary loading problems
+ No results. Please try another request.
+ Receive NFT
+ To My wallet
%1$d NFTs in %2$d collection
Tap here to receive first NFT
NFT collections
diff --git a/data/nft/src/main/kotlin/com/tangem/data/nft/DefaultNFTRepository.kt b/data/nft/src/main/kotlin/com/tangem/data/nft/DefaultNFTRepository.kt
index ebf03a5f42..197249ec85 100644
--- a/data/nft/src/main/kotlin/com/tangem/data/nft/DefaultNFTRepository.kt
+++ b/data/nft/src/main/kotlin/com/tangem/data/nft/DefaultNFTRepository.kt
@@ -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,
diff --git a/domain/nft/build.gradle.kts b/domain/nft/build.gradle.kts
index 2159e615a7..b5ce316d58 100644
--- a/domain/nft/build.gradle.kts
+++ b/domain/nft/build.gradle.kts
@@ -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)
diff --git a/domain/nft/src/main/kotlin/com/tangem/domain/nft/FilterNFTAvailableNetworksUseCase.kt b/domain/nft/src/main/kotlin/com/tangem/domain/nft/FilterNFTAvailableNetworksUseCase.kt
new file mode 100644
index 0000000000..3308232789
--- /dev/null
+++ b/domain/nft/src/main/kotlin/com/tangem/domain/nft/FilterNFTAvailableNetworksUseCase.kt
@@ -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, searchQuery: String): List =
+ withContext(dispatchers.default) {
+ networks.filter {
+ it.name.contains(searchQuery, ignoreCase = true) ||
+ it.currencySymbol.contains(searchQuery, ignoreCase = true)
+ }
+ }
+}
\ No newline at end of file
diff --git a/domain/nft/src/main/kotlin/com/tangem/domain/nft/GetNFTAvailableNetworksUseCase.kt b/domain/nft/src/main/kotlin/com/tangem/domain/nft/GetNFTAvailableNetworksUseCase.kt
new file mode 100644
index 0000000000..203f12e012
--- /dev/null
+++ b/domain/nft/src/main/kotlin/com/tangem/domain/nft/GetNFTAvailableNetworksUseCase.kt
@@ -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> = currenciesRepository
+ .getWalletCurrenciesUpdates(userWalletId)
+ .map { cryptoCurrencies ->
+ cryptoCurrencies
+ .map { cryptoCurrency -> cryptoCurrency.network }
+ .distinct()
+ .filter { nftRepository.isNFTSupported(it) }
+ }
+}
\ No newline at end of file
diff --git a/domain/nft/src/main/kotlin/com/tangem/domain/nft/repository/NFTRepository.kt b/domain/nft/src/main/kotlin/com/tangem/domain/nft/repository/NFTRepository.kt
index 7ab39c2bff..5d811e9a39 100644
--- a/domain/nft/src/main/kotlin/com/tangem/domain/nft/repository/NFTRepository.kt
+++ b/domain/nft/src/main/kotlin/com/tangem/domain/nft/repository/NFTRepository.kt
@@ -12,4 +12,6 @@ interface NFTRepository {
suspend fun refreshCollections(userWalletId: UserWalletId, networks: List)
suspend fun refreshAssets(userWalletId: UserWalletId, network: Network, collectionId: NFTCollection.Identifier)
+
+ suspend fun isNFTSupported(network: Network): Boolean
}
\ No newline at end of file
diff --git a/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTReceiveComponent.kt b/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTReceiveComponent.kt
new file mode 100644
index 0000000000..9184afa340
--- /dev/null
+++ b/features/nft/api/src/main/kotlin/com/tangem/features/nft/component/NFTReceiveComponent.kt
@@ -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
+}
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/NFTFeatureModule.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/NFTFeatureModule.kt
index 09b06ecd70..91a6bbd3d5 100644
--- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/NFTFeatureModule.kt
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/NFTFeatureModule.kt
@@ -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
}
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt
index 5a206e8c95..aa8431196e 100644
--- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/collections/model/NFTCollectionsModel.kt
@@ -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() {
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/DefaultNFTReceiveComponent.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/DefaultNFTReceiveComponent.kt
new file mode 100644
index 0000000000..f9651f18e3
--- /dev/null
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/DefaultNFTReceiveComponent.kt
@@ -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
+ }
+}
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/NFTReceiveNetworksUM.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/NFTReceiveNetworksUM.kt
deleted file mode 100644
index 91abfb75ef..0000000000
--- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/NFTReceiveNetworksUM.kt
+++ /dev/null
@@ -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,
-)
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/NFTReceiveUM.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/NFTReceiveUM.kt
new file mode 100644
index 0000000000..0764b2f074
--- /dev/null
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/NFTReceiveUM.kt
@@ -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,
+ ) : Networks()
+ }
+}
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/transformer/ToggleSearchBarTransformer.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/transformer/ToggleSearchBarTransformer.kt
new file mode 100644
index 0000000000..16b51e66a9
--- /dev/null
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/transformer/ToggleSearchBarTransformer.kt
@@ -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 {
+
+ override fun transform(prevState: NFTReceiveUM): NFTReceiveUM = prevState.copy(
+ search = prevState.search.copy(
+ isActive = isActive,
+ ),
+ )
+}
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/transformer/UpdateDataStateTransformer.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/transformer/UpdateDataStateTransformer.kt
new file mode 100644
index 0000000000..560bf018f7
--- /dev/null
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/transformer/UpdateDataStateTransformer.kt
@@ -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,
+ private val onNetworkClick: (Network) -> Unit,
+) : Transformer {
+
+ 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)
+ },
+ )
+}
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/transformer/UpdateSearchQueryTransformer.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/transformer/UpdateSearchQueryTransformer.kt
new file mode 100644
index 0000000000..6e2d305b3d
--- /dev/null
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/entity/transformer/UpdateSearchQueryTransformer.kt
@@ -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 {
+
+ override fun transform(prevState: NFTReceiveUM): NFTReceiveUM = prevState.copy(
+ search = prevState.search.copy(
+ query = newQuery,
+ ),
+ )
+}
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt
new file mode 100644
index 0000000000..2e1b50b3c7
--- /dev/null
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt
@@ -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 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()
+ }
+}
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceive.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceive.kt
new file mode 100644
index 0000000000..326d77da63
--- /dev/null
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceive.kt
@@ -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)
+ }
+ }
+ }
+ },
+ )
+}
\ No newline at end of file
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceiveNetworks.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceiveNetworksContent.kt
similarity index 59%
rename from features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceiveNetworks.kt
rename to features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceiveNetworksContent.kt
index e51fb169bb..23fab1ef15 100644
--- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceiveNetworks.kt
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceiveNetworksContent.kt
@@ -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",
diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceiveNetworksEmpty.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceiveNetworksEmpty.kt
new file mode 100644
index 0000000000..cebaa5a91d
--- /dev/null
+++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/ui/NFTReceiveNetworksEmpty.kt
@@ -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,
+ )
+}
\ No newline at end of file