Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-02 13:54:21 +05:00
parent 58e26ca5e6
commit a411d79c10
32 changed files with 79 additions and 819 deletions

View file

@ -143,7 +143,6 @@ abstract class BaseTestCase : TestCase(
private fun applicationInjectionRule(): ApplicationInjectionExecutionRule {
return ApplicationInjectionExecutionRule(
toggleStates = mapOf(
"NEW_TOKEN_RECEIVE_ENABLED" to true,
"SWAP_REDESIGN_ENABLED" to false,
"NEW_ONRAMP_MAIN_ENABLED" to true,
"HOT_WALLET_ENABLED" to true,

View file

@ -1,15 +1,23 @@
package com.tangem.common.ui.bottomsheet.chooseaddress
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
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.PreviewParameterProvider
import com.tangem.common.ui.bottomsheet.receive.AddressModel
import com.tangem.core.ui.R
import com.tangem.core.ui.components.SimpleSettingsRow
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.TangemBottomSheet
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 kotlinx.collections.immutable.persistentListOf
@Composable
fun ChooseAddressBottomSheet(config: TangemBottomSheetConfig) {
@ -31,4 +39,40 @@ private fun ChooseAddressBottomSheetContent(content: ChooseAddressBottomSheetCon
)
}
}
}
}
// region Preview
@Composable
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun ChooseAddressBottomSheet_Preview(
@PreviewParameter(ChooseAddressBottomSheetPreviewProvider::class) params: ChooseAddressBottomSheetConfig,
) {
TangemThemePreview {
ChooseAddressBottomSheetContent(params)
}
}
private class ChooseAddressBottomSheetPreviewProvider : PreviewParameterProvider<ChooseAddressBottomSheetConfig> {
override val values: Sequence<ChooseAddressBottomSheetConfig>
get() = sequenceOf(
ChooseAddressBottomSheetConfig(
addressModels = persistentListOf(
AddressModel(
displayName = stringReference("Main address"),
fullName = stringReference("Bitcoin"),
value = "0x1234...abcd",
type = AddressModel.Type.Default,
),
AddressModel(
displayName = stringReference("Legacy address"),
fullName = stringReference("Bitcoin"),
value = "0x1234...abcd",
type = AddressModel.Type.Default,
),
),
onClick = {},
),
)
}
// endregion

View file

@ -1,10 +1,9 @@
package com.tangem.common.ui.bottomsheet.chooseaddress
import com.tangem.common.ui.bottomsheet.receive.AddressModel
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.NetworkAddress
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
@ -14,13 +13,12 @@ class ChooseAddressBottomSheetConfig(
val onClick: (AddressModel) -> Unit,
) : TangemBottomSheetConfigContent {
constructor(
asset: TokenReceiveBottomSheetConfig.Asset,
network: Network,
currency: CryptoCurrency,
networkAddress: NetworkAddress,
onClick: (AddressModel) -> Unit,
) : this(
addressModels = networkAddress.availableAddresses
.mapToAddressModels(asset, network)
.mapToAddressModels(cryptoCurrency = currency)
.toImmutableList(),
onClick = onClick,
)

View file

@ -1,9 +1,7 @@
package com.tangem.common.ui.bottomsheet.receive
import com.tangem.core.ui.R
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.combinedReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
@ -20,20 +18,6 @@ fun Set<NetworkAddress.Address>.mapToAddressModels(cryptoCurrency: CryptoCurrenc
cryptoCurrency.network,
)
fun Set<NetworkAddress.Address>.mapToAddressModels(
asset: TokenReceiveBottomSheetConfig.Asset,
network: Network,
): List<AddressModel> = when (asset) {
is TokenReceiveBottomSheetConfig.Asset.Currency -> mapToAddressModels(
stringReference("${asset.name} (${asset.symbol})"),
network,
)
is TokenReceiveBottomSheetConfig.Asset.NFT -> mapToAddressModels(
resourceReference(R.string.common_nft),
network,
)
}
private fun Set<NetworkAddress.Address>.mapToAddressModels(name: TextReference, network: Network): List<AddressModel> =
this
.sortedBy { it.type.ordinal }

View file

@ -1,330 +0,0 @@
package com.tangem.common.ui.bottomsheet.receive
import android.content.res.Configuration
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import com.tangem.core.res.getStringSafe
import com.tangem.core.ui.R
import com.tangem.core.ui.components.SecondaryButtonIconStart
import com.tangem.core.ui.components.bottomsheets.sheet.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.components.rememberQrPainters
import com.tangem.core.ui.components.snackbar.CopiedTextSnackbarHost
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.launch
@Composable
fun TokenReceiveBottomSheet(config: TangemBottomSheetConfig) {
TangemBottomSheet(config) { content: TokenReceiveBottomSheetConfig ->
TokenReceiveBottomSheetContent(content = content)
}
}
@Composable
private fun TokenReceiveBottomSheetContent(content: TokenReceiveBottomSheetConfig) {
var selectedAddress by remember { mutableStateOf(content.addresses.first()) }
val snackbarHostState = remember(::SnackbarHostState)
ContainerWithSnackbarHost(snackbarHostState = snackbarHostState) {
Column(
modifier = Modifier
.verticalScroll(state = rememberScrollState())
.padding(top = 24.dp, bottom = 16.dp)
.padding(horizontal = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(space = 24.dp),
) {
QrCodeContent(content = content, onAddressChange = { selectedAddress = it })
Info(
showMemoDisclaimer = content.showMemoDisclaimer,
notifications = content.notifications,
)
Buttons(
snackbarHostState = snackbarHostState,
onShareClick = { content.onShareClick(selectedAddress.value) },
onCopyClick = { content.onCopyClick(selectedAddress.value) },
)
}
}
}
@Composable
private fun Info(
showMemoDisclaimer: Boolean,
notifications: ImmutableList<NotificationConfig>,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
) {
if (showMemoDisclaimer) {
Text(
modifier = Modifier
.padding(horizontal = 18.dp)
.fillMaxWidth(),
text = stringResourceSafe(R.string.receive_bottom_sheet_no_memo_required_message),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,
)
}
notifications.fastForEach { notificationConfig ->
key(notificationConfig.hashCode()) {
Notification(config = notificationConfig)
}
}
}
}
@Composable
private fun ContainerWithSnackbarHost(snackbarHostState: SnackbarHostState, content: @Composable () -> Unit) {
Box {
content()
CopiedTextSnackbarHost(
hostState = snackbarHostState,
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 80.dp),
)
}
}
@Composable
private fun QrCodeContent(content: TokenReceiveBottomSheetConfig, onAddressChange: (AddressModel) -> Unit) {
val qrCodes = rememberQrPainters(content.addresses.map(AddressModel::value))
val pagerState = rememberPagerState(
initialPage = 0,
initialPageOffsetFraction = 0f,
pageCount = content.addresses::count,
)
LaunchedEffect(key1 = pagerState.currentPage) {
onAddressChange.invoke(content.addresses[pagerState.currentPage])
}
HorizontalPager(state = pagerState) { currentPage ->
QrCodePage(
content = content,
qrCodePainter = qrCodes[currentPage],
currentIndex = currentPage,
)
}
if (pagerState.pageCount > 1) {
val indicatorState = rememberLazyListState()
val selectedColor = TangemTheme.colors.icon.primary1
val unselectedColor = TangemTheme.colors.icon.informative
LazyRow(
modifier = Modifier.height(20.dp),
state = indicatorState,
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
repeat(pagerState.pageCount) { iteration ->
item(key = iteration) {
val color by animateColorAsState(
targetValue = if (pagerState.currentPage == iteration) selectedColor else unselectedColor,
label = "",
)
Box(
modifier = Modifier
.padding(horizontal = 4.dp, vertical = 6.dp)
.background(color = color, shape = CircleShape)
.size(7.dp),
)
}
}
}
}
}
@Composable
private fun QrCodePage(content: TokenReceiveBottomSheetConfig, qrCodePainter: Painter, currentIndex: Int) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(24.dp),
) {
Text(
text = stringResourceSafe(
R.string.receive_bottom_sheet_warning_message_compact,
content.addresses[currentIndex].fullName.resolveReference(),
content.network,
),
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
style = TangemTheme.typography.h3,
)
Image(
painter = qrCodePainter,
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier.size(248.dp),
)
Text(
text = content.addresses[currentIndex].value,
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
style = TangemTheme.typography.subtitle1,
)
}
}
@Composable
private fun Buttons(
snackbarHostState: SnackbarHostState,
onShareClick: () -> Unit,
onCopyClick: () -> Unit,
modifier: Modifier = Modifier,
) {
val hapticFeedback = LocalHapticFeedback.current
val coroutineScope = rememberCoroutineScope()
val context = LocalContext.current
val resources = context.resources
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(16.dp),
) {
SecondaryButtonIconStart(
modifier = Modifier.weight(1f),
text = stringResourceSafe(id = R.string.common_copy),
iconResId = R.drawable.ic_copy_24,
onClick = {
onCopyClick()
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
coroutineScope.launch {
snackbarHostState.showSnackbar(
message = resources.getStringSafe(R.string.wallet_notification_address_copied),
)
}
},
)
SecondaryButtonIconStart(
modifier = Modifier.weight(1f),
text = stringResourceSafe(id = R.string.common_share),
iconResId = R.drawable.ic_share_24,
onClick = {
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
onShareClick()
},
)
}
}
// region Preview
@Composable
@Preview(showBackground = true, widthDp = 360)
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun Preview_TokenReceiveBottomSheet(
@PreviewParameter(TokenReceiveBottomSheetConfigPreviewProvider::class) params: TokenReceiveBottomSheetConfig,
) {
TangemThemePreview {
val config = TangemBottomSheetConfig(
isShown = true,
content = params,
onDismissRequest = {},
)
TokenReceiveBottomSheet(config)
}
}
private class TokenReceiveBottomSheetConfigPreviewProvider : PreviewParameterProvider<TokenReceiveBottomSheetConfig> {
val address = AddressModel(
displayName = stringReference("Address 1"),
fullName = combinedReference(
stringReference("Address 1"),
stringReference(" Stellar"),
),
value = "0xe5178c7d4d0e861ed2e9414e045b501226b0de8d",
type = AddressModel.Type.Default,
)
private val baseConfig = TokenReceiveBottomSheetConfig(
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = "Stellar",
symbol = "XLM",
),
network = "Ethereum",
notifications = persistentListOf(
NotificationConfig(
title = stringReference("Send only XLM on the Ethereum network"),
subtitle = resourceReference(R.string.receive_bottom_sheet_warning_message_description),
iconResId = R.drawable.ic_alert_circle_24,
),
),
addresses = persistentListOf(address),
showMemoDisclaimer = false,
onCopyClick = {},
onShareClick = {},
)
override val values: Sequence<TokenReceiveBottomSheetConfig>
get() = sequenceOf(
baseConfig,
baseConfig.copy(
addresses = persistentListOf(
address,
address.copy(displayName = stringReference("Address 2")),
),
),
baseConfig.copy(
showMemoDisclaimer = true,
),
baseConfig.copy(
showMemoDisclaimer = true,
addresses = persistentListOf(
address,
address.copy(displayName = stringReference("Address 2")),
),
),
)
}
// endregion Preview

View file

@ -1,72 +0,0 @@
package com.tangem.common.ui.bottomsheet.receive
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.R
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.network.NetworkAddress
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
data class TokenReceiveBottomSheetConfig(
val asset: Asset,
val network: String,
val addresses: ImmutableList<AddressModel>,
val showMemoDisclaimer: Boolean,
val notifications: ImmutableList<NotificationConfig>,
val onCopyClick: (String) -> Unit,
val onShareClick: (String) -> Unit,
) : TangemBottomSheetConfigContent {
constructor(
asset: Asset,
network: Network,
networkAddress: NetworkAddress,
showMemoDisclaimer: Boolean,
customNotifications: ImmutableList<NotificationConfig> = persistentListOf(),
onCopyClick: (String) -> Unit,
onShareClick: (String) -> Unit,
) : this(
asset = asset,
network = network.name,
addresses = networkAddress.availableAddresses
.mapToAddressModels(asset, network)
.toImmutableList(),
showMemoDisclaimer = showMemoDisclaimer,
notifications = persistentListOf(defaultAssetNotificationConfig(asset, network)).addAll(0, customNotifications),
onCopyClick = onCopyClick,
onShareClick = onShareClick,
)
companion object {
private fun defaultAssetNotificationConfig(asset: Asset, network: Network): NotificationConfig =
NotificationConfig(
title = resourceReference(
R.string.receive_bottom_sheet_warning_title,
wrappedList(asset.displaySymbol, network.name),
),
subtitle = resourceReference(R.string.receive_bottom_sheet_warning_message_description),
iconResId = R.drawable.ic_alert_circle_24,
iconTint = NotificationConfig.IconTint.Accent,
)
}
@Immutable
sealed class Asset {
abstract val displaySymbol: TextReference
data class Currency(val name: String, val symbol: String) : Asset() {
override val displaySymbol = stringReference(symbol)
}
data object NFT : Asset() {
override val displaySymbol = resourceReference(R.string.common_nft)
}
}
}

View file

@ -47,10 +47,6 @@
"name": "TANGEM_PAY_ENABLED",
"version": "5.31.0"
},
{
"name": "NEW_TOKEN_RECEIVE_ENABLED",
"version": "5.28.0"
},
{
"name": "YIELD_SUPPLY_FEATURE_ENABLED",
"version": "5.30.0"

View file

@ -47,7 +47,6 @@ internal class TokenActionsModel @Inject constructor(
private val tokenActionsHandler: TokenActionsHandler =
tokenActionsIntentsFactory.create(
currentAppCurrency = Provider { currentAppCurrency.value },
updateTokenReceiveBSConfig = { },
onHandleQuickAction = { handledAction -> handledQuickAction(handledAction) },
)

View file

@ -39,7 +39,6 @@ import com.tangem.features.feed.components.market.details.portfolio.impl.loader.
import com.tangem.features.feed.components.market.details.portfolio.impl.ui.state.MyPortfolioUM
import com.tangem.features.feed.components.market.details.portfolio.impl.ui.state.TokenActionsBSContentUM
import com.tangem.features.feed.impl.R
import com.tangem.features.tokenreceive.TokenReceiveFeatureToggle
import com.tangem.features.wallet.utils.UserWalletImageFetcher
import com.tangem.lib.crypto.BlockchainUtils
import com.tangem.operations.attestation.ArtworkSize
@ -68,7 +67,6 @@ internal class MarketsPortfolioModel @Inject constructor(
private val saveMarketTokensUseCase: SaveMarketTokensUseCase,
private val addToPortfolioManager: AddToPortfolioManager,
private val analyticsEventHandler: AnalyticsEventHandler,
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
private val userWalletImageFetcher: UserWalletImageFetcher,
private val receiveAddressesFactory: ReceiveAddressesFactory,
accountsFeatureToggles: AccountsFeatureToggles,
@ -111,13 +109,6 @@ internal class MarketsPortfolioModel @Inject constructor(
private val tokenActionsHandler = tokenActionsIntentsFactory.create(
currentAppCurrency = Provider { currentAppCurrency.value },
updateTokenReceiveBSConfig = { updateBlock ->
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled.not()) {
updateTokensState {
it.copy(tokenReceiveBSConfig = updateBlock(it.tokenReceiveBSConfig))
}
}
},
onHandleQuickAction = { handledAction ->
analyticsEventHandler.send(
analyticsEventBuilder.quickActionClick(
@ -130,9 +121,7 @@ internal class MarketsPortfolioModel @Inject constructor(
.name,
),
)
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled) {
configureReceiveAddresses(handledAction)
}
configureReceiveAddresses(handledAction)
},
)
@ -426,8 +415,7 @@ internal class MarketsPortfolioModel @Inject constructor(
}
private fun configureReceiveAddresses(quickAction: TokenActionsHandler.HandledQuickAction) {
val isNewReceive = quickAction.action == TokenActionsBSContentUM.Action.Receive &&
tokenReceiveFeatureToggle.isNewTokenReceiveEnabled
val isNewReceive = quickAction.action == TokenActionsBSContentUM.Action.Receive
if (isNewReceive) {
modelScope.launch {
val tokenConfig = receiveAddressesFactory.create(

View file

@ -1,20 +1,16 @@
package com.tangem.features.feed.components.market.details.portfolio.impl.model
import com.tangem.common.routing.AppRoute
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.model.OnrampSource
import com.tangem.domain.redux.ReduxStateHolder
@ -36,11 +32,9 @@ internal class TokenActionsHandler @AssistedInject constructor(
private val uiMessageSender: UiMessageSender,
private val reduxStateHolder: ReduxStateHolder,
@Assisted private val currentAppCurrency: Provider<AppCurrency>,
@Assisted private val updateTokenReceiveBSConfig: ((TangemBottomSheetConfig) -> TangemBottomSheetConfig) -> Unit,
@Assisted private val onHandleQuickAction: (HandledQuickAction) -> Unit,
private val isDemoCardUseCase: IsDemoCardUseCase,
private val messageSender: UiMessageSender,
private val shareManager: ShareManager,
) {
private val disabledActionsInDemoMode = buildSet {
@ -60,7 +54,7 @@ internal class TokenActionsHandler @AssistedInject constructor(
when (action) {
TokenActionsBSContentUM.Action.Buy -> onBuyClick(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Exchange -> onExchangeClick(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Receive -> onReceiveClick(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Receive -> Unit
TokenActionsBSContentUM.Action.CopyAddress -> onCopyAddress(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Sell -> onSellClick(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Send -> onSendClick(cryptoCurrencyData)
@ -87,34 +81,6 @@ internal class TokenActionsHandler @AssistedInject constructor(
messageSender.send(message)
}
private fun onReceiveClick(cryptoCurrencyData: PortfolioData.CryptoCurrencyData) {
val cryptoCurrencyStatus = cryptoCurrencyData.status
val currency = cryptoCurrencyStatus.currency
val networkAddress = cryptoCurrencyStatus.value.networkAddress ?: return
updateTokenReceiveBSConfig {
TangemBottomSheetConfig(
isShown = true,
onDismissRequest = {
updateTokenReceiveBSConfig {
it.copy(isShown = false)
}
},
content = TokenReceiveBottomSheetConfig(
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
networkAddress = networkAddress,
showMemoDisclaimer = currency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
onCopyClick = { clipboardManager.setText(networkAddress.defaultAddress.value, isSensitive = true) },
onShareClick = { shareManager.shareText(networkAddress.defaultAddress.value) },
),
)
}
}
private fun onCopyAddress(cryptoCurrencyData: PortfolioData.CryptoCurrencyData) {
val cryptoCurrencyStatus = cryptoCurrencyData.status
val networkAddress = cryptoCurrencyStatus.value.networkAddress ?: return
@ -196,7 +162,6 @@ internal class TokenActionsHandler @AssistedInject constructor(
interface Factory {
fun create(
currentAppCurrency: Provider<AppCurrency>,
updateTokenReceiveBSConfig: ((TangemBottomSheetConfig) -> TangemBottomSheetConfig) -> Unit,
onHandleQuickAction: (HandledQuickAction) -> Unit,
): TokenActionsHandler
}

View file

@ -12,7 +12,6 @@ import com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.isZero
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlin.collections.map
/**
* Converter from [Map] of [UserWallet] and [CryptoCurrencyStatus] to [MyPortfolioUM.Tokens]
@ -50,9 +49,6 @@ internal class TokensPortfolioUMConverter(
buttonState = addButtonState,
addToPortfolioBSConfig = bsConfig,
onAddClick = onAddClick,
tokenReceiveBSConfig = (currentState() as? MyPortfolioUM.Tokens)
?.tokenReceiveBSConfig
?: TangemBottomSheetConfig.Empty,
)
}

View file

@ -16,7 +16,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachIndexed
import com.tangem.common.ui.account.AccountTitle
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheet
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.SmallButtonShimmer
@ -140,8 +139,6 @@ private fun TokenList(state: MyPortfolioUM.Tokens, modifier: Modifier = Modifier
}
}
}
TokenReceiveBottomSheet(config = state.tokenReceiveBSConfig)
}
@Composable

View file

@ -23,21 +23,18 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfol
tokens = persistentListOf(sampleToken, sampleToken),
buttonState = MyPortfolioUM.Tokens.AddButtonState.Available,
addToPortfolioBSConfig = TangemBottomSheetConfig.Empty,
tokenReceiveBSConfig = TangemBottomSheetConfig.Empty,
onAddClick = {},
),
MyPortfolioUM.Tokens(
tokens = persistentListOf(sampleToken, sampleToken.copy(isQuickActionsShown = true)),
buttonState = MyPortfolioUM.Tokens.AddButtonState.Unavailable,
addToPortfolioBSConfig = TangemBottomSheetConfig.Empty,
tokenReceiveBSConfig = TangemBottomSheetConfig.Empty,
onAddClick = {},
),
MyPortfolioUM.Tokens(
tokens = persistentListOf(sampleToken.copy(isQuickActionsShown = true), sampleToken),
buttonState = MyPortfolioUM.Tokens.AddButtonState.Loading,
addToPortfolioBSConfig = TangemBottomSheetConfig.Empty,
tokenReceiveBSConfig = TangemBottomSheetConfig.Empty,
onAddClick = {},
),
MyPortfolioUM.AddFirstToken(

View file

@ -13,7 +13,6 @@ internal sealed class MyPortfolioUM {
override val addToPortfolioBSConfig: TangemBottomSheetConfig,
val tokens: ImmutableList<PortfolioTokenUM>,
val buttonState: AddButtonState,
val tokenReceiveBSConfig: TangemBottomSheetConfig,
val onAddClick: () -> Unit,
) : MyPortfolioUM() {

View file

@ -48,7 +48,6 @@ internal class TokenActionsModel @Inject constructor(
private val tokenActionsHandler: TokenActionsHandler =
tokenActionsIntentsFactory.create(
currentAppCurrency = Provider { currentAppCurrency.value },
updateTokenReceiveBSConfig = { },
onHandleQuickAction = { handledAction -> handledQuickAction(handledAction) },
)

View file

@ -40,7 +40,6 @@ import com.tangem.features.markets.portfolio.impl.loader.PortfolioDataLoader
import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM
import com.tangem.features.markets.portfolio.impl.ui.state.MyPortfolioUM.Tokens.AddButtonState
import com.tangem.features.markets.portfolio.impl.ui.state.TokenActionsBSContentUM
import com.tangem.features.tokenreceive.TokenReceiveFeatureToggle
import com.tangem.features.wallet.utils.UserWalletImageFetcher
import com.tangem.lib.crypto.BlockchainUtils
import com.tangem.operations.attestation.ArtworkSize
@ -69,12 +68,11 @@ internal class MarketsPortfolioModel @Inject constructor(
private val saveMarketTokensUseCase: SaveMarketTokensUseCase,
private val addToPortfolioManager: AddToPortfolioManager,
private val analyticsEventHandler: AnalyticsEventHandler,
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
private val userWalletImageFetcher: UserWalletImageFetcher,
private val receiveAddressesFactory: ReceiveAddressesFactory,
private val accountsFeatureToggles: AccountsFeatureToggles,
accountsFeatureToggles: AccountsFeatureToggles,
newAddToPortfolioManagerFactory: NewAddToPortfolioManager.Factory,
private val newMarketsPortfolioDelegateFactory: NewMarketsPortfolioDelegate.Factory,
newMarketsPortfolioDelegateFactory: NewMarketsPortfolioDelegate.Factory,
) : Model() {
private val _state: MutableStateFlow<MyPortfolioUM> = MutableStateFlow(value = MyPortfolioUM.Loading)
@ -111,13 +109,6 @@ internal class MarketsPortfolioModel @Inject constructor(
private val tokenActionsHandler = tokenActionsIntentsFactory.create(
currentAppCurrency = Provider { currentAppCurrency.value },
updateTokenReceiveBSConfig = { updateBlock ->
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled.not()) {
updateTokensState {
it.copy(tokenReceiveBSConfig = updateBlock(it.tokenReceiveBSConfig))
}
}
},
onHandleQuickAction = { handledAction ->
val currencyNetwork = handledAction.cryptoCurrencyData.status.currency.network
analyticsEventHandler.send(
@ -126,9 +117,7 @@ internal class MarketsPortfolioModel @Inject constructor(
blockchainName = currencyNetwork.name,
),
)
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled) {
configureReceiveAddresses(handledAction)
}
configureReceiveAddresses(handledAction)
},
)
@ -423,8 +412,7 @@ internal class MarketsPortfolioModel @Inject constructor(
}
private fun configureReceiveAddresses(quickAction: TokenActionsHandler.HandledQuickAction) {
val isNewReceive = quickAction.action == TokenActionsBSContentUM.Action.Receive &&
tokenReceiveFeatureToggle.isNewTokenReceiveEnabled
val isNewReceive = quickAction.action == TokenActionsBSContentUM.Action.Receive
if (isNewReceive) {
modelScope.launch {
val tokenConfig = receiveAddressesFactory.create(

View file

@ -1,20 +1,16 @@
package com.tangem.features.markets.portfolio.impl.model
import com.tangem.common.routing.AppRoute
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.model.OnrampSource
import com.tangem.domain.redux.ReduxStateHolder
@ -36,11 +32,9 @@ internal class TokenActionsHandler @AssistedInject constructor(
private val uiMessageSender: UiMessageSender,
private val reduxStateHolder: ReduxStateHolder,
@Assisted private val currentAppCurrency: Provider<AppCurrency>,
@Assisted private val updateTokenReceiveBSConfig: ((TangemBottomSheetConfig) -> TangemBottomSheetConfig) -> Unit,
@Assisted private val onHandleQuickAction: (HandledQuickAction) -> Unit,
private val isDemoCardUseCase: IsDemoCardUseCase,
private val messageSender: UiMessageSender,
private val shareManager: ShareManager,
) {
private val disabledActionsInDemoMode = buildSet {
@ -60,7 +54,7 @@ internal class TokenActionsHandler @AssistedInject constructor(
when (action) {
TokenActionsBSContentUM.Action.Buy -> onBuyClick(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Exchange -> onExchangeClick(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Receive -> onReceiveClick(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Receive -> Unit
TokenActionsBSContentUM.Action.CopyAddress -> onCopyAddress(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Sell -> onSellClick(cryptoCurrencyData)
TokenActionsBSContentUM.Action.Send -> onSendClick(cryptoCurrencyData)
@ -87,34 +81,6 @@ internal class TokenActionsHandler @AssistedInject constructor(
messageSender.send(message)
}
private fun onReceiveClick(cryptoCurrencyData: PortfolioData.CryptoCurrencyData) {
val cryptoCurrencyStatus = cryptoCurrencyData.status
val currency = cryptoCurrencyStatus.currency
val networkAddress = cryptoCurrencyStatus.value.networkAddress ?: return
updateTokenReceiveBSConfig {
TangemBottomSheetConfig(
isShown = true,
onDismissRequest = {
updateTokenReceiveBSConfig {
it.copy(isShown = false)
}
},
content = TokenReceiveBottomSheetConfig(
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
networkAddress = networkAddress,
showMemoDisclaimer = currency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
onCopyClick = { clipboardManager.setText(networkAddress.defaultAddress.value, isSensitive = true) },
onShareClick = { shareManager.shareText(networkAddress.defaultAddress.value) },
),
)
}
}
private fun onCopyAddress(cryptoCurrencyData: PortfolioData.CryptoCurrencyData) {
val cryptoCurrencyStatus = cryptoCurrencyData.status
val networkAddress = cryptoCurrencyStatus.value.networkAddress ?: return
@ -196,7 +162,6 @@ internal class TokenActionsHandler @AssistedInject constructor(
interface Factory {
fun create(
currentAppCurrency: Provider<AppCurrency>,
updateTokenReceiveBSConfig: ((TangemBottomSheetConfig) -> TangemBottomSheetConfig) -> Unit,
onHandleQuickAction: (HandledQuickAction) -> Unit,
): TokenActionsHandler
}

View file

@ -50,9 +50,6 @@ internal class TokensPortfolioUMConverter(
buttonState = addButtonState,
addToPortfolioBSConfig = bsConfig,
onAddClick = onAddClick,
tokenReceiveBSConfig = (currentState() as? MyPortfolioUM.Tokens)
?.tokenReceiveBSConfig
?: TangemBottomSheetConfig.Empty,
)
}

View file

@ -16,7 +16,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachIndexed
import com.tangem.common.ui.account.AccountTitle
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheet
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.SmallButtonShimmer
@ -141,8 +140,6 @@ private fun TokenList(state: MyPortfolioUM.Tokens, modifier: Modifier = Modifier
}
}
}
TokenReceiveBottomSheet(config = state.tokenReceiveBSConfig)
}
@Composable

View file

@ -93,21 +93,18 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfol
tokens = persistentListOf(sampleToken, sampleToken),
buttonState = MyPortfolioUM.Tokens.AddButtonState.Available,
addToPortfolioBSConfig = TangemBottomSheetConfig.Empty,
tokenReceiveBSConfig = TangemBottomSheetConfig.Empty,
onAddClick = {},
),
MyPortfolioUM.Tokens(
tokens = persistentListOf(sampleToken, sampleToken.copy(isQuickActionsShown = true)),
buttonState = MyPortfolioUM.Tokens.AddButtonState.Unavailable,
addToPortfolioBSConfig = TangemBottomSheetConfig.Empty,
tokenReceiveBSConfig = TangemBottomSheetConfig.Empty,
onAddClick = {},
),
MyPortfolioUM.Tokens(
tokens = persistentListOf(sampleToken.copy(isQuickActionsShown = true), sampleToken),
buttonState = MyPortfolioUM.Tokens.AddButtonState.Loading,
addToPortfolioBSConfig = TangemBottomSheetConfig.Empty,
tokenReceiveBSConfig = TangemBottomSheetConfig.Empty,
onAddClick = {},
),
MyPortfolioUM.AddFirstToken(

View file

@ -13,7 +13,6 @@ internal sealed class MyPortfolioUM {
override val addToPortfolioBSConfig: TangemBottomSheetConfig,
val tokens: ImmutableList<PortfolioTokenUM>,
val buttonState: AddButtonState,
val tokenReceiveBSConfig: TangemBottomSheetConfig,
val onAddClick: () -> Unit,
) : MyPortfolioUM() {

View file

@ -1,49 +0,0 @@
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.core.ui.components.notifications.NotificationConfig
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.network.NetworkAddress
import com.tangem.features.nft.receive.entity.NFTReceiveUM
import com.tangem.utils.transformer.Transformer
import com.tangem.core.ui.R
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.lib.crypto.BlockchainUtils
import kotlinx.collections.immutable.toPersistentList
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,
customNotifications = buildList {
if (BlockchainUtils.isSolana(network.rawId)) {
add(
NotificationConfig(
title = resourceReference(R.string.nft_receive_unsupported_types),
subtitle = resourceReference(R.string.nft_receive_unsupported_types_description),
iconResId = R.drawable.ic_alert_circle_24,
iconTint = NotificationConfig.IconTint.Attention,
),
)
}
}.toPersistentList(),
onCopyClick = onCopyClick,
onShareClick = onShareClick,
),
),
)
}

View file

@ -8,8 +8,6 @@ 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.ui.UiMessageSender
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.TextReference
@ -37,11 +35,9 @@ import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.nft.impl.R
import com.tangem.features.nft.receive.NFTReceiveComponent
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
import com.tangem.features.tokenreceive.TokenReceiveFeatureToggle
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.*
@ -56,11 +52,8 @@ internal class NFTReceiveModel @Inject constructor(
private val getNFTNetworksUseCase: GetNFTNetworksUseCase,
private val filterNFTAvailableNetworksUseCase: FilterNFTAvailableNetworksUseCase,
private val getNFTNetworkStatusUseCase: GetNFTNetworkStatusUseCase,
private val clipboardManager: ClipboardManager,
private val shareManager: ShareManager,
private val analyticsEventHandler: AnalyticsEventHandler,
private val messageSender: UiMessageSender,
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
private val getNFTCurrencyUseCase: GetNFTCurrencyUseCase,
private val receiveAddressesFactory: ReceiveAddressesFactory,
private val getUserWalletUseCase: GetUserWalletUseCase,
@ -167,14 +160,6 @@ internal class NFTReceiveModel @Inject constructor(
}
}
private fun onReceiveBottomSheetDismiss() {
_state.update {
it.copy(
bottomSheetConfig = it.bottomSheetConfig?.copy(isShown = false),
)
}
}
private fun onNetworkClick(network: Network, enabled: Boolean) {
if (!enabled) {
val message = DialogMessage(
@ -194,24 +179,12 @@ internal class NFTReceiveModel @Inject constructor(
when (val value = networkStatus.value) {
is NetworkStatus.Verified -> {
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled) {
bottomSheetNavigation.activate(
configuration = configureReceiveAddresses(
addresses = value.address,
network = network,
),
)
} else {
_state.update {
ShowReceiveBottomSheetTransformer(
network = network,
networkAddress = value.address,
onDismissBottomSheet = ::onReceiveBottomSheetDismiss,
onCopyClick = { text -> onCopyClick(text, network) },
onShareClick = { text -> onShareClick(text, network) },
).transform(it)
}
}
bottomSheetNavigation.activate(
configuration = configureReceiveAddresses(
addresses = value.address,
network = network,
),
)
}
is NetworkStatus.MissedDerivation,
is NetworkStatus.NoAccount,
@ -222,16 +195,6 @@ internal class NFTReceiveModel @Inject constructor(
}
}
private fun onCopyClick(text: String, network: Network) {
analyticsEventHandler.send(NFTAnalyticsEvent.Receive.CopyAddress(network.name))
clipboardManager.setText(text = text, isSensitive = true)
}
private fun onShareClick(text: String, network: Network) {
analyticsEventHandler.send(NFTAnalyticsEvent.Receive.ShareAddress(network.name))
shareManager.shareText(text = text)
}
private suspend fun configureReceiveAddresses(addresses: NetworkAddress, network: Network): TokenReceiveConfig {
val cryptoCurrency = getNFTCurrencyUseCase.invoke(network)
return receiveAddressesFactory.createForNft(

View file

@ -2,14 +2,13 @@ package com.tangem.features.nft.receive.ui
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
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.resolveReference
@ -48,17 +47,4 @@ internal fun NFTReceive(state: NFTReceiveUM, modifier: Modifier = Modifier) {
is NFTReceiveUM.Networks.Empty -> NFTReceiveNetworksEmpty()
}
}
ShowBottomSheet(state.bottomSheetConfig)
}
@Composable
private fun ShowBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
if (bottomSheetConfig != null) {
when (bottomSheetConfig.content) {
is TokenReceiveBottomSheetConfig -> {
TokenReceiveBottomSheet(config = bottomSheetConfig)
}
}
}
}

View file

@ -1,6 +0,0 @@
package com.tangem.features.tokenreceive
interface TokenReceiveFeatureToggle {
val isNewTokenReceiveEnabled: Boolean
}

View file

@ -1,11 +0,0 @@
package com.tangem.features.tokenreceive
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
internal class DefaultTokenReceiveFeatureToggle(
private val featureTogglesManager: FeatureTogglesManager,
) : TokenReceiveFeatureToggle {
override val isNewTokenReceiveEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled("NEW_TOKEN_RECEIVE_ENABLED")
}

View file

@ -1,11 +1,8 @@
package com.tangem.features.tokenreceive.di
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.core.decompose.di.ModelComponent
import com.tangem.core.decompose.model.Model
import com.tangem.features.tokenreceive.DefaultTokenReceiveFeatureToggle
import com.tangem.features.tokenreceive.TokenReceiveComponent
import com.tangem.features.tokenreceive.TokenReceiveFeatureToggle
import com.tangem.features.tokenreceive.component.DefaultTokenReceiveComponent
import com.tangem.features.tokenreceive.model.TokenReceiveAssetsModel
import com.tangem.features.tokenreceive.model.TokenReceiveModel
@ -13,26 +10,12 @@ import com.tangem.features.tokenreceive.model.TokenReceiveQrCodeModel
import com.tangem.features.tokenreceive.model.TokenReceiveWarningModel
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object FeatureToggleModule {
@Provides
@Singleton
fun provideTokenReceiveFeatureToggle(featureTogglesManager: FeatureTogglesManager): TokenReceiveFeatureToggle {
return DefaultTokenReceiveFeatureToggle(
featureTogglesManager = featureTogglesManager,
)
}
}
@Module
@InstallIn(SingletonComponent::class)
internal interface ComponentModule {

View file

@ -23,7 +23,6 @@ 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.ui.UiMessageSender
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
@ -59,7 +58,10 @@ import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.tokens.model.analytics.*
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
import com.tangem.domain.tokens.model.analytics.TokenReceiveNewAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent.Companion.toReasonAnalyticsText
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent.DetailsScreenOpened.TokenBalance
import com.tangem.domain.tokens.model.details.NavigationAction
@ -87,7 +89,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.T
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.express.ExpressStatusFactory
import com.tangem.features.tokendetails.TokenDetailsComponent
import com.tangem.features.tokendetails.impl.R
import com.tangem.features.tokenreceive.TokenReceiveFeatureToggle
import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter
import com.tangem.features.yield.supply.api.YieldSupplyDepositedWarningComponent
import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
@ -133,7 +134,6 @@ internal class TokenDetailsModel @Inject constructor(
private val analyticsEventsHandler: AnalyticsEventHandler,
private val vibratorHapticManager: VibratorHapticManager,
private val clipboardManager: ClipboardManager,
private val shareManager: ShareManager,
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter,
paramsContainer: ParamsContainer,
@ -143,7 +143,6 @@ internal class TokenDetailsModel @Inject constructor(
private val router: InnerTokenDetailsRouter,
private val tokenDetailsDeepLinkActionListener: TokenDetailsDeepLinkActionListener,
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
private val receiveAddressesFactory: ReceiveAddressesFactory,
private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles,
private val saveViewedYieldSupplyWarningUseCase: SaveViewedYieldSupplyWarningUseCase,
@ -1250,28 +1249,9 @@ internal class TokenDetailsModel @Inject constructor(
}
private fun navigateToReceive() {
val networkAddress = cryptoCurrencyStatus?.value?.networkAddress ?: return
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled) {
modelScope.launch {
configureReceiveAddresses(cryptoCurrencyStatus = cryptoCurrencyStatus)
?.let { bottomSheetNavigation.activate(it) }
}
} else {
analyticsEventsHandler.send(TokenReceiveAnalyticsEvent.ReceiveScreenOpened(cryptoCurrency.symbol))
internalUiState.value = stateFactory.getStateWithReceiveBottomSheet(
currency = cryptoCurrency,
networkAddress = networkAddress,
onCopyClick = {
analyticsEventsHandler.send(TokenReceiveAnalyticsEvent.ButtonCopyAddress(cryptoCurrency.symbol))
clipboardManager.setText(text = it, isSensitive = true)
},
onShareClick = {
analyticsEventsHandler.send(
TokenReceiveAnalyticsEvent.ButtonShareAddress(cryptoCurrency.symbol),
)
shareManager.shareText(text = it)
},
)
modelScope.launch {
configureReceiveAddresses(cryptoCurrencyStatus = cryptoCurrencyStatus)
?.let { bottomSheetNavigation.activate(it) }
}
}

View file

@ -2,7 +2,6 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
import arrow.core.Either
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.tokendetails.TokenDetailsDialogConfig
import com.tangem.common.ui.tokens.getUnavailabilityReasonText
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
@ -15,7 +14,6 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.card.common.util.cardTypesResolver
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.network.NetworkAddress
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
@ -210,31 +208,6 @@ internal class TokenDetailsStateFactory(
return refreshStateConverter.convert(false)
}
fun getStateWithReceiveBottomSheet(
currency: CryptoCurrency,
networkAddress: NetworkAddress,
onCopyClick: (String) -> Unit,
onShareClick: (String) -> Unit,
): TokenDetailsState {
return currentStateProvider().copy(
bottomSheetConfig = TangemBottomSheetConfig(
isShown = true,
onDismissRequest = expressTransactionsClickIntents::onDismissBottomSheet,
content = TokenReceiveBottomSheetConfig(
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,
),
),
)
}
fun getStateWithChooseAddressBottomSheet(
currency: CryptoCurrency,
networkAddress: NetworkAddress,
@ -244,11 +217,7 @@ internal class TokenDetailsStateFactory(
isShown = true,
onDismissRequest = expressTransactionsClickIntents::onDismissBottomSheet,
content = ChooseAddressBottomSheetConfig(
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
currency = currency,
networkAddress = networkAddress,
onClick = tokenDetailsClickIntents::onAddressTypeSelected,
),

View file

@ -16,8 +16,6 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheet
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheet
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
import com.tangem.common.ui.expressStatus.expressTransactionsItems
import com.tangem.core.ui.components.containers.pullToRefresh.TangemPullToRefreshContainer
@ -169,9 +167,6 @@ internal fun TokenDetailsScreen(
state.bottomSheetConfig?.let { config ->
when (config.content) {
is TokenReceiveBottomSheetConfig -> {
TokenReceiveBottomSheet(config = config)
}
is ChooseAddressBottomSheetConfig -> {
ChooseAddressBottomSheet(config = config)
}

View file

@ -5,7 +5,6 @@ import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.AddressModel
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
import com.tangem.common.ui.tokens.getUnavailabilityReasonText
import com.tangem.core.analytics.api.AnalyticsEventHandler
@ -13,9 +12,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.WrappedList
@ -35,7 +32,6 @@ import com.tangem.domain.markets.TokenMarketParams
import com.tangem.domain.models.TokenReceiveConfig
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.network.NetworkAddress
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
@ -47,7 +43,6 @@ import com.tangem.domain.staking.model.StakingOption
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.analytics.TokenReceiveAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenReceiveCopyActionSource
import com.tangem.domain.tokens.model.analytics.TokenReceiveNewAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
@ -67,7 +62,6 @@ import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletTokensListState
import com.tangem.feature.wallet.presentation.wallet.state.transformers.CloseBottomSheetTransformer
import com.tangem.feature.wallet.presentation.wallet.state.utils.WalletEventSender
import com.tangem.features.tokenreceive.TokenReceiveFeatureToggle
import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.collections.immutable.toImmutableList
@ -144,10 +138,8 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private val reduxStateHolder: ReduxStateHolder,
private val vibratorHapticManager: VibratorHapticManager,
private val clipboardManager: ClipboardManager,
private val shareManager: ShareManager,
private val appRouter: AppRouter,
private val rampStateManager: RampStateManager,
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
private val saveViewedTokenReceiveWarningUseCase: SaveViewedTokenReceiveWarningUseCase,
private val receiveAddressesFactory: ReceiveAddressesFactory,
private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles,
@ -249,29 +241,6 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
return resourceReference(R.string.wallet_notification_address_copied)
}
private fun createReceiveBottomSheetContent(
currency: CryptoCurrency,
addresses: NetworkAddress,
): TangemBottomSheetConfigContent {
return TokenReceiveBottomSheetConfig(
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))
clipboardManager.setText(text = it, isSensitive = true)
},
onShareClick = {
analyticsEventHandler.send(TokenReceiveAnalyticsEvent.ButtonShareAddress(currency.symbol))
shareManager.shareText(text = it)
},
)
}
override fun onCopyAddressClick(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) {
analyticsEventHandler.send(
event = TokenReceiveNewAnalyticsEvent.ButtonCopyAddress(
@ -596,11 +565,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
) {
stateHolder.showBottomSheet(
ChooseAddressBottomSheetConfig(
asset = TokenReceiveBottomSheetConfig.Asset.Currency(
name = currency.name,
symbol = currency.symbol,
),
network = currency.network,
currency = currency,
networkAddress = addresses,
onClick = {
onAddressTypeSelected(
@ -768,25 +733,11 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
}
private fun navigateToReceive(cryptoCurrencyStatus: CryptoCurrencyStatus) {
val userWalletId = stateHolder.getSelectedWalletId()
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled) {
stateHolder.hideBottomSheet()
modelScope.launch {
configureReceiveAddresses(cryptoCurrencyStatus = cryptoCurrencyStatus)?.let {
router.openTokenReceiveBottomSheet(it)
}
stateHolder.hideBottomSheet()
modelScope.launch {
configureReceiveAddresses(cryptoCurrencyStatus = cryptoCurrencyStatus)?.let {
router.openTokenReceiveBottomSheet(it)
}
} else {
analyticsEventHandler.send(
event = TokenReceiveAnalyticsEvent.ReceiveScreenOpened(cryptoCurrencyStatus.currency.symbol),
)
stateHolder.showBottomSheet(
createReceiveBottomSheetContent(
currency = cryptoCurrencyStatus.currency,
addresses = cryptoCurrencyStatus.value.networkAddress ?: return,
),
userWalletId,
)
}
}

View file

@ -42,8 +42,6 @@ import androidx.compose.ui.unit.dp
import androidx.paging.compose.collectAsLazyPagingItems
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheet
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheet
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheet
import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig
import com.tangem.common.ui.expressStatus.expressTransactionsItems
@ -709,7 +707,6 @@ private fun ShowBottomSheet(bottomSheetConfig: TangemBottomSheetConfig?) {
if (bottomSheetConfig != null) {
when (bottomSheetConfig.content) {
is WalletBottomSheetConfig -> WalletBottomSheet(config = bottomSheetConfig)
is TokenReceiveBottomSheetConfig -> TokenReceiveBottomSheet(config = bottomSheetConfig)
is ActionsBottomSheetConfig -> TokenActionsBottomSheet(config = bottomSheetConfig)
is ChooseAddressBottomSheetConfig -> ChooseAddressBottomSheet(config = bottomSheetConfig)
is ExpressStatusBottomSheetConfig -> ExpressStatusBottomSheet(config = bottomSheetConfig)