Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-02 01:41:05 +05:00
parent 6c16caedba
commit 3bbdbbb5a3
16 changed files with 286 additions and 73 deletions

View file

@ -102,12 +102,12 @@ internal class TokenActionsHandler @AssistedInject constructor(
}
},
content = TokenReceiveBottomSheetConfig(
name = currency.name,
symbol = currency.symbol,
network = currency.network.name,
addresses = networkAddress.availableAddresses
.mapToAddressModels(currency)
.toImmutableList(),
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
networkAddress = networkAddress,
showMemoDisclaimer = currency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
onCopyClick = {},
onShareClick = {},

View file

@ -0,0 +1,32 @@
package com.tangem.features.nft.receive.entity.transformer
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.tokens.model.NetworkAddress
import com.tangem.features.nft.receive.entity.NFTReceiveUM
import com.tangem.utils.transformer.Transformer
internal class ShowReceiveBottomSheetTransformer(
private val network: Network,
private val networkAddress: NetworkAddress,
private val onDismissBottomSheet: () -> Unit,
private val onCopyClick: (String) -> Unit,
private val onShareClick: (String) -> Unit,
) : Transformer<NFTReceiveUM> {
override fun transform(prevState: NFTReceiveUM): NFTReceiveUM = prevState.copy(
bottomSheetConfig = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = onDismissBottomSheet,
content = TokenReceiveBottomSheetConfig(
asset = TokenReceiveBottomSheetConfig.Asset.NFT,
network = network,
networkAddress = networkAddress,
showMemoDisclaimer = network.transactionExtrasType != Network.TransactionExtrasType.NONE,
onCopyClick = onCopyClick,
onShareClick = onShareClick,
),
),
)
}

View file

@ -4,15 +4,20 @@ 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.navigation.share.ShareManager
import com.tangem.core.ui.clipboard.ClipboardManager
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.nft.GetNFTNetworkStatusUseCase
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.tokens.model.NetworkStatus
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.ShowReceiveBottomSheetTransformer
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
@ -22,6 +27,7 @@ import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@Suppress("LongParameterList")
@ModelScoped
internal class NFTReceiveModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
@ -29,6 +35,9 @@ internal class NFTReceiveModel @Inject constructor(
private val searchManager: InputManager,
private val getNFTAvailableNetworksUseCase: GetNFTAvailableNetworksUseCase,
private val filterNFTAvailableNetworksUseCase: FilterNFTAvailableNetworksUseCase,
private val getNFTNetworkStatusUseCase: GetNFTNetworkStatusUseCase,
private val clipboardManager: ClipboardManager,
private val shareManager: ShareManager,
paramsContainer: ParamsContainer,
) : Model() {
@ -89,9 +98,47 @@ internal class NFTReceiveModel @Inject constructor(
}
}
@Suppress("UnusedPrivateMember")
private fun onReceiveBottomSheetDismiss() {
_state.update {
it.copy(
bottomSheetConfig = it.bottomSheetConfig?.copy(isShown = false),
)
}
}
private fun onNetworkClick(network: Network) {
// TODO show receive bottom sheet
modelScope.launch {
val networkStatus = getNFTNetworkStatusUseCase.invoke(
userWalletId = params.userWalletId,
network = network,
) ?: return@launch
when (val value = networkStatus.value) {
is NetworkStatus.Verified -> {
_state.update {
ShowReceiveBottomSheetTransformer(
network = network,
networkAddress = value.address,
onDismissBottomSheet = ::onReceiveBottomSheetDismiss,
onCopyClick = ::onCopyClick,
onShareClick = ::onShareClick,
).transform(it)
}
}
is NetworkStatus.MissedDerivation,
is NetworkStatus.NoAccount,
is NetworkStatus.Unreachable,
-> Unit
}
}
}
private fun onCopyClick(text: String) {
clipboardManager.setText(text = text, isSensitive = true)
}
private fun onShareClick(text: String) {
shareManager.shareText(text = text)
}
private fun navigateBack() {

View file

@ -6,8 +6,11 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheet
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
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.components.fields.SearchBar
import com.tangem.core.ui.components.fields.TangemSearchBarDefaults
import com.tangem.core.ui.extensions.stringResourceSafe
@ -63,4 +66,17 @@ internal fun NFTReceive(state: NFTReceiveUM, modifier: Modifier = Modifier) {
}
},
)
ShowBottomSheet(state.bottomSheetConfig)
}
@Composable
private fun ShowBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
if (bottomSheetConfig != null) {
when (bottomSheetConfig.content) {
is TokenReceiveBottomSheetConfig -> {
TokenReceiveBottomSheet(config = bottomSheetConfig)
}
}
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.features.onboarding.v2.note.impl.child.topup.model
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.core.analytics.Analytics
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
@ -8,8 +9,6 @@ import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.card.repository.CardRepository
@ -30,7 +29,6 @@ import com.tangem.features.onboarding.v2.note.impl.child.topup.OnboardingNoteTop
import com.tangem.features.onboarding.v2.note.impl.child.topup.ui.state.OnboardingNoteTopUpUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.isPositive
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -223,12 +221,12 @@ internal class OnboardingNoteTopUpModel @Inject constructor(
isShown = true,
onDismissRequest = uiState.value.onDismissBottomSheet,
content = TokenReceiveBottomSheetConfig(
name = currencyStatus.currency.name,
symbol = currencyStatus.currency.symbol,
network = currencyStatus.currency.network.name,
addresses = networkAddress.availableAddresses
.mapToAddressModels(currencyStatus.currency)
.toImmutableList(),
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currencyStatus.currency.name,
symbol = currencyStatus.currency.symbol,
),
network = currencyStatus.currency.network,
networkAddress = networkAddress,
showMemoDisclaimer =
currencyStatus.currency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
onCopyClick = {

View file

@ -16,7 +16,6 @@ import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.toWrappedList
import com.tangem.core.ui.format.bigdecimal.crypto
@ -51,7 +50,6 @@ import com.tangem.sdk.extensions.localizedDescriptionRes
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.firstOrNull
@ -370,12 +368,12 @@ internal class OnboardingTwinModel @Inject constructor(
}
},
content = TokenReceiveBottomSheetConfig(
name = currency.name,
symbol = currency.symbol,
network = currency.network.name,
addresses = networkAddress.availableAddresses
.mapToAddressModels(currency)
.toImmutableList(),
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
networkAddress = networkAddress,
showMemoDisclaimer =
currency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
onCopyClick = {},

View file

@ -6,7 +6,6 @@ import com.tangem.common.ui.tokens.getUnavailabilityReasonText
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
@ -267,10 +266,12 @@ internal class TokenDetailsStateFactory(
isShown = true,
onDismissRequest = clickIntents::onDismissBottomSheet,
content = TokenReceiveBottomSheetConfig(
name = currency.name,
symbol = currency.symbol,
network = currency.network.name,
addresses = networkAddress.availableAddresses.mapToAddressModels(currency).toImmutableList(),
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
networkAddress = networkAddress,
showMemoDisclaimer = currency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
onCopyClick = onCopyClick,
onShareClick = onShareClick,
@ -288,7 +289,12 @@ internal class TokenDetailsStateFactory(
isShown = true,
onDismissRequest = clickIntents::onDismissBottomSheet,
content = ChooseAddressBottomSheetConfig(
addressModels = networkAddress.availableAddresses.mapToAddressModels(currency).toImmutableList(),
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
networkAddress = networkAddress,
onClick = clickIntents::onAddressTypeSelected,
),
),

View file

@ -169,7 +169,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
stateHolder.showBottomSheet(
createReceiveBottomSheetContent(
currency = cryptoCurrencyStatus.currency,
addresses = cryptoCurrencyStatus.value.networkAddress?.availableAddresses ?: return,
addresses = cryptoCurrencyStatus.value.networkAddress ?: return,
),
userWalletId,
)
@ -189,13 +189,15 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private fun createReceiveBottomSheetContent(
currency: CryptoCurrency,
addresses: Set<NetworkAddress.Address>,
addresses: NetworkAddress,
): TangemBottomSheetConfigContent {
return TokenReceiveBottomSheetConfig(
name = currency.name,
symbol = currency.symbol,
network = currency.network.name,
addresses = addresses.mapToAddressModels(currency).toImmutableList(),
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
networkAddress = addresses,
showMemoDisclaimer = currency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
onCopyClick = {
analyticsEventHandler.send(TokenReceiveAnalyticsEvent.ButtonCopyAddress(currency.symbol))
@ -488,7 +490,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
when (val addresses = currencyStatus.value.networkAddress) {
is NetworkAddress.Selectable -> {
showChooseAddressBottomSheet(userWalletId, addresses.availableAddresses, currencyStatus.currency)
showChooseAddressBottomSheet(userWalletId, addresses, currencyStatus.currency)
}
is NetworkAddress.Single -> {
router.openUrl(
@ -506,12 +508,17 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private fun showChooseAddressBottomSheet(
userWalletId: UserWalletId,
addresses: Set<NetworkAddress.Address>,
addresses: NetworkAddress,
currency: CryptoCurrency,
) {
stateHolder.showBottomSheet(
ChooseAddressBottomSheetConfig(
addressModels = addresses.mapToAddressModels(currency).toImmutableList(),
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
networkAddress = addresses,
onClick = {
onAddressTypeSelected(
userWalletId = userWalletId,