Updated on 2026-08-14
This commit is contained in:
parent
18091cfea9
commit
8c9452f46c
17 changed files with 665 additions and 266 deletions
|
|
@ -5,6 +5,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository
|
|||
import com.tangem.domain.demo.models.DemoConfig
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
|
||||
import com.tangem.domain.tokens.GetViewedTokenReceiveWarningUseCase
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||
import com.tangem.domain.transaction.FeeRepository
|
||||
import com.tangem.domain.transaction.TransactionRepository
|
||||
|
|
@ -231,6 +232,18 @@ internal object TransactionDomainModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideReceiveAddressesFactory(
|
||||
getEnsNameUseCase: GetEnsNameUseCase,
|
||||
getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
|
||||
): ReceiveAddressesFactory {
|
||||
return ReceiveAddressesFactory(
|
||||
getEnsNameUseCase = getEnsNameUseCase,
|
||||
getViewedTokenReceiveWarningUseCase = getViewedTokenReceiveWarningUseCase,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetReverseResolvedEnsAddressUseCase(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
package com.tangem.domain.transaction.usecase
|
||||
|
||||
import com.tangem.domain.models.Asset
|
||||
import com.tangem.domain.models.ReceiveAddressModel
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.TokenReceiveNotification
|
||||
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.UserWalletId
|
||||
import com.tangem.domain.tokens.GetViewedTokenReceiveWarningUseCase
|
||||
import com.tangem.domain.transaction.R
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
|
||||
class ReceiveAddressesFactory(
|
||||
private val getEnsNameUseCase: GetEnsNameUseCase,
|
||||
private val getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
|
||||
) {
|
||||
|
||||
suspend fun create(
|
||||
status: CryptoCurrencyStatus,
|
||||
userWalletId: UserWalletId,
|
||||
notifications: List<TokenReceiveNotification> = emptyList(),
|
||||
): TokenReceiveConfig? {
|
||||
val addresses = status.value.networkAddress ?: return null
|
||||
val cryptoCurrency = status.currency
|
||||
|
||||
val ensName = getEnsNameUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
network = cryptoCurrency.network,
|
||||
address = addresses.defaultAddress.value,
|
||||
)
|
||||
|
||||
val receiveAddresses = buildList {
|
||||
ensName?.let { ens ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = ReceiveAddressModel.NameService.Ens,
|
||||
value = ens,
|
||||
),
|
||||
)
|
||||
}
|
||||
addresses.availableAddresses.map { address ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = when (address.type) {
|
||||
NetworkAddress.Address.Type.Primary -> ReceiveAddressModel.NameService.Default
|
||||
NetworkAddress.Address.Type.Secondary -> ReceiveAddressModel.NameService.Legacy
|
||||
},
|
||||
value = address.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
return TokenReceiveConfig(
|
||||
shouldShowWarning = cryptoCurrency.name !in getViewedTokenReceiveWarningUseCase(),
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
userWalletId = userWalletId,
|
||||
showMemoDisclaimer = cryptoCurrency.network.transactionExtrasType != Network
|
||||
.TransactionExtrasType.NONE,
|
||||
receiveAddress = receiveAddresses,
|
||||
tokenReceiveNotification = notifications,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun createForNft(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: NetworkAddress,
|
||||
network: Network,
|
||||
nft: CryptoCurrency,
|
||||
): TokenReceiveConfig {
|
||||
val cryptoCurrency = nft
|
||||
|
||||
val ensName = getEnsNameUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
address = addresses.defaultAddress.value,
|
||||
)
|
||||
|
||||
val receiveAddresses = buildList {
|
||||
ensName?.let { ens ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = ReceiveAddressModel.NameService.Ens,
|
||||
value = ens,
|
||||
),
|
||||
)
|
||||
}
|
||||
addresses.availableAddresses.map { address ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = when (address.type) {
|
||||
NetworkAddress.Address.Type.Primary -> ReceiveAddressModel.NameService.Default
|
||||
NetworkAddress.Address.Type.Secondary -> ReceiveAddressModel.NameService.Legacy
|
||||
},
|
||||
value = address.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val notifications = buildList {
|
||||
if (BlockchainUtils.isSolana(network.rawId)) {
|
||||
add(
|
||||
TokenReceiveNotification(
|
||||
title = R.string.nft_receive_unsupported_types,
|
||||
subtitle = R.string.nft_receive_unsupported_types_description,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return TokenReceiveConfig(
|
||||
shouldShowWarning = Asset.NFT.name !in getViewedTokenReceiveWarningUseCase(),
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
userWalletId = userWalletId,
|
||||
showMemoDisclaimer = false,
|
||||
receiveAddress = receiveAddresses,
|
||||
tokenReceiveNotification = notifications,
|
||||
asset = Asset.NFT,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,18 @@
|
|||
package com.tangem.features.account.archived.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.account.ArchivedAccountListComponent
|
||||
import com.tangem.features.account.archived.ArchivedAccountListModel
|
||||
import com.tangem.features.account.archived.DefaultArchivedAccountListComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface AccountArchivedModule {
|
||||
|
||||
@Binds
|
||||
fun bindArchivedAccountListComponentFactory(
|
||||
impl: DefaultArchivedAccountListComponent.Factory,
|
||||
): ArchivedAccountListComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(ArchivedAccountListModel::class)
|
||||
|
|
|
|||
|
|
@ -1,25 +1,18 @@
|
|||
package com.tangem.features.account.createedit.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.account.AccountCreateEditComponent
|
||||
import com.tangem.features.account.createedit.AccountCreateEditModel
|
||||
import com.tangem.features.account.createedit.DefaultAccountCreateEditComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface AccountCreateEditModule {
|
||||
|
||||
@Binds
|
||||
fun bindAccountCreateEditComponentFactory(
|
||||
impl: DefaultAccountCreateEditComponent.Factory,
|
||||
): AccountCreateEditComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(AccountCreateEditModel::class)
|
||||
|
|
|
|||
|
|
@ -1,25 +1,18 @@
|
|||
package com.tangem.features.account.details.di
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.account.AccountDetailsComponent
|
||||
import com.tangem.features.account.details.AccountDetailsModel
|
||||
import com.tangem.features.account.details.DefaultAccountDetailsComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface AccountDetailsModule {
|
||||
|
||||
@Binds
|
||||
fun bindAccountDetailsComponentFactory(
|
||||
impl: DefaultAccountDetailsComponent.Factory,
|
||||
): AccountDetailsComponent.Factory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(AccountDetailsModel::class)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
package com.tangem.features.account.di
|
||||
|
||||
import com.tangem.features.account.AccountCreateEditComponent
|
||||
import com.tangem.features.account.AccountDetailsComponent
|
||||
import com.tangem.features.account.ArchivedAccountListComponent
|
||||
import com.tangem.features.account.PortfolioFetcher
|
||||
import com.tangem.features.account.PortfolioSelectorComponent
|
||||
import com.tangem.features.account.PortfolioSelectorController
|
||||
import com.tangem.features.account.archived.DefaultArchivedAccountListComponent
|
||||
import com.tangem.features.account.createedit.DefaultAccountCreateEditComponent
|
||||
import com.tangem.features.account.details.DefaultAccountDetailsComponent
|
||||
import com.tangem.features.account.fetcher.DefaultPortfolioFetcher
|
||||
import com.tangem.features.account.selector.DefaultPortfolioSelectorComponent
|
||||
import com.tangem.features.account.selector.DefaultPortfolioSelectorController
|
||||
|
|
@ -25,4 +31,19 @@ internal interface AccountFeatureModule {
|
|||
fun bindPortfolioSelectorComponentFactory(
|
||||
impl: DefaultPortfolioSelectorComponent.Factory,
|
||||
): PortfolioSelectorComponent.Factory
|
||||
|
||||
@Binds
|
||||
fun bindAccountCreateEditComponentFactory(
|
||||
impl: DefaultAccountCreateEditComponent.Factory,
|
||||
): AccountCreateEditComponent.Factory
|
||||
|
||||
@Binds
|
||||
fun bindAccountDetailsComponentFactory(
|
||||
impl: DefaultAccountDetailsComponent.Factory,
|
||||
): AccountDetailsComponent.Factory
|
||||
|
||||
@Binds
|
||||
fun bindArchivedAccountListComponentFactory(
|
||||
impl: DefaultArchivedAccountListComponent.Factory,
|
||||
): ArchivedAccountListComponent.Factory
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.tangem.features.markets.portfolio.add.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.features.markets.portfolio.add.impl.model.TokenActionsModel
|
||||
import com.tangem.features.markets.portfolio.add.impl.ui.TokenActionsContent
|
||||
import com.tangem.features.markets.portfolio.impl.analytics.PortfolioAnalyticsEvent
|
||||
import com.tangem.features.markets.portfolio.impl.loader.PortfolioData
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
internal class TokenActionsComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted private val params: Params,
|
||||
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
|
||||
) : AppComponentContext by context, ComposableContentComponent {
|
||||
|
||||
private val model: TokenActionsModel = getOrCreateModel(params)
|
||||
private val bottomSheetSlot = childSlot(
|
||||
source = model.bottomSheetNavigation,
|
||||
serializer = TokenReceiveConfig.serializer(),
|
||||
handleBackButton = false,
|
||||
childFactory = ::bottomSheetChild,
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state = model.uiState.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
val tokenActionsUM = state.value ?: return
|
||||
TokenActionsContent(
|
||||
modifier = modifier,
|
||||
state = tokenActionsUM,
|
||||
)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
private fun bottomSheetChild(
|
||||
config: TokenReceiveConfig,
|
||||
componentContext: ComponentContext,
|
||||
): ComposableBottomSheetComponent = tokenReceiveComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = TokenReceiveComponent.Params(
|
||||
config = config,
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
|
||||
data class Params(
|
||||
val eventBuilder: PortfolioAnalyticsEvent.EventBuilder,
|
||||
val data: Flow<PortfolioData.CryptoCurrencyData>,
|
||||
val callbacks: Callbacks,
|
||||
)
|
||||
|
||||
interface Callbacks {
|
||||
fun onLaterClick()
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : ComponentFactory<Params, TokenActionsComponent> {
|
||||
override fun create(context: AppComponentContext, params: Params): TokenActionsComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.features.markets.portfolio.add.impl.model
|
||||
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.transaction.usecase.ReceiveAddressesFactory
|
||||
import com.tangem.features.markets.portfolio.add.impl.TokenActionsComponent
|
||||
import com.tangem.features.markets.portfolio.add.impl.ui.state.TokenActionsUM
|
||||
import com.tangem.features.markets.portfolio.impl.model.TokenActionsHandler
|
||||
import com.tangem.features.markets.portfolio.impl.model.TokenActionsHandler.HandledQuickAction
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.TokenActionsBSContentUM
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
@Suppress("LongParameterList")
|
||||
internal class TokenActionsModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
tokenActionsIntentsFactory: TokenActionsHandler.Factory,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val uiBuilder: TokenActionsUiBuilder,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val receiveAddressesFactory: ReceiveAddressesFactory,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<TokenActionsComponent.Params>()
|
||||
private val analyticsEventBuilder get() = params.eventBuilder
|
||||
private val currentAppCurrency = getSelectedAppCurrencyUseCase.invokeOrDefault()
|
||||
.stateIn(
|
||||
scope = modelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = AppCurrency.Default,
|
||||
)
|
||||
|
||||
private val tokenActionsHandler: TokenActionsHandler =
|
||||
tokenActionsIntentsFactory.create(
|
||||
currentAppCurrency = Provider { currentAppCurrency.value },
|
||||
updateTokenReceiveBSConfig = { },
|
||||
onHandleQuickAction = { handledAction -> handledQuickAction(handledAction) },
|
||||
)
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TokenReceiveConfig> = SlotNavigation()
|
||||
val uiState: StateFlow<TokenActionsUM?> = params.data
|
||||
.mapLatest { uiBuilder.build(it, tokenActionsHandler) }
|
||||
.stateIn(
|
||||
scope = modelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
private fun handledQuickAction(handledAction: HandledQuickAction) {
|
||||
val event = analyticsEventBuilder.quickActionClick(
|
||||
actionUM = handledAction.action,
|
||||
blockchainName = handledAction.cryptoCurrencyData.status.currency.network.name,
|
||||
)
|
||||
analyticsEventHandler.send(event)
|
||||
val isReceive = handledAction.action == TokenActionsBSContentUM.Action.Receive
|
||||
if (!isReceive) return
|
||||
modelScope.launch {
|
||||
val tokenConfig = receiveAddressesFactory.create(
|
||||
status = handledAction.cryptoCurrencyData.status,
|
||||
userWalletId = handledAction.cryptoCurrencyData.userWallet.walletId,
|
||||
) ?: return@launch
|
||||
bottomSheetNavigation.activate(tokenConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.features.markets.portfolio.add.impl.model
|
||||
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.features.markets.portfolio.add.impl.TokenActionsComponent
|
||||
import com.tangem.features.markets.portfolio.add.impl.ui.state.TokenActionsUM
|
||||
import com.tangem.features.markets.portfolio.impl.loader.PortfolioData
|
||||
import com.tangem.features.markets.portfolio.impl.model.PortfolioTokenUMConverter
|
||||
import com.tangem.features.markets.portfolio.impl.model.TokenActionsHandler
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class TokenActionsUiBuilder @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
) {
|
||||
private val params = paramsContainer.require<TokenActionsComponent.Params>()
|
||||
|
||||
fun build(data: PortfolioData.CryptoCurrencyData, tokenActionsHandler: TokenActionsHandler): TokenActionsUM {
|
||||
val status = data.status
|
||||
val tokenUM = TokenItemState.Content(
|
||||
id = status.currency.id.value,
|
||||
iconState = CryptoCurrencyToIconStateConverter().convert(status.currency),
|
||||
titleState = TokenItemState.TitleState.Content(stringReference(status.currency.name)),
|
||||
fiatAmountState = null,
|
||||
subtitle2State = null,
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(stringReference(status.currency.symbol)),
|
||||
onItemClick = null,
|
||||
onItemLongClick = null,
|
||||
)
|
||||
return TokenActionsUM(
|
||||
token = tokenUM,
|
||||
onLaterClick = { params.callbacks.onLaterClick() },
|
||||
quickActions = PortfolioTokenUMConverter.quickActions(data, tokenActionsHandler),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
package com.tangem.features.markets.portfolio.add.impl.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
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.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerH16
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.icons.badge.drawBadge
|
||||
import com.tangem.core.ui.components.token.TokenItem
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.haptic.TangemHapticEffect
|
||||
import com.tangem.core.ui.res.LocalHapticManager
|
||||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.markets.impl.R
|
||||
import com.tangem.features.markets.portfolio.add.impl.ui.state.TokenActionsUM
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.PortfolioTokenUM
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.QuickActionUM
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import java.util.UUID
|
||||
|
||||
@Composable
|
||||
internal fun TokenActionsContent(state: TokenActionsUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
TokenItem(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
|
||||
.background(color = TangemTheme.colors.background.action),
|
||||
state = state.token,
|
||||
isBalanceHidden = false,
|
||||
)
|
||||
|
||||
SpacerH(TangemTheme.dimens.spacing14)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(TangemTheme.dimens.radius14))
|
||||
.background(TangemTheme.colors.background.action),
|
||||
) {
|
||||
state.quickActions.actions.fastForEach {
|
||||
key(it.title) {
|
||||
ActionRow(
|
||||
state = it,
|
||||
onClick = { state.quickActions.onQuickActionClick(it) },
|
||||
onLongClick = { state.quickActions.onQuickActionLongClick(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpacerH16()
|
||||
|
||||
SecondaryButton(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
text = stringResourceSafe(R.string.common_later),
|
||||
onClick = state.onLaterClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun ActionRow(
|
||||
state: QuickActionUM,
|
||||
onClick: () -> Unit,
|
||||
onLongClick: (() -> Unit),
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val hapticManager = LocalHapticManager.current
|
||||
val onLongClickInternal = {
|
||||
hapticManager.perform(TangemHapticEffect.View.LongPress)
|
||||
onLongClick()
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.combinedClickable(
|
||||
onLongClick = onLongClickInternal.takeIf { state.longClickAvailable },
|
||||
onClick = {
|
||||
hapticManager.perform(TangemHapticEffect.View.SegmentTick)
|
||||
onClick()
|
||||
},
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12, vertical = TangemTheme.dimens.spacing15),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
val containerColor = TangemTheme.colors.background.action
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.icon.accent.copy(alpha = 0.1f),
|
||||
shape = CircleShape,
|
||||
)
|
||||
.size(36.dp)
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
if (state is QuickActionUM.Exchange && state.showBadge) {
|
||||
drawBadge(containerColor = containerColor, offset = 4.dp)
|
||||
}
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.requiredSize(TangemTheme.dimens.size16),
|
||||
imageVector = ImageVector.vectorResource(id = state.icon),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
)
|
||||
}
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing2),
|
||||
) {
|
||||
Text(
|
||||
text = state.title.resolveReference(),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = state.description.resolveReference(),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(widthDp = 360, showBackground = true)
|
||||
@Preview(widthDp = 360, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun Preview(@PreviewParameter(TokenActionsContentPreviewProvider::class) state: TokenActionsUM) {
|
||||
TangemThemePreview {
|
||||
TokenActionsContent(
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class TokenActionsContentPreviewProvider : PreviewParameterProvider<TokenActionsUM> {
|
||||
private val tokenState
|
||||
get() = TokenItemState.Content(
|
||||
id = UUID.randomUUID().toString(),
|
||||
iconState = CurrencyIconState.TokenIcon(
|
||||
url = null,
|
||||
topBadgeIconResId = R.drawable.img_eth_22,
|
||||
fallbackTint = TangemColorPalette.Black,
|
||||
fallbackBackground = TangemColorPalette.Meadow,
|
||||
isGrayscale = false,
|
||||
shouldShowCustomBadge = false,
|
||||
),
|
||||
titleState = TokenItemState.TitleState.Content(
|
||||
text = stringReference(value = "Tether"),
|
||||
),
|
||||
fiatAmountState = null,
|
||||
subtitle2State = null,
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(value = stringReference("USDT")),
|
||||
onItemClick = {},
|
||||
onItemLongClick = {},
|
||||
)
|
||||
|
||||
override val values: Sequence<TokenActionsUM>
|
||||
get() = sequenceOf(
|
||||
TokenActionsUM(
|
||||
quickActions = PortfolioTokenUM.QuickActions(
|
||||
actions = persistentListOf(
|
||||
QuickActionUM.Buy,
|
||||
QuickActionUM.Exchange(showBadge = true),
|
||||
QuickActionUM.Receive,
|
||||
),
|
||||
onQuickActionClick = {},
|
||||
onQuickActionLongClick = {},
|
||||
),
|
||||
token = tokenState,
|
||||
onLaterClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.markets.portfolio.add.impl.ui.state
|
||||
|
||||
import com.tangem.core.ui.components.token.state.TokenItemState
|
||||
import com.tangem.features.markets.portfolio.impl.ui.state.PortfolioTokenUM
|
||||
|
||||
internal data class TokenActionsUM(
|
||||
val token: TokenItemState,
|
||||
val quickActions: PortfolioTokenUM.QuickActions,
|
||||
val onLaterClick: () -> Unit,
|
||||
)
|
||||
|
|
@ -2,9 +2,9 @@ package com.tangem.features.markets.portfolio.impl.model
|
|||
|
||||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
|
|
@ -22,16 +22,13 @@ import com.tangem.domain.managetokens.CheckCurrencyUnsupportedUseCase
|
|||
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
|
||||
import com.tangem.domain.markets.SaveMarketTokensUseCase
|
||||
import com.tangem.domain.markets.TokenMarketInfo
|
||||
import com.tangem.domain.models.ReceiveAddressModel
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
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
|
||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.domain.tokens.GetViewedTokenReceiveWarningUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetEnsNameUseCase
|
||||
import com.tangem.domain.transaction.usecase.ReceiveAddressesFactory
|
||||
import com.tangem.domain.wallets.usecase.ColdWalletAndHasMissedDerivationsUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
|
||||
import com.tangem.features.markets.impl.R
|
||||
|
|
@ -70,9 +67,8 @@ internal class MarketsPortfolioModel @Inject constructor(
|
|||
private val addToPortfolioManager: AddToPortfolioManager,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
|
||||
private val getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
|
||||
private val getEnsNameUseCase: GetEnsNameUseCase,
|
||||
private val userWalletImageFetcher: UserWalletImageFetcher,
|
||||
private val receiveAddressesFactory: ReceiveAddressesFactory,
|
||||
) : Model() {
|
||||
|
||||
val state: StateFlow<MyPortfolioUM> get() = _state
|
||||
|
|
@ -374,50 +370,16 @@ internal class MarketsPortfolioModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun configureReceiveAddresses(quickAction: TokenActionsHandler.HandledQuickAction) {
|
||||
when (quickAction.action) {
|
||||
TokenActionsBSContentUM.Action.Receive -> {
|
||||
val addresses = quickAction.cryptoCurrencyData.status.value.networkAddress ?: return
|
||||
val cryptoCurrency = quickAction.cryptoCurrencyData.status.currency
|
||||
modelScope.launch {
|
||||
val ensName = getEnsNameUseCase.invoke(
|
||||
userWalletId = quickAction.cryptoCurrencyData.userWallet.walletId,
|
||||
network = cryptoCurrency.network,
|
||||
address = addresses.defaultAddress.value,
|
||||
)
|
||||
|
||||
val receiveAddresses = buildList {
|
||||
ensName?.let { ens ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = ReceiveAddressModel.NameService.Ens,
|
||||
value = ens,
|
||||
),
|
||||
)
|
||||
}
|
||||
addresses.availableAddresses.map { address ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = when (address.type) {
|
||||
NetworkAddress.Address.Type.Primary -> ReceiveAddressModel.NameService.Default
|
||||
NetworkAddress.Address.Type.Secondary -> ReceiveAddressModel.NameService.Legacy
|
||||
},
|
||||
value = address.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
val tokenConfig = TokenReceiveConfig(
|
||||
shouldShowWarning = cryptoCurrency.name !in getViewedTokenReceiveWarningUseCase(),
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
userWalletId = quickAction.cryptoCurrencyData.userWallet.walletId,
|
||||
showMemoDisclaimer = cryptoCurrency.network.transactionExtrasType != Network
|
||||
.TransactionExtrasType.NONE,
|
||||
receiveAddress = receiveAddresses,
|
||||
)
|
||||
bottomSheetNavigation.activate(tokenConfig)
|
||||
}
|
||||
val isNewReceive = quickAction.action == TokenActionsBSContentUM.Action.Receive &&
|
||||
tokenReceiveFeatureToggle.isNewTokenReceiveEnabled
|
||||
if (isNewReceive) {
|
||||
modelScope.launch {
|
||||
val tokenConfig = receiveAddressesFactory.create(
|
||||
status = quickAction.cryptoCurrencyData.status,
|
||||
userWalletId = quickAction.cryptoCurrencyData.userWallet.walletId,
|
||||
) ?: return@launch
|
||||
bottomSheetNavigation.activate(tokenConfig)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,55 +42,60 @@ internal class PortfolioTokenUMConverter(
|
|||
walletId = value.userWallet.walletId,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
isQuickActionsShown = false,
|
||||
quickActions = quickActions(cryptoData = value),
|
||||
quickActions = quickActions(cryptoData = value, tokenActionsHandler = tokenActionsHandler),
|
||||
)
|
||||
}
|
||||
|
||||
private fun quickActions(cryptoData: PortfolioData.CryptoCurrencyData): PortfolioTokenUM.QuickActions {
|
||||
return PortfolioTokenUM.QuickActions(
|
||||
actions = toQuickActions(cryptoData.actions),
|
||||
onQuickActionClick = {
|
||||
when (it) {
|
||||
QuickActionUM.Buy -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Buy,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
is QuickActionUM.Exchange -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Exchange,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
QuickActionUM.Receive -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Receive,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
QuickActionUM.Stake -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Stake,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
}
|
||||
},
|
||||
onQuickActionLongClick = {
|
||||
if (it == QuickActionUM.Receive) {
|
||||
tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.CopyAddress,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun toQuickActions(actions: List<TokenActionsState.ActionState>) = buildList {
|
||||
actions.forEach { action ->
|
||||
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
||||
when (action) {
|
||||
is TokenActionsState.ActionState.Buy -> QuickActionUM.Buy
|
||||
is TokenActionsState.ActionState.Swap -> QuickActionUM.Exchange(showBadge = action.showBadge)
|
||||
is TokenActionsState.ActionState.Receive -> QuickActionUM.Receive
|
||||
is TokenActionsState.ActionState.Stake -> QuickActionUM.Stake
|
||||
else -> null
|
||||
}?.let(::add)
|
||||
}
|
||||
companion object {
|
||||
fun quickActions(
|
||||
cryptoData: PortfolioData.CryptoCurrencyData,
|
||||
tokenActionsHandler: TokenActionsHandler,
|
||||
): PortfolioTokenUM.QuickActions {
|
||||
return PortfolioTokenUM.QuickActions(
|
||||
actions = toQuickActions(cryptoData.actions),
|
||||
onQuickActionClick = {
|
||||
when (it) {
|
||||
QuickActionUM.Buy -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Buy,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
is QuickActionUM.Exchange -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Exchange,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
QuickActionUM.Receive -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Receive,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
QuickActionUM.Stake -> tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.Stake,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
}
|
||||
},
|
||||
onQuickActionLongClick = {
|
||||
if (it == QuickActionUM.Receive) {
|
||||
tokenActionsHandler.handle(
|
||||
action = TokenActionsBSContentUM.Action.CopyAddress,
|
||||
cryptoCurrencyData = cryptoData,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}.toImmutableList()
|
||||
|
||||
private fun toQuickActions(actions: List<TokenActionsState.ActionState>) = buildList {
|
||||
actions.forEach { action ->
|
||||
if (action.unavailabilityReason == ScenarioUnavailabilityReason.None) {
|
||||
when (action) {
|
||||
is TokenActionsState.ActionState.Buy -> QuickActionUM.Buy
|
||||
is TokenActionsState.ActionState.Swap -> QuickActionUM.Exchange(showBadge = action.showBadge)
|
||||
is TokenActionsState.ActionState.Receive -> QuickActionUM.Receive
|
||||
is TokenActionsState.ActionState.Stake -> QuickActionUM.Stake
|
||||
else -> null
|
||||
}?.let(::add)
|
||||
}
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
|
@ -14,10 +14,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.domain.models.Asset
|
||||
import com.tangem.domain.models.ReceiveAddressModel
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.TokenReceiveNotification
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.domain.models.network.NetworkStatus
|
||||
|
|
@ -26,8 +23,7 @@ import com.tangem.domain.nft.GetNFTCurrencyUseCase
|
|||
import com.tangem.domain.nft.GetNFTNetworkStatusUseCase
|
||||
import com.tangem.domain.nft.GetNFTNetworksUseCase
|
||||
import com.tangem.domain.nft.analytics.NFTAnalyticsEvent
|
||||
import com.tangem.domain.tokens.GetViewedTokenReceiveWarningUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetEnsNameUseCase
|
||||
import com.tangem.domain.transaction.usecase.ReceiveAddressesFactory
|
||||
import com.tangem.features.nft.impl.R
|
||||
import com.tangem.features.nft.receive.NFTReceiveComponent
|
||||
import com.tangem.features.nft.receive.entity.NFTReceiveUM
|
||||
|
|
@ -36,7 +32,6 @@ import com.tangem.features.nft.receive.entity.transformer.ToggleSearchBarTransfo
|
|||
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.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -56,9 +51,8 @@ internal class NFTReceiveModel @Inject constructor(
|
|||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val messageSender: UiMessageSender,
|
||||
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
|
||||
private val getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
|
||||
private val getEnsNameUseCase: GetEnsNameUseCase,
|
||||
private val getNFTCurrencyUseCase: GetNFTCurrencyUseCase,
|
||||
private val receiveAddressesFactory: ReceiveAddressesFactory,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
|
|
@ -196,54 +190,11 @@ internal class NFTReceiveModel @Inject constructor(
|
|||
|
||||
private suspend fun configureReceiveAddresses(addresses: NetworkAddress, network: Network): TokenReceiveConfig {
|
||||
val cryptoCurrency = getNFTCurrencyUseCase.invoke(network)
|
||||
|
||||
val ensName = getEnsNameUseCase.invoke(
|
||||
return receiveAddressesFactory.createForNft(
|
||||
userWalletId = params.userWalletId,
|
||||
addresses = addresses,
|
||||
network = network,
|
||||
address = addresses.defaultAddress.value,
|
||||
)
|
||||
|
||||
val receiveAddresses = buildList {
|
||||
ensName?.let { ens ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = ReceiveAddressModel.NameService.Ens,
|
||||
value = ens,
|
||||
),
|
||||
)
|
||||
}
|
||||
addresses.availableAddresses.map { address ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = when (address.type) {
|
||||
NetworkAddress.Address.Type.Primary -> ReceiveAddressModel.NameService.Default
|
||||
NetworkAddress.Address.Type.Secondary -> ReceiveAddressModel.NameService.Legacy
|
||||
},
|
||||
value = address.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val notifications = buildList {
|
||||
if (BlockchainUtils.isSolana(network.rawId)) {
|
||||
add(
|
||||
TokenReceiveNotification(
|
||||
title = R.string.nft_receive_unsupported_types,
|
||||
subtitle = R.string.nft_receive_unsupported_types_description,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return TokenReceiveConfig(
|
||||
shouldShowWarning = Asset.NFT.name !in getViewedTokenReceiveWarningUseCase(),
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
userWalletId = params.userWalletId,
|
||||
showMemoDisclaimer = false,
|
||||
receiveAddress = receiveAddresses,
|
||||
tokenReceiveNotification = notifications,
|
||||
asset = Asset.NFT,
|
||||
nft = cryptoCurrency,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -47,8 +47,8 @@ internal class AccountAwardConverter(
|
|||
id = currency.id.value,
|
||||
iconState = CryptoCurrencyToIconStateConverter().convert(currency),
|
||||
titleState = TokenItemState.TitleState.Content(stringReference(currency.name)),
|
||||
fiatAmountState = TokenItemState.FiatAmountState.Content(text = ""),
|
||||
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = ""),
|
||||
fiatAmountState = null,
|
||||
subtitle2State = null,
|
||||
subtitleState = TokenItemState.SubtitleState.TextContent(stringReference(currency.symbol)),
|
||||
onItemClick = null,
|
||||
onItemLongClick = null,
|
||||
|
|
|
|||
|
|
@ -36,12 +36,9 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.models.ReceiveAddressModel
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.TokenReceiveNotification
|
||||
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
|
||||
|
|
@ -139,8 +136,7 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val tokenDetailsDeepLinkActionListener: TokenDetailsDeepLinkActionListener,
|
||||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
|
||||
private val getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
|
||||
private val getEnsNameUseCase: GetEnsNameUseCase,
|
||||
private val receiveAddressesFactory: ReceiveAddressesFactory,
|
||||
private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles,
|
||||
private val saveViewedYieldSupplyWarningUseCase: SaveViewedYieldSupplyWarningUseCase,
|
||||
private val saveViewedTokenReceiveWarningUseCase: SaveViewedTokenReceiveWarningUseCase,
|
||||
|
|
@ -1058,34 +1054,10 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private suspend fun configureReceiveAddresses(addresses: NetworkAddress): TokenDetailsBottomSheetConfig {
|
||||
val ensName = getEnsNameUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
network = cryptoCurrency.network,
|
||||
address = addresses.defaultAddress.value,
|
||||
)
|
||||
|
||||
val receiveAddresses = buildList {
|
||||
ensName?.let { ens ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = ReceiveAddressModel.NameService.Ens,
|
||||
value = ens,
|
||||
),
|
||||
)
|
||||
}
|
||||
addresses.availableAddresses.map { address ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = when (address.type) {
|
||||
NetworkAddress.Address.Type.Primary -> ReceiveAddressModel.NameService.Default
|
||||
NetworkAddress.Address.Type.Secondary -> ReceiveAddressModel.NameService.Legacy
|
||||
},
|
||||
value = address.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
private suspend fun configureReceiveAddresses(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
): TokenDetailsBottomSheetConfig? {
|
||||
cryptoCurrencyStatus ?: return null
|
||||
|
||||
val notifications = buildList {
|
||||
if (isActiveYieldSupply()) {
|
||||
|
|
@ -1099,16 +1071,13 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
return TokenDetailsBottomSheetConfig.Receive(
|
||||
TokenReceiveConfig(
|
||||
shouldShowWarning = cryptoCurrency.name !in getViewedTokenReceiveWarningUseCase(),
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
userWalletId = userWalletId,
|
||||
showMemoDisclaimer = cryptoCurrency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
|
||||
tokenReceiveNotification = notifications,
|
||||
receiveAddress = receiveAddresses,
|
||||
),
|
||||
)
|
||||
val receiveConfig = receiveAddressesFactory.create(
|
||||
status = cryptoCurrencyStatus,
|
||||
userWalletId = userWalletId,
|
||||
notifications = notifications,
|
||||
) ?: return null
|
||||
|
||||
return TokenDetailsBottomSheetConfig.Receive(receiveConfig)
|
||||
}
|
||||
|
||||
private fun sendOneTimeBalanceLoadedAnalyticsEvent(cryptoCurrencyStatus: CryptoCurrencyStatus?) {
|
||||
|
|
@ -1186,9 +1155,8 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
val networkAddress = cryptoCurrencyStatus?.value?.networkAddress ?: return
|
||||
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled) {
|
||||
modelScope.launch {
|
||||
bottomSheetNavigation.activate(
|
||||
configuration = configureReceiveAddresses(addresses = networkAddress),
|
||||
)
|
||||
configureReceiveAddresses(cryptoCurrencyStatus = cryptoCurrencyStatus)
|
||||
?.let { bottomSheetNavigation.activate(it) }
|
||||
}
|
||||
} else {
|
||||
analyticsEventsHandler.send(TokenReceiveAnalyticsEvent.ReceiveScreenOpened(cryptoCurrency.symbol))
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import com.tangem.domain.core.utils.lceError
|
|||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.exchange.RampStateManager
|
||||
import com.tangem.domain.markets.TokenMarketParams
|
||||
import com.tangem.domain.models.ReceiveAddressModel
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
|
|
@ -52,7 +51,7 @@ import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
|
|||
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent.Companion.AVAILABLE
|
||||
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent.Companion.toReasonAnalyticsText
|
||||
import com.tangem.domain.tokens.model.details.TokenAction
|
||||
import com.tangem.domain.transaction.usecase.GetEnsNameUseCase
|
||||
import com.tangem.domain.transaction.usecase.ReceiveAddressesFactory
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
|
|
@ -145,9 +144,8 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
private val appRouter: AppRouter,
|
||||
private val rampStateManager: RampStateManager,
|
||||
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
|
||||
private val getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
|
||||
private val saveViewedTokenReceiveWarningUseCase: SaveViewedTokenReceiveWarningUseCase,
|
||||
private val getEnsNameUseCase: GetEnsNameUseCase,
|
||||
private val receiveAddressesFactory: ReceiveAddressesFactory,
|
||||
private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles,
|
||||
private val needShowYieldSupplyDepositedWarningUseCase: NeedShowYieldSupplyDepositedWarningUseCase,
|
||||
private val saveViewedYieldSupplyWarningUseCase: SaveViewedYieldSupplyWarningUseCase,
|
||||
|
|
@ -708,44 +706,10 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun configureReceiveAddresses(cryptoCurrencyStatus: CryptoCurrencyStatus): TokenReceiveConfig? {
|
||||
val networkAddress = cryptoCurrencyStatus.value.networkAddress ?: return null
|
||||
val userWalletId = stateHolder.getSelectedWalletId()
|
||||
|
||||
val ensName = getEnsNameUseCase.invoke(
|
||||
return receiveAddressesFactory.create(
|
||||
status = cryptoCurrencyStatus,
|
||||
userWalletId = userWalletId,
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
address = networkAddress.defaultAddress.value,
|
||||
)
|
||||
|
||||
val receiveAddresses = buildList {
|
||||
ensName?.let { ens ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = ReceiveAddressModel.NameService.Ens,
|
||||
value = ens,
|
||||
),
|
||||
)
|
||||
}
|
||||
networkAddress.availableAddresses.map { address ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = when (address.type) {
|
||||
NetworkAddress.Address.Type.Primary -> ReceiveAddressModel.NameService.Default
|
||||
NetworkAddress.Address.Type.Secondary -> ReceiveAddressModel.NameService.Legacy
|
||||
},
|
||||
value = address.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return TokenReceiveConfig(
|
||||
shouldShowWarning = cryptoCurrencyStatus.currency.name !in getViewedTokenReceiveWarningUseCase(),
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
userWalletId = userWalletId,
|
||||
showMemoDisclaimer = cryptoCurrencyStatus.currency.network.transactionExtrasType != Network
|
||||
.TransactionExtrasType.NONE,
|
||||
receiveAddress = receiveAddresses,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue