Updated on 2026-08-14
This commit is contained in:
parent
f0de027151
commit
33fd5a927a
21 changed files with 825 additions and 20 deletions
|
|
@ -16,6 +16,7 @@ dependencies {
|
|||
api(projects.features.markets.api)
|
||||
api(projects.features.onramp.api)
|
||||
api(projects.features.sendV2.api)
|
||||
api(projects.features.tokenRecieve.api)
|
||||
|
||||
/* Data */
|
||||
implementation(projects.data.common)
|
||||
|
|
@ -39,6 +40,7 @@ dependencies {
|
|||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.settings)
|
||||
implementation(projects.domain.notifications.models)
|
||||
implementation(projects.domain.transaction)
|
||||
|
||||
// FIXME [REDACTED_TASK_KEY]
|
||||
// Remove the "Buy" and "Sell" actions from the redux middleware.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ android {
|
|||
dependencies {
|
||||
/** Api */
|
||||
implementation(projects.features.nft.api)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
|
||||
/** Core modules */
|
||||
implementation(projects.core.configToggles)
|
||||
|
|
@ -34,6 +35,8 @@ dependencies {
|
|||
implementation(projects.domain.nft.models)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.transaction)
|
||||
implementation(projects.domain.tokens)
|
||||
|
||||
/** Common */
|
||||
implementation(projects.common.ui)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ dependencies {
|
|||
implementation(projects.features.manageTokens.api)
|
||||
implementation(projects.features.biometry.api)
|
||||
implementation(projects.features.hotWallet.api)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
|
||||
/** Core modules */
|
||||
implementation(projects.core.configToggles)
|
||||
|
|
@ -49,6 +50,7 @@ dependencies {
|
|||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.onramp)
|
||||
implementation(projects.domain.transaction)
|
||||
|
||||
/** Tangem libraries */
|
||||
implementation(projects.libs.tangemSdkApi)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.features.tokenreceive
|
||||
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
|
||||
interface TokenReceiveComponent : ComposableBottomSheetComponent {
|
||||
|
||||
data class Params(
|
||||
val config: TokenReceiveConfig,
|
||||
val onDismiss: () -> Unit,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, TokenReceiveComponent> {
|
||||
override fun create(context: AppComponentContext, params: Params): TokenReceiveComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@ dependencies {
|
|||
implementation(projects.domain.transaction)
|
||||
implementation(projects.domain.transaction.models)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
|
||||
/** Feature Apis */
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,197 @@
|
|||
package com.tangem.features.tokenreceive.component
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.stack.ChildStack
|
||||
import com.arkivanov.decompose.router.stack.childStack
|
||||
import com.arkivanov.decompose.router.stack.pop
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.decompose.navigation.inner.InnerRouter
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import com.tangem.features.tokenreceive.model.TokenReceiveModel
|
||||
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveContent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultTokenReceiveComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: TokenReceiveComponent.Params,
|
||||
) : TokenReceiveComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: TokenReceiveModel = getOrCreateModel(params)
|
||||
private val innerRouter = InnerRouter<TokenReceiveRoutes>(
|
||||
stackNavigation = model.stackNavigation,
|
||||
popCallback = { onChildBack() },
|
||||
)
|
||||
|
||||
private val contentStack = childStack(
|
||||
key = "TokenReceiveFlowStack",
|
||||
source = model.stackNavigation,
|
||||
serializer = TokenReceiveRoutes.serializer(),
|
||||
initialConfiguration = getInitialConfig(model.params.config.shouldShowWarning),
|
||||
handleBackButton = false,
|
||||
childFactory = ::screenChild,
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val content by contentStack.subscribeAsState()
|
||||
val currentRoute = content.active.configuration
|
||||
|
||||
TokenReceiveContentSheet(
|
||||
route = currentRoute,
|
||||
onCloseClick = ::dismiss,
|
||||
onBackClick = ::onChildBack,
|
||||
contentStack = content,
|
||||
)
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
model.params.onDismiss()
|
||||
}
|
||||
|
||||
private fun onChildBack() {
|
||||
when (contentStack.value.active.configuration) {
|
||||
is TokenReceiveRoutes.QrCode -> model.stackNavigation.pop()
|
||||
TokenReceiveRoutes.ReceiveAssets,
|
||||
TokenReceiveRoutes.Warning,
|
||||
-> dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun screenChild(
|
||||
config: TokenReceiveRoutes,
|
||||
componentContext: ComponentContext,
|
||||
): ComposableContentComponent {
|
||||
val appComponentContext = childByContext(
|
||||
componentContext = componentContext,
|
||||
router = innerRouter,
|
||||
)
|
||||
return when (config) {
|
||||
is TokenReceiveRoutes.QrCode -> TokenReceiveQrCodeComponent(
|
||||
appComponentContext = appComponentContext,
|
||||
params = TokenReceiveQrCodeComponent.TokenReceiveQrCodeParams(
|
||||
network = model.params.config.cryptoCurrency.network.name,
|
||||
address = model.state.value.addresses[config.addressId] ?: error("Address has to be there"),
|
||||
callback = model,
|
||||
onDismiss = ::dismiss,
|
||||
id = config.addressId,
|
||||
),
|
||||
)
|
||||
TokenReceiveRoutes.ReceiveAssets -> TokenReceiveAssetsComponent(
|
||||
appComponentContext = appComponentContext,
|
||||
params = TokenReceiveAssetsComponent.TokenReceiveAssetsParams(
|
||||
addresses = model.state.value.addresses,
|
||||
callback = model,
|
||||
onDismiss = ::dismiss,
|
||||
notificationConfigs = model.state.value.notificationConfigs,
|
||||
showMemoDisclaimer = model.params.config.showMemoDisclaimer,
|
||||
fullName = model.params.config.cryptoCurrency.network.name,
|
||||
),
|
||||
)
|
||||
TokenReceiveRoutes.Warning -> TokenReceiveWarningComponent(
|
||||
appComponentContext = appComponentContext,
|
||||
params = TokenReceiveWarningComponent.TokenReceiveWarningParams(
|
||||
iconState = model.state.value.iconState,
|
||||
callback = model,
|
||||
onDismiss = ::dismiss,
|
||||
network = model.params.config.cryptoCurrency.network,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInitialConfig(shouldShowWarning: Boolean): TokenReceiveRoutes {
|
||||
return if (shouldShowWarning) {
|
||||
TokenReceiveRoutes.Warning
|
||||
} else {
|
||||
TokenReceiveRoutes.ReceiveAssets
|
||||
}
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : TokenReceiveComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: TokenReceiveComponent.Params,
|
||||
): DefaultTokenReceiveComponent
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun TokenReceiveContentSheet(
|
||||
route: TokenReceiveRoutes,
|
||||
onCloseClick: () -> Unit,
|
||||
onBackClick: () -> Unit,
|
||||
contentStack: ChildStack<TokenReceiveRoutes, ComposableContentComponent>,
|
||||
) {
|
||||
TangemModalBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = onCloseClick,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
),
|
||||
onBack = onBackClick,
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
title = {
|
||||
Title(
|
||||
route = route,
|
||||
onBackClick = onBackClick,
|
||||
onCloseClick = onCloseClick,
|
||||
)
|
||||
},
|
||||
content = {
|
||||
TokenReceiveContent(
|
||||
stackState = contentStack,
|
||||
modifier = Modifier,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Title(route: TokenReceiveRoutes, onBackClick: () -> Unit, onCloseClick: () -> Unit) {
|
||||
when (route) {
|
||||
is TokenReceiveRoutes.QrCode -> {
|
||||
TangemModalBottomSheetTitle(
|
||||
startIconRes = R.drawable.ic_back_24,
|
||||
onStartClick = onBackClick,
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = onCloseClick,
|
||||
)
|
||||
}
|
||||
TokenReceiveRoutes.ReceiveAssets -> {
|
||||
TangemModalBottomSheetTitle(
|
||||
title = resourceReference(R.string.domain_receive_assets_navigation_title),
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = onCloseClick,
|
||||
)
|
||||
}
|
||||
TokenReceiveRoutes.Warning -> {
|
||||
TangemModalBottomSheetTitle(
|
||||
endIconRes = R.drawable.ic_close_24,
|
||||
onEndClick = onCloseClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal interface TokenReceiveModelCallback :
|
||||
TokenReceiveAssetsComponent.TokenReceiveAssetsModelCallback,
|
||||
TokenReceiveQrCodeComponent.TokenReceiveQrCodeModelCallback,
|
||||
TokenReceiveWarningComponent.TokenReceiveWarningModelCallback
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tangem.features.tokenreceive.component
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||
import com.tangem.features.tokenreceive.model.TokenReceiveAssetsModel
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveAssetsContent
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
|
||||
internal class TokenReceiveAssetsComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
private val params: TokenReceiveAssetsParams,
|
||||
) : AppComponentContext by appComponentContext, ComposableContentComponent {
|
||||
|
||||
private val model: TokenReceiveAssetsModel = getOrCreateModel(params = params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
TokenReceiveAssetsContent(assetsUM = state)
|
||||
}
|
||||
|
||||
internal interface TokenReceiveAssetsModelCallback {
|
||||
fun onQrCodeClick(id: Int)
|
||||
fun onCopyClick(id: Int)
|
||||
}
|
||||
|
||||
data class TokenReceiveAssetsParams(
|
||||
val notificationConfigs: ImmutableList<NotificationUM>,
|
||||
val addresses: ImmutableMap<Int, ReceiveAddress>,
|
||||
val callback: TokenReceiveAssetsModelCallback,
|
||||
val onDismiss: () -> Unit,
|
||||
val showMemoDisclaimer: Boolean,
|
||||
val fullName: String,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.features.tokenreceive.component
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||
import com.tangem.features.tokenreceive.model.TokenReceiveQrCodeModel
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveQrCodeContent
|
||||
|
||||
internal class TokenReceiveQrCodeComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
private val params: TokenReceiveQrCodeParams,
|
||||
) : AppComponentContext by appComponentContext, ComposableContentComponent {
|
||||
|
||||
private val model: TokenReceiveQrCodeModel = getOrCreateModel(params = params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
TokenReceiveQrCodeContent(qrCodeUM = state)
|
||||
}
|
||||
|
||||
internal interface TokenReceiveQrCodeModelCallback {
|
||||
fun onCopyClick(id: Int)
|
||||
fun onShareClick(address: String)
|
||||
}
|
||||
|
||||
data class TokenReceiveQrCodeParams(
|
||||
val id: Int,
|
||||
val network: String,
|
||||
val address: ReceiveAddress,
|
||||
val callback: TokenReceiveQrCodeModelCallback,
|
||||
val onDismiss: () -> Unit,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.features.tokenreceive.component
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.features.tokenreceive.model.TokenReceiveWarningModel
|
||||
import com.tangem.features.tokenreceive.ui.TokenReceiveWarningContent
|
||||
|
||||
internal class TokenReceiveWarningComponent(
|
||||
appComponentContext: AppComponentContext,
|
||||
private val params: TokenReceiveWarningParams,
|
||||
) : AppComponentContext by appComponentContext, ComposableContentComponent {
|
||||
|
||||
private val model: TokenReceiveWarningModel = getOrCreateModel(params = params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
TokenReceiveWarningContent(warningUM = state)
|
||||
}
|
||||
|
||||
internal interface TokenReceiveWarningModelCallback {
|
||||
fun onWarningAcknowledged()
|
||||
}
|
||||
|
||||
data class TokenReceiveWarningParams(
|
||||
val iconState: CurrencyIconState,
|
||||
val callback: TokenReceiveWarningModelCallback,
|
||||
val onDismiss: () -> Unit,
|
||||
val network: Network,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
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
|
||||
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 {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindComponent(factory: DefaultTokenReceiveComponent.Factory): TokenReceiveComponent.Factory
|
||||
}
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface ModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(TokenReceiveModel::class)
|
||||
fun bindsTokenReceiveModel(model: TokenReceiveModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(TokenReceiveAssetsModel::class)
|
||||
fun bindsTokenReceiveAssetsModel(model: TokenReceiveAssetsModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(TokenReceiveQrCodeModel::class)
|
||||
fun bindsTokenReceiveQrCodeModel(model: TokenReceiveQrCodeModel): Model
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(TokenReceiveWarningModel::class)
|
||||
fun bindsTokenReceiveWarningModel(model: TokenReceiveWarningModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.features.tokenreceive.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.features.tokenreceive.component.TokenReceiveAssetsComponent
|
||||
import com.tangem.features.tokenreceive.ui.state.ReceiveAssetsUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class TokenReceiveAssetsModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<TokenReceiveAssetsComponent.TokenReceiveAssetsParams>()
|
||||
|
||||
internal val state: StateFlow<ReceiveAssetsUM>
|
||||
field = MutableStateFlow<ReceiveAssetsUM>(
|
||||
ReceiveAssetsUM(
|
||||
onCopyClick = params.callback::onCopyClick,
|
||||
onOpenQrCodeClick = params.callback::onQrCodeClick,
|
||||
addresses = params.addresses,
|
||||
showMemoDisclaimer = params.showMemoDisclaimer,
|
||||
isEnsResultLoading = false,
|
||||
notificationConfigs = params.notificationConfigs,
|
||||
fullName = params.fullName,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
package com.tangem.features.tokenreceive.model
|
||||
|
||||
import com.arkivanov.decompose.router.stack.StackNavigation
|
||||
import com.arkivanov.decompose.router.stack.push
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
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.navigation.share.ShareManager
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.components.notifications.NotificationConfig
|
||||
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.Asset
|
||||
import com.tangem.domain.models.ReceiveAddressModel
|
||||
import com.tangem.domain.models.ens.EnsAddress
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.tokens.SaveViewedTokenReceiveWarningUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetReverseResolvedEnsAddressUseCase
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import com.tangem.features.tokenreceive.component.TokenReceiveModelCallback
|
||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||
import com.tangem.features.tokenreceive.route.TokenReceiveRoutes
|
||||
import com.tangem.features.tokenreceive.ui.state.TokenReceiveUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentMap
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class TokenReceiveModel @Inject constructor(
|
||||
private val clipboardManager: ClipboardManager,
|
||||
private val shareManager: ShareManager,
|
||||
private val getReverseResolvedEnsAddressUseCase: GetReverseResolvedEnsAddressUseCase,
|
||||
private val saveViewedTokenReceiveWarningUseCase: SaveViewedTokenReceiveWarningUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model(), TokenReceiveModelCallback {
|
||||
|
||||
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
|
||||
|
||||
val params = paramsContainer.require<TokenReceiveComponent.Params>()
|
||||
|
||||
val stackNavigation = StackNavigation<TokenReceiveRoutes>()
|
||||
|
||||
internal val state: StateFlow<TokenReceiveUM>
|
||||
field = MutableStateFlow<TokenReceiveUM>(getInitState())
|
||||
|
||||
init {
|
||||
modelScope.launch {
|
||||
load()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQrCodeClick(id: Int) {
|
||||
stackNavigation.push(configuration = TokenReceiveRoutes.QrCode(addressId = id))
|
||||
}
|
||||
|
||||
override fun onCopyClick(id: Int) {
|
||||
val addressToCopy = state.value.addresses[id] ?: return
|
||||
clipboardManager.setText(text = addressToCopy.value, isSensitive = true)
|
||||
}
|
||||
|
||||
override fun onShareClick(address: String) {
|
||||
shareManager.shareText(text = address)
|
||||
}
|
||||
|
||||
override fun onWarningAcknowledged() {
|
||||
modelScope.launch {
|
||||
saveViewedTokenReceiveWarningUseCase.invoke(
|
||||
when (val asset = params.config.asset) {
|
||||
Asset.Currency -> params.config.cryptoCurrency.name
|
||||
Asset.NFT -> asset.name
|
||||
},
|
||||
)
|
||||
stackNavigation.push(configuration = TokenReceiveRoutes.ReceiveAssets)
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapAddresses(addresses: List<ReceiveAddressModel>): ImmutableMap<Int, ReceiveAddress> {
|
||||
return buildMap {
|
||||
addresses.mapIndexed { index, model ->
|
||||
val type = when (model.nameService) {
|
||||
ReceiveAddressModel.NameService.Default -> {
|
||||
ReceiveAddress.Type.Default(
|
||||
displayName = stringReference(model.displayName),
|
||||
)
|
||||
}
|
||||
ReceiveAddressModel.NameService.Ens -> ReceiveAddress.Type.Ens
|
||||
}
|
||||
put(
|
||||
key = index,
|
||||
value = ReceiveAddress(
|
||||
value = model.value,
|
||||
type = type,
|
||||
),
|
||||
)
|
||||
}
|
||||
}.toPersistentMap()
|
||||
}
|
||||
|
||||
private suspend fun load() = withContext(dispatchers.default) {
|
||||
state.value = state.value.copy(
|
||||
isEnsResultLoading = true,
|
||||
)
|
||||
|
||||
val reverseResolveResult =
|
||||
if (params.config.cryptoCurrency.network.nameResolvingType == Network.NameResolvingType.ENS) {
|
||||
getReverseResolvedEnsAddressUseCase(
|
||||
userWalletId = params.config.userWalletId,
|
||||
network = params.config.cryptoCurrency.network,
|
||||
addresses = params.config.receiveAddress.map { it.value },
|
||||
)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val currentAddressValues = state.value.addresses.values.map { it.value }.toSet()
|
||||
|
||||
val newEnsAddresses = reverseResolveResult
|
||||
.filterIsInstance<EnsAddress.Address>()
|
||||
.filterNot { it.name in currentAddressValues }
|
||||
.map { ensAddress -> ReceiveAddress(value = ensAddress.name, type = ReceiveAddress.Type.Ens) }
|
||||
|
||||
val combinedAddresses = (state.value.addresses.values + newEnsAddresses)
|
||||
.sortedWith(compareByDescending { it.type is ReceiveAddress.Type.Ens })
|
||||
|
||||
val updatedAddresses = combinedAddresses
|
||||
.mapIndexed { index, address -> index to address }
|
||||
.toMap()
|
||||
.toPersistentMap()
|
||||
|
||||
state.value = state.value.copy(
|
||||
isEnsResultLoading = false,
|
||||
addresses = updatedAddresses,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getNotifications(): List<NotificationUM> {
|
||||
return buildList {
|
||||
add(
|
||||
NotificationUM.Info(
|
||||
title = resourceReference(
|
||||
R.string.receive_bottom_sheet_warning_title,
|
||||
wrappedList(
|
||||
when (val asset = params.config.asset) {
|
||||
Asset.Currency -> params.config.cryptoCurrency.symbol
|
||||
Asset.NFT -> asset.name
|
||||
},
|
||||
params.config.cryptoCurrency.network.name,
|
||||
),
|
||||
),
|
||||
subtitle = resourceReference(R.string.receive_bottom_sheet_warning_message_description),
|
||||
iconTint = NotificationConfig.IconTint.Accent,
|
||||
),
|
||||
)
|
||||
|
||||
params.config.tokenReceiveNotification.map { notification ->
|
||||
add(
|
||||
NotificationUM.Warning(
|
||||
title = resourceReference(notification.title),
|
||||
subtitle = resourceReference(notification.subtitle),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInitState(): TokenReceiveUM {
|
||||
return TokenReceiveUM(
|
||||
addresses = mapAddresses(params.config.receiveAddress),
|
||||
iconState = iconStateConverter.convert(params.config.cryptoCurrency),
|
||||
network = params.config.cryptoCurrency.network.name,
|
||||
isEnsResultLoading = false,
|
||||
notificationConfigs = getNotifications().toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.features.tokenreceive.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
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.ui.extensions.stringReference
|
||||
import com.tangem.features.tokenreceive.component.TokenReceiveQrCodeComponent
|
||||
import com.tangem.features.tokenreceive.entity.ReceiveAddress
|
||||
import com.tangem.features.tokenreceive.ui.state.QrCodeUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class TokenReceiveQrCodeModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<TokenReceiveQrCodeComponent.TokenReceiveQrCodeParams>()
|
||||
|
||||
internal val state: StateFlow<QrCodeUM>
|
||||
field = MutableStateFlow<QrCodeUM>(
|
||||
QrCodeUM(
|
||||
network = params.network,
|
||||
addressValue = params.address.value,
|
||||
addressName = (params.address.type as? ReceiveAddress.Type.Default)?.displayName ?: stringReference(""),
|
||||
onCopyClick = { params.callback.onCopyClick(params.id) },
|
||||
onShareClick = params.callback::onShareClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.features.tokenreceive.model
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
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.ui.extensions.iconResId
|
||||
import com.tangem.features.tokenreceive.component.TokenReceiveWarningComponent
|
||||
import com.tangem.features.tokenreceive.ui.state.WarningUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@Stable
|
||||
@ModelScoped
|
||||
internal class TokenReceiveWarningModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<TokenReceiveWarningComponent.TokenReceiveWarningParams>()
|
||||
|
||||
internal val state: StateFlow<WarningUM>
|
||||
field = MutableStateFlow<WarningUM>(
|
||||
WarningUM(
|
||||
iconState = params.iconState,
|
||||
onWarningAcknowledged = params.callback::onWarningAcknowledged,
|
||||
network = params.network.name,
|
||||
networkIcon = params.network.iconResId,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.features.tokenreceive.route
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.core.decompose.navigation.Route
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Immutable
|
||||
@Serializable
|
||||
internal sealed interface TokenReceiveRoutes : Route {
|
||||
|
||||
@Serializable
|
||||
data object Warning : TokenReceiveRoutes
|
||||
|
||||
@Serializable
|
||||
data object ReceiveAssets : TokenReceiveRoutes
|
||||
|
||||
@Serializable
|
||||
data class QrCode(val addressId: Int) : TokenReceiveRoutes
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ internal fun TokenReceiveQrCodeContent(qrCodeUM: QrCodeUM) {
|
|||
|
||||
Buttons(
|
||||
onShareClick = { qrCodeUM.onShareClick(qrCodeUM.addressValue) },
|
||||
onCopyClick = { qrCodeUM.onCopyClick(qrCodeUM.addressValue) },
|
||||
onCopyClick = qrCodeUM.onCopyClick,
|
||||
snackbarHostState = snackbarHostState,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.features.tokenreceive.ui.state
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
|
||||
internal data class QrCodeUM(
|
||||
val onCopyClick: (String) -> Unit,
|
||||
val onCopyClick: (Int) -> Unit,
|
||||
val onShareClick: (String) -> Unit,
|
||||
val addressName: TextReference,
|
||||
val addressValue: String,
|
||||
|
|
|
|||
|
|
@ -101,5 +101,8 @@ dependencies {
|
|||
implementation(projects.features.swap.api)
|
||||
implementation(projects.features.txhistory.api)
|
||||
implementation(projects.features.sendV2.api)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
|
||||
implementation(deps.decompose.ext.compose)
|
||||
|
||||
}
|
||||
|
|
@ -4,16 +4,24 @@ 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.router.slot.childSlot
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.arkivanov.essenty.lifecycle.subscribe
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.context.childByContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsModel
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
|
||||
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
|
||||
import com.tangem.features.tokendetails.TokenDetailsComponent
|
||||
import com.tangem.features.tokenreceive.TokenReceiveComponent
|
||||
import com.tangem.features.txhistory.component.TxHistoryComponent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -25,6 +33,7 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
@Assisted params: TokenDetailsComponent.Params,
|
||||
tokenMarketBlockComponentFactory: TokenMarketBlockComponent.Factory,
|
||||
txHistoryComponentFactory: TxHistoryComponent.Factory,
|
||||
private val tokenReceiveComponentFactory: TokenReceiveComponent.Factory,
|
||||
) : TokenDetailsComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: TokenDetailsModel = getOrCreateModel(params)
|
||||
|
|
@ -37,6 +46,13 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
|
||||
private val bottomSheetSlot = childSlot(
|
||||
source = model.bottomSheetNavigation,
|
||||
serializer = TokenReceiveConfig.serializer(),
|
||||
handleBackButton = false,
|
||||
childFactory = ::bottomSheetChild,
|
||||
)
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
onPause = model::onPause,
|
||||
|
|
@ -54,12 +70,14 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
NavigationBar3ButtonsScrim()
|
||||
TokenDetailsScreen(
|
||||
state = state,
|
||||
tokenMarketBlockComponent = tokenMarketBlockComponent,
|
||||
txHistoryComponent = txHistoryComponent,
|
||||
)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
}
|
||||
|
||||
private fun CryptoCurrency.toTokenMarketParam(): TokenMarketBlockComponent.Params? {
|
||||
|
|
@ -68,6 +86,17 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
|
|||
return TokenMarketBlockComponent.Params(cryptoCurrency = this)
|
||||
}
|
||||
|
||||
private fun bottomSheetChild(
|
||||
config: TokenReceiveConfig,
|
||||
componentContext: ComponentContext,
|
||||
): ComposableBottomSheetComponent = tokenReceiveComponentFactory.create(
|
||||
context = childByContext(componentContext),
|
||||
params = TokenReceiveComponent.Params(
|
||||
config = config,
|
||||
onDismiss = model.bottomSheetNavigation::dismiss,
|
||||
),
|
||||
)
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : TokenDetailsComponent.Factory {
|
||||
override fun create(
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import androidx.compose.runtime.Stable
|
|||
import androidx.paging.cachedIn
|
||||
import arrow.core.getOrElse
|
||||
import arrow.core.merge
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
|
|
@ -35,8 +37,11 @@ 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.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
|
||||
|
|
@ -60,10 +65,7 @@ import com.tangem.domain.transaction.error.AssociateAssetError
|
|||
import com.tangem.domain.transaction.error.IncompleteTransactionError
|
||||
import com.tangem.domain.transaction.error.OpenTrustlineError
|
||||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
import com.tangem.domain.transaction.usecase.AssociateAssetUseCase
|
||||
import com.tangem.domain.transaction.usecase.DismissIncompleteTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.OpenTrustlineUseCase
|
||||
import com.tangem.domain.transaction.usecase.RetryIncompleteTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.*
|
||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
||||
|
|
@ -82,6 +84,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.e
|
|||
import com.tangem.features.send.v2.api.SendFeatureToggles
|
||||
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.utils.Provider
|
||||
import com.tangem.utils.coroutines.*
|
||||
|
|
@ -137,6 +140,9 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val tokenDetailsDeepLinkActionListener: TokenDetailsDeepLinkActionListener,
|
||||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||
private val sendFeatureToggles: SendFeatureToggles,
|
||||
private val tokenReceiveFeatureToggle: TokenReceiveFeatureToggle,
|
||||
private val getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
|
||||
private val getEnsNameUseCase: GetEnsNameUseCase,
|
||||
) : Model(), TokenDetailsClickIntents {
|
||||
|
||||
private val params = paramsContainer.require<TokenDetailsComponent.Params>()
|
||||
|
|
@ -159,6 +165,8 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
/** Transaction id to check for status */
|
||||
private val waitForFirstExpressStatusEmmit = MutableStateFlow(false)
|
||||
|
||||
val bottomSheetNavigation: SlotNavigation<TokenReceiveConfig> = SlotNavigation()
|
||||
|
||||
private val stateFactory = TokenDetailsStateFactory(
|
||||
currentStateProvider = Provider { uiState.value },
|
||||
appCurrencyProvider = Provider(selectedAppCurrencyFlow::value),
|
||||
|
|
@ -594,20 +602,27 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
modelScope.launch {
|
||||
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)
|
||||
},
|
||||
)
|
||||
if (tokenReceiveFeatureToggle.isNewTokenReceiveEnabled) {
|
||||
bottomSheetNavigation.activate(
|
||||
configuration = configureReceiveAddresses(addresses = networkAddress),
|
||||
)
|
||||
} 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)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1061,6 +1076,43 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private suspend fun configureReceiveAddresses(addresses: NetworkAddress): TokenReceiveConfig {
|
||||
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,
|
||||
displayName = ens,
|
||||
),
|
||||
)
|
||||
}
|
||||
addresses.availableAddresses.map { address ->
|
||||
add(
|
||||
ReceiveAddressModel(
|
||||
nameService = ReceiveAddressModel.NameService.Default,
|
||||
value = address.value,
|
||||
displayName = "${cryptoCurrency.name} (${cryptoCurrency.symbol})",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return TokenReceiveConfig(
|
||||
shouldShowWarning = cryptoCurrency.name !in getViewedTokenReceiveWarningUseCase(),
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
userWalletId = userWalletId,
|
||||
showMemoDisclaimer = cryptoCurrency.network.transactionExtrasType != Network.TransactionExtrasType.NONE,
|
||||
receiveAddress = receiveAddresses,
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val EXPRESS_STATUS_UPDATE_DELAY = 10_000L
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ dependencies {
|
|||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.domain.notifications)
|
||||
implementation(projects.domain.notifications.toggles)
|
||||
implementation(projects.domain.transaction)
|
||||
|
||||
/** Feature Apis */
|
||||
implementation(projects.features.details.api)
|
||||
|
|
@ -113,6 +114,7 @@ dependencies {
|
|||
implementation(projects.features.biometry.api)
|
||||
implementation(projects.features.nft.api)
|
||||
implementation(projects.features.sendV2.api)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
|
||||
/** Common modules */
|
||||
implementation(projects.common)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue