Updated on 2026-08-14
This commit is contained in:
parent
5b3a6d51b3
commit
950dc41662
10 changed files with 417 additions and 0 deletions
|
|
@ -34,6 +34,7 @@ dependencies {
|
|||
implementation(projects.domain.appCurrency.models)
|
||||
implementation(projects.domain.balanceHiding)
|
||||
implementation(projects.domain.balanceHiding.models)
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.demo)
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.models)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
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.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.features.onramp.hottokens.portfolio.model.OnrampAddToPortfolioModel
|
||||
import com.tangem.features.onramp.hottokens.portfolio.ui.OnrampAddToPortfolioBottomSheet
|
||||
import com.tangem.features.onramp.hottokens.portfolio.ui.OnrampAddToPortfolioContent
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class DefaultOnrampAddToPortfolioComponent @AssistedInject constructor(
|
||||
@Assisted context: AppComponentContext,
|
||||
@Assisted private val params: OnrampAddToPortfolioComponent.Params,
|
||||
) : OnrampAddToPortfolioComponent, AppComponentContext by context {
|
||||
|
||||
private val model: OnrampAddToPortfolioModel = getOrCreateModel(params)
|
||||
|
||||
override fun dismiss() {
|
||||
params.onDismiss()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet() {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
val bottomSheetConfig = remember(key1 = this) {
|
||||
TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = ::dismiss,
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
)
|
||||
}
|
||||
|
||||
OnrampAddToPortfolioBottomSheet(
|
||||
config = bottomSheetConfig,
|
||||
content = { OnrampAddToPortfolioContent(state = state) },
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : OnrampAddToPortfolioComponent.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: OnrampAddToPortfolioComponent.Params,
|
||||
): DefaultOnrampAddToPortfolioComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
* Onramp bottom sheet component for adding token to portfolio
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface OnrampAddToPortfolioComponent : ComposableBottomSheetComponent {
|
||||
|
||||
/**
|
||||
* Params
|
||||
*
|
||||
* @property userWalletId user wallet id
|
||||
* @property cryptoCurrency crypto currency
|
||||
* @property currencyIconState currency icon state
|
||||
* @property onSuccessAdding lambda be invoked when token will added
|
||||
* @property onDismiss lambda be invoked when bottom sheet is dismissed
|
||||
*/
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
val currencyIconState: CurrencyIconState,
|
||||
val onSuccessAdding: () -> Unit,
|
||||
val onDismiss: () -> Unit,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, OnrampAddToPortfolioComponent>
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio.di
|
||||
|
||||
import com.tangem.features.onramp.hottokens.portfolio.DefaultOnrampAddToPortfolioComponent
|
||||
import com.tangem.features.onramp.hottokens.portfolio.OnrampAddToPortfolioComponent
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface OnrampAddToPortfolioComponentModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindOnrampAddToPortfolioComponentFactory(
|
||||
factory: DefaultOnrampAddToPortfolioComponent.Factory,
|
||||
): OnrampAddToPortfolioComponent.Factory
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio.di
|
||||
|
||||
import com.tangem.core.decompose.di.DecomposeComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.features.onramp.hottokens.portfolio.model.OnrampAddToPortfolioModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(DecomposeComponent::class)
|
||||
internal interface OnrampAddToPortfolioModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(OnrampAddToPortfolioModel::class)
|
||||
fun bindOnrampSelectCountryModel(model: OnrampAddToPortfolioModel): Model
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio.entity
|
||||
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
||||
internal sealed class OnrampAddToPortfolioBSConfig {
|
||||
|
||||
data class AddToPortfolio(
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
val currencyIconState: CurrencyIconState,
|
||||
val onSuccessAdding: () -> Unit,
|
||||
) : OnrampAddToPortfolioBSConfig()
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio.entity
|
||||
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.features.onramp.impl.R
|
||||
|
||||
/**
|
||||
* Onramp add to portfolio UM
|
||||
*
|
||||
* @property currencyName currency name
|
||||
* @property networkName network name
|
||||
* @property currencyIconState currency icon state
|
||||
* @property onAddClick lambda be invoked when add button is clicked
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class OnrampAddToPortfolioUM(
|
||||
val currencyName: String,
|
||||
val networkName: String,
|
||||
val currencyIconState: CurrencyIconState,
|
||||
val onAddClick: () -> Unit,
|
||||
) {
|
||||
|
||||
val bsTitle: TextReference = resourceReference(id = R.string.common_add_token)
|
||||
|
||||
val subtitle: TextReference = resourceReference(
|
||||
id = R.string.hot_crypto_token_network,
|
||||
formatArgs = wrappedList(networkName),
|
||||
)
|
||||
|
||||
val addButtonText: TextReference = resourceReference(R.string.common_add_to_portfolio)
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio.model
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||
import com.tangem.features.onramp.hottokens.portfolio.OnrampAddToPortfolioComponent
|
||||
import com.tangem.features.onramp.hottokens.portfolio.entity.OnrampAddToPortfolioUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Model for adding token to portfolio
|
||||
*
|
||||
* @param paramsContainer params container
|
||||
* @property dispatchers dispatchers
|
||||
* @property derivePublicKeysUseCase use case for deriving public key
|
||||
* @property addCryptoCurrenciesUseCase use case for adding crypto currency
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@ComponentScoped
|
||||
internal class OnrampAddToPortfolioModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val derivePublicKeysUseCase: DerivePublicKeysUseCase,
|
||||
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
|
||||
) : Model() {
|
||||
|
||||
val state: StateFlow<OnrampAddToPortfolioUM> get() = _state
|
||||
private val _state = MutableStateFlow(value = getInitialState())
|
||||
|
||||
private val params: OnrampAddToPortfolioComponent.Params = paramsContainer.require()
|
||||
|
||||
private fun getInitialState(): OnrampAddToPortfolioUM {
|
||||
return OnrampAddToPortfolioUM(
|
||||
currencyName = params.cryptoCurrency.name,
|
||||
networkName = params.cryptoCurrency.network.name,
|
||||
currencyIconState = params.currencyIconState,
|
||||
onAddClick = ::onAddClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun onAddClick() {
|
||||
modelScope.launch {
|
||||
derivePublicKeysUseCase(params.userWalletId, listOfNotNull(params.cryptoCurrency)).getOrElse {
|
||||
Timber.e("Failed to derive public keys: $it")
|
||||
}
|
||||
|
||||
addCryptoCurrenciesUseCase(
|
||||
userWalletId = params.userWalletId,
|
||||
currencies = listOfNotNull(params.cryptoCurrency),
|
||||
)
|
||||
.onRight { params.onSuccessAdding() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
@Composable
|
||||
internal fun OnrampAddToPortfolioBottomSheet(config: TangemBottomSheetConfig, content: @Composable () -> Unit) {
|
||||
TangemBottomSheet<TangemBottomSheetConfigContent.Empty>(
|
||||
config = config,
|
||||
addBottomInsets = true,
|
||||
containerColor = TangemTheme.colors.background.tertiary,
|
||||
content = { content() },
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
package com.tangem.features.onramp.hottokens.portfolio.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.SpacerH
|
||||
import com.tangem.core.ui.components.SpacerH12
|
||||
import com.tangem.core.ui.components.SpacerH16
|
||||
import com.tangem.core.ui.components.SpacerH24
|
||||
import com.tangem.core.ui.components.appbar.TangemTopAppBar
|
||||
import com.tangem.core.ui.components.appbar.TangemTopAppBarHeight
|
||||
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButton
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
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.onramp.hottokens.portfolio.entity.OnrampAddToPortfolioUM
|
||||
import com.tangem.features.onramp.impl.R
|
||||
|
||||
/**
|
||||
* Onramp add to portfolio content
|
||||
*
|
||||
* @param state state
|
||||
*/
|
||||
@Composable
|
||||
fun OnrampAddToPortfolioContent(state: OnrampAddToPortfolioUM) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
TopAppBar(text = state.bsTitle)
|
||||
|
||||
SpacerH(height = 19.dp)
|
||||
|
||||
CurrencyIcon(state = state.currencyIconState)
|
||||
|
||||
SpacerH12()
|
||||
|
||||
CurrencyName(
|
||||
text = state.currencyName,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
SpacerH(height = 6.dp)
|
||||
|
||||
CurrencyNetworkName(
|
||||
text = state.subtitle,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
SpacerH24()
|
||||
|
||||
AddToPortfolioButton(
|
||||
text = state.addButtonText,
|
||||
onClick = state.onAddClick,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
SpacerH16()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TopAppBar(text: TextReference) {
|
||||
TangemTopAppBar(
|
||||
title = text.resolveReference(),
|
||||
endButton = TopAppBarButtonUM(
|
||||
iconRes = R.drawable.ic_information_24,
|
||||
onIconClicked = {},
|
||||
),
|
||||
iconTint = TangemTheme.colors.icon.informative,
|
||||
titleAlignment = Alignment.CenterHorizontally,
|
||||
height = TangemTopAppBarHeight.BOTTOM_SHEET,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CurrencyName(text: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = text,
|
||||
modifier = modifier,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
maxLines = 1,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CurrencyNetworkName(text: TextReference, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = text.resolveReference(),
|
||||
modifier = modifier,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddToPortfolioButton(text: TextReference, onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
TangemButton(
|
||||
text = text.resolveReference(),
|
||||
icon = TangemButtonIconPosition.End(iconResId = R.drawable.ic_tangem_24),
|
||||
onClick = onClick,
|
||||
colors = TangemButtonsDefaults.primaryButtonColors,
|
||||
showProgress = false,
|
||||
enabled = true,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
size = TangemButtonSize.WideAction,
|
||||
textStyle = TangemTheme.typography.subtitle1,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PreviewOnrampAddToPortfolioContent() {
|
||||
TangemThemePreview {
|
||||
val bottomSheetConfig = remember {
|
||||
TangemBottomSheetConfig(
|
||||
isShown = true,
|
||||
onDismissRequest = {},
|
||||
content = TangemBottomSheetConfigContent.Empty,
|
||||
)
|
||||
}
|
||||
OnrampAddToPortfolioBottomSheet(
|
||||
config = bottomSheetConfig,
|
||||
content = {
|
||||
OnrampAddToPortfolioContent(
|
||||
state = OnrampAddToPortfolioUM(
|
||||
currencyName = "Tether",
|
||||
networkName = "Ethereum",
|
||||
currencyIconState = CurrencyIconState.TokenIcon(
|
||||
url = null,
|
||||
topBadgeIconResId = R.drawable.img_eth_22,
|
||||
fallbackTint = TangemColorPalette.Black,
|
||||
fallbackBackground = TangemColorPalette.Meadow,
|
||||
isGrayscale = false,
|
||||
showCustomBadge = false,
|
||||
),
|
||||
onAddClick = {},
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue