Updated on 2026-08-14
This commit is contained in:
parent
dbc5555503
commit
44f7f23a95
16 changed files with 719 additions and 551 deletions
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.core.ui.decompose
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
|
||||
@Stable
|
||||
interface ComposableBottomSheetComponent {
|
||||
|
||||
fun dismiss()
|
||||
|
||||
@Composable
|
||||
fun BottomSheet()
|
||||
}
|
||||
|
|
@ -1,18 +1,15 @@
|
|||
package com.tangem.features.managetokens.component
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface AddCustomTokenComponent {
|
||||
|
||||
@Composable
|
||||
fun BottomSheet(isVisible: Boolean, onDismiss: () -> Unit)
|
||||
interface AddCustomTokenComponent : ComposableBottomSheetComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val onDismiss: () -> Unit,
|
||||
)
|
||||
|
||||
interface Factory {
|
||||
fun create(params: Params): AddCustomTokenComponent
|
||||
}
|
||||
interface Factory : ComponentFactory<Params, AddCustomTokenComponent>
|
||||
}
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
package com.tangem.features.managetokens.component
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork
|
||||
|
||||
internal interface CustomTokenFormComponent {
|
||||
|
||||
fun content(scope: LazyListScope)
|
||||
internal interface CustomTokenFormComponent : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val networkId: Network.ID,
|
||||
val network: SelectedNetwork,
|
||||
val derivationPath: SelectedDerivationPath,
|
||||
val onSelectNetworkClick: () -> Unit,
|
||||
val onSelectDerivationPathClick: () -> Unit,
|
||||
)
|
||||
|
||||
interface Factory {
|
||||
fun create(params: Params): CustomTokenFormComponent
|
||||
}
|
||||
interface Factory : ComponentFactory<Params, CustomTokenFormComponent>
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package com.tangem.features.managetokens.component
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.entity.SelectedNetworkUM
|
||||
|
||||
internal interface CustomTokenNetworkSelectorComponent {
|
||||
|
||||
fun content(scope: LazyListScope)
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val selectedNetwork: SelectedNetworkUM?,
|
||||
val onNetworkSelected: (SelectedNetworkUM) -> Unit,
|
||||
)
|
||||
|
||||
interface Factory {
|
||||
fun create(params: Params): CustomTokenNetworkSelectorComponent
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.features.managetokens.component
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork
|
||||
|
||||
internal interface CustomTokenSelectorComponent : ComposableContentComponent {
|
||||
|
||||
sealed class Params {
|
||||
|
||||
data class NetworkSelector(
|
||||
val userWalletId: UserWalletId,
|
||||
val selectedNetwork: SelectedNetwork?,
|
||||
val onNetworkSelected: (SelectedNetwork) -> Unit,
|
||||
) : Params()
|
||||
|
||||
data class DerivationPathSelector(
|
||||
val userWalletId: UserWalletId,
|
||||
val selectedDerivationPath: SelectedDerivationPath?,
|
||||
val onDerivationPathSelected: (SelectedDerivationPath) -> Unit,
|
||||
) : Params()
|
||||
}
|
||||
|
||||
interface Factory : ComponentFactory<Params, CustomTokenSelectorComponent>
|
||||
}
|
||||
|
|
@ -4,81 +4,72 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.AddCustomTokenComponent
|
||||
import com.tangem.features.managetokens.component.CustomTokenNetworkSelectorComponent
|
||||
import com.tangem.features.managetokens.entity.AddCustomTokenButtonUM
|
||||
import com.tangem.features.managetokens.entity.AddCustomTokenUM
|
||||
import com.tangem.features.managetokens.entity.ClickableFieldUM
|
||||
import com.tangem.features.managetokens.entity.SelectedNetworkUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
import com.tangem.features.managetokens.component.CustomTokenSelectorComponent
|
||||
import com.tangem.features.managetokens.entity.customtoken.AddCustomTokenConfig
|
||||
import com.tangem.features.managetokens.ui.AddCustomTokenBottomSheet
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
internal class PreviewAddCustomTokenComponent(
|
||||
initialState: AddCustomTokenUM = AddCustomTokenUM.NetworkSelector(popBack = {}),
|
||||
initialState: AddCustomTokenConfig = AddCustomTokenConfig(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
step = AddCustomTokenConfig.Step.INITIAL_NETWORK_SELECTOR,
|
||||
popBack = {},
|
||||
),
|
||||
) : AddCustomTokenComponent {
|
||||
|
||||
private val userWalletId = UserWalletId(stringValue = "321")
|
||||
private val previewState: MutableStateFlow<AddCustomTokenConfig> = MutableStateFlow(initialState)
|
||||
|
||||
private val previewState: MutableStateFlow<AddCustomTokenUM> = MutableStateFlow(initialState)
|
||||
override fun dismiss() {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun BottomSheet(isVisible: Boolean, onDismiss: () -> Unit) {
|
||||
override fun BottomSheet() {
|
||||
val state by previewState.collectAsStateWithLifecycle()
|
||||
val config = TangemBottomSheetConfig(
|
||||
isShow = isVisible,
|
||||
onDismissRequest = onDismiss,
|
||||
isShow = true,
|
||||
onDismissRequest = ::dismiss,
|
||||
content = state,
|
||||
)
|
||||
|
||||
AddCustomTokenBottomSheet(
|
||||
config = config,
|
||||
content = {
|
||||
when (val s = state) {
|
||||
is AddCustomTokenUM.Form -> {
|
||||
PreviewCustomTokenFormComponent(
|
||||
networkName = ClickableFieldUM(
|
||||
label = resourceReference(R.string.custom_token_network_input_title),
|
||||
value = stringReference(s.selectedNetwork.name),
|
||||
onClick = { showNetworkSelector(s.selectedNetwork) },
|
||||
content = { modifier ->
|
||||
when (state.step) {
|
||||
AddCustomTokenConfig.Step.INITIAL_NETWORK_SELECTOR -> {
|
||||
PreviewCustomTokenSelectorComponent(
|
||||
params = CustomTokenSelectorComponent.Params.NetworkSelector(
|
||||
userWalletId = state.userWalletId,
|
||||
selectedNetwork = null,
|
||||
onNetworkSelected = {},
|
||||
),
|
||||
).content(this)
|
||||
).Content(modifier)
|
||||
}
|
||||
is AddCustomTokenUM.NetworkSelector -> {
|
||||
PreviewCustomTokenNetworkSelectorComponent(
|
||||
params = CustomTokenNetworkSelectorComponent.Params(
|
||||
userWalletId = userWalletId,
|
||||
selectedNetwork = s.selectedNetwork,
|
||||
onNetworkSelected = ::showForm,
|
||||
AddCustomTokenConfig.Step.NETWORK_SELECTOR -> {
|
||||
PreviewCustomTokenSelectorComponent(
|
||||
params = CustomTokenSelectorComponent.Params.NetworkSelector(
|
||||
userWalletId = state.userWalletId,
|
||||
selectedNetwork = state.selectedNetwork,
|
||||
onNetworkSelected = {},
|
||||
),
|
||||
networksSize = 20,
|
||||
).content(this)
|
||||
).Content(modifier)
|
||||
}
|
||||
AddCustomTokenConfig.Step.DERIVATION_PATH_SELECTOR -> {
|
||||
PreviewCustomTokenSelectorComponent(
|
||||
params = CustomTokenSelectorComponent.Params.DerivationPathSelector(
|
||||
userWalletId = state.userWalletId,
|
||||
selectedDerivationPath = state.selectedDerivationPath,
|
||||
onDerivationPathSelected = {},
|
||||
),
|
||||
).Content(modifier)
|
||||
}
|
||||
AddCustomTokenConfig.Step.FORM -> {
|
||||
PreviewCustomTokenFormComponent().Content(modifier)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun showNetworkSelector(selectedNetwork: SelectedNetworkUM) {
|
||||
previewState.update {
|
||||
AddCustomTokenUM.NetworkSelector(selectedNetwork, popBack = { showForm(selectedNetwork) })
|
||||
}
|
||||
}
|
||||
|
||||
private fun showForm(network: SelectedNetworkUM) {
|
||||
previewState.update {
|
||||
AddCustomTokenUM.Form(
|
||||
popBack = {},
|
||||
selectedNetwork = network,
|
||||
addTokenButton = AddCustomTokenButtonUM.Visible(
|
||||
isEnabled = false,
|
||||
onClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,81 +1,87 @@
|
|||
package com.tangem.features.managetokens.component.preview
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
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.features.managetokens.component.CustomTokenFormComponent
|
||||
import com.tangem.features.managetokens.entity.ClickableFieldUM
|
||||
import com.tangem.features.managetokens.entity.CustomTokenFormUM
|
||||
import com.tangem.features.managetokens.entity.TextInputFieldUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.ClickableFieldUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.CustomTokenFormUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.TextInputFieldUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
import com.tangem.features.managetokens.ui.customTokenFormContent
|
||||
import com.tangem.features.managetokens.ui.CustomTokenFormContent
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal class PreviewCustomTokenFormComponent(
|
||||
networkName: ClickableFieldUM = ClickableFieldUM(
|
||||
label = resourceReference(R.string.custom_token_network_input_title),
|
||||
value = stringReference(value = "Ethereum"),
|
||||
onClick = {},
|
||||
),
|
||||
derivationPath: ClickableFieldUM = ClickableFieldUM(
|
||||
label = resourceReference(R.string.custom_token_derivation_path),
|
||||
value = stringReference(value = "Default"),
|
||||
onClick = {},
|
||||
),
|
||||
networkName: ClickableFieldUM = PreviewCustomTokenFormComponent.networkName,
|
||||
derivationPath: ClickableFieldUM = PreviewCustomTokenFormComponent.derivationPath,
|
||||
canAddToken: Boolean = false,
|
||||
contractAddress: TextInputFieldUM = TextInputFieldUM(
|
||||
label = resourceReference(R.string.custom_token_contract_address_input_title),
|
||||
placeholder = stringReference(value = "0x000000000000000000000000000"),
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
),
|
||||
tokenName: TextInputFieldUM = TextInputFieldUM(
|
||||
label = resourceReference(R.string.custom_token_name_input_title),
|
||||
placeholder = stringReference(value = "E.g. USD Coin"),
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
),
|
||||
tokenSymbol: TextInputFieldUM = TextInputFieldUM(
|
||||
label = resourceReference(R.string.custom_token_token_symbol_input_title),
|
||||
placeholder = stringReference(value = "E.g. USDC"),
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
),
|
||||
tokenDecimals: TextInputFieldUM = TextInputFieldUM(
|
||||
label = resourceReference(R.string.custom_token_decimals_input_title),
|
||||
placeholder = stringReference(value = "8"),
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
),
|
||||
notifications: ImmutableList<CustomTokenFormUM.NotificationUM> = persistentListOf(
|
||||
CustomTokenFormUM.NotificationUM(
|
||||
id = "1",
|
||||
config = NotificationConfig(
|
||||
title = stringReference(value = "Note that tokens can be created by anyone"),
|
||||
subtitle = stringReference(value = "Be aware of adding scam tokens, they can cost nothing"),
|
||||
iconResId = R.drawable.img_attention_20,
|
||||
),
|
||||
),
|
||||
),
|
||||
tokenForm: CustomTokenFormUM.TokenFormUM? = PreviewCustomTokenFormComponent.tokenForm,
|
||||
notifications: ImmutableList<CustomTokenFormUM.NotificationUM> = PreviewCustomTokenFormComponent.notifications,
|
||||
) : CustomTokenFormComponent {
|
||||
|
||||
private val previewState = CustomTokenFormUM(
|
||||
networkName = networkName,
|
||||
contractAddress = contractAddress,
|
||||
tokenName = tokenName,
|
||||
tokenSymbol = tokenSymbol,
|
||||
tokenDecimals = tokenDecimals,
|
||||
tokenForm = tokenForm,
|
||||
derivationPath = derivationPath,
|
||||
notifications = notifications,
|
||||
canAddToken = canAddToken,
|
||||
onDerivationPathClick = {},
|
||||
onNetworkClick = {},
|
||||
onAddClick = {},
|
||||
saveToken = {},
|
||||
)
|
||||
|
||||
override fun content(scope: LazyListScope) {
|
||||
scope.customTokenFormContent(model = previewState)
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
CustomTokenFormContent(modifier = modifier, model = previewState)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val networkName: ClickableFieldUM = ClickableFieldUM(
|
||||
label = resourceReference(R.string.custom_token_network_input_title),
|
||||
value = stringReference(value = "Ethereum"),
|
||||
onClick = {},
|
||||
)
|
||||
val derivationPath: ClickableFieldUM = ClickableFieldUM(
|
||||
label = resourceReference(R.string.custom_token_derivation_path),
|
||||
value = stringReference(value = "Default"),
|
||||
onClick = {},
|
||||
)
|
||||
val tokenForm: CustomTokenFormUM.TokenFormUM = CustomTokenFormUM.TokenFormUM(
|
||||
contractAddress = TextInputFieldUM(
|
||||
label = resourceReference(R.string.custom_token_contract_address_input_title),
|
||||
placeholder = stringReference(value = "0x000000000000000000000000000"),
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
),
|
||||
name = TextInputFieldUM(
|
||||
label = resourceReference(R.string.custom_token_name_input_title),
|
||||
placeholder = stringReference(value = "E.g. USD Coin"),
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
),
|
||||
symbol = TextInputFieldUM(
|
||||
label = resourceReference(R.string.custom_token_token_symbol_input_title),
|
||||
placeholder = stringReference(value = "E.g. USDC"),
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
),
|
||||
decimals = TextInputFieldUM(
|
||||
label = resourceReference(R.string.custom_token_decimals_input_title),
|
||||
placeholder = stringReference(value = "8"),
|
||||
value = "",
|
||||
onValueChange = {},
|
||||
),
|
||||
)
|
||||
val notifications: ImmutableList<CustomTokenFormUM.NotificationUM> = persistentListOf(
|
||||
CustomTokenFormUM.NotificationUM(
|
||||
id = "1",
|
||||
config = NotificationConfig(
|
||||
title = stringReference(value = "Note that tokens can be created by anyone"),
|
||||
subtitle = stringReference(value = "Be aware of adding scam tokens, they can cost nothing"),
|
||||
iconResId = R.drawable.img_attention_20,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
package com.tangem.features.managetokens.component.preview
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.CustomTokenNetworkSelectorComponent
|
||||
import com.tangem.features.managetokens.entity.CurrencyNetworkUM
|
||||
import com.tangem.features.managetokens.entity.CustomTokenNetworkSelectorUM
|
||||
import com.tangem.features.managetokens.entity.SelectedNetworkUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
import com.tangem.features.managetokens.ui.customTokenNetworkSelectorContent
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class PreviewCustomTokenNetworkSelectorComponent(
|
||||
private val params: CustomTokenNetworkSelectorComponent.Params = CustomTokenNetworkSelectorComponent.Params(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
selectedNetwork = null,
|
||||
onNetworkSelected = {},
|
||||
),
|
||||
networksSize: Int = 5,
|
||||
) : CustomTokenNetworkSelectorComponent {
|
||||
|
||||
private val previewNetworks = List(size = networksSize) { networkIndex ->
|
||||
val n = SelectedNetworkUM(
|
||||
id = Network.ID(networkIndex.toString()),
|
||||
name = "Network $networkIndex",
|
||||
)
|
||||
|
||||
CurrencyNetworkUM(
|
||||
id = n.id,
|
||||
name = n.name,
|
||||
type = "N$networkIndex",
|
||||
iconResId = R.drawable.ic_eth_16,
|
||||
isMainNetwork = false,
|
||||
isSelected = n.id == params.selectedNetwork?.id,
|
||||
onSelectedStateChange = { params.onNetworkSelected(n) },
|
||||
)
|
||||
}.toImmutableList()
|
||||
|
||||
private val previewState = CustomTokenNetworkSelectorUM(
|
||||
showTitle = params.selectedNetwork == null,
|
||||
networks = previewNetworks,
|
||||
)
|
||||
|
||||
override fun content(scope: LazyListScope) {
|
||||
scope.customTokenNetworkSelectorContent(
|
||||
model = previewState,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.tangem.features.managetokens.component.preview
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.CustomTokenSelectorComponent
|
||||
import com.tangem.features.managetokens.component.CustomTokenSelectorComponent.Params
|
||||
import com.tangem.features.managetokens.entity.customtoken.CustomTokenSelectorUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM
|
||||
import com.tangem.features.managetokens.entity.item.DerivationPathUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
import com.tangem.features.managetokens.ui.CustomTokenSelectorContent
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class PreviewCustomTokenSelectorComponent(
|
||||
private val params: Params = Params.NetworkSelector(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
selectedNetwork = null,
|
||||
onNetworkSelected = {},
|
||||
),
|
||||
itemsSize: Int = 5,
|
||||
) : CustomTokenSelectorComponent {
|
||||
|
||||
private val previewItems = List(size = itemsSize) { index ->
|
||||
when (params) {
|
||||
is Params.DerivationPathSelector -> {
|
||||
val d = SelectedDerivationPath(
|
||||
value = "m/44'/0'/0'/0/$index",
|
||||
name = stringReference(value = "Network $index"),
|
||||
)
|
||||
|
||||
DerivationPathUM(
|
||||
value = "m/44'/0'/0'/0/$index",
|
||||
blockchainName = d.name,
|
||||
isSelected = d.value == params.selectedDerivationPath?.value,
|
||||
onSelectedStateChange = { params.onDerivationPathSelected(d) },
|
||||
)
|
||||
}
|
||||
is Params.NetworkSelector -> {
|
||||
val n = SelectedNetwork(
|
||||
id = Network.ID(index.toString()),
|
||||
name = stringReference(value = "Network $index"),
|
||||
derivationPath = "m/44'/0'/0'/0/$index",
|
||||
)
|
||||
|
||||
CurrencyNetworkUM(
|
||||
networkId = n.id,
|
||||
name = "Network $index",
|
||||
type = "N$index",
|
||||
iconResId = R.drawable.ic_eth_16,
|
||||
isMainNetwork = false,
|
||||
isSelected = n.id == params.selectedNetwork?.id,
|
||||
onSelectedStateChange = { params.onNetworkSelected(n) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}.toImmutableList()
|
||||
|
||||
val previewState = CustomTokenSelectorUM(
|
||||
header = when (params) {
|
||||
is Params.DerivationPathSelector -> CustomTokenSelectorUM.HeaderUM.CustomDerivationButton({})
|
||||
is Params.NetworkSelector -> if (params.selectedNetwork == null) {
|
||||
CustomTokenSelectorUM.HeaderUM.Description
|
||||
} else {
|
||||
CustomTokenSelectorUM.HeaderUM.None
|
||||
}
|
||||
},
|
||||
items = previewItems,
|
||||
)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
CustomTokenSelectorContent(modifier = modifier, model = previewState)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,10 +13,10 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.features.managetokens.component.ManageTokensComponent
|
||||
import com.tangem.features.managetokens.entity.CurrencyItemUM
|
||||
import com.tangem.features.managetokens.entity.CurrencyNetworkUM
|
||||
import com.tangem.features.managetokens.entity.ManageTokensTopBarUM
|
||||
import com.tangem.features.managetokens.entity.ManageTokensUM
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyItemUM
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM
|
||||
import com.tangem.features.managetokens.entity.managetokens.ManageTokensTopBarUM
|
||||
import com.tangem.features.managetokens.entity.managetokens.ManageTokensUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
import com.tangem.features.managetokens.ui.ManageTokensScreen
|
||||
import kotlinx.collections.immutable.mutate
|
||||
|
|
@ -134,7 +134,7 @@ internal class PreviewManageTokensComponent : ManageTokensComponent {
|
|||
|
||||
private fun getCurrencyNetworks(currencyIndex: Int) = List(size = 3) { networkIndex ->
|
||||
CurrencyNetworkUM(
|
||||
id = Network.ID(networkIndex.toString()),
|
||||
networkId = Network.ID(networkIndex.toString()),
|
||||
name = "NETWORK$networkIndex",
|
||||
type = "N$networkIndex",
|
||||
iconResId = R.drawable.ic_eth_16,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import com.tangem.core.ui.message.SnackbarMessage
|
|||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.ManageTokensComponent
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyItemUM
|
||||
import com.tangem.features.managetokens.entity.managetokens.BottomSheetConfig
|
||||
import com.tangem.features.managetokens.entity.managetokens.ManageTokensTopBarUM
|
||||
import com.tangem.features.managetokens.entity.managetokens.ManageTokensUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
|
|
|
|||
|
|
@ -1,146 +1,80 @@
|
|||
package com.tangem.features.managetokens.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.FabPosition
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
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.TangemBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetTitle
|
||||
import com.tangem.core.ui.components.isOpened
|
||||
import com.tangem.core.ui.components.keyboardAsState
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.AddCustomTokenComponent
|
||||
import com.tangem.features.managetokens.component.preview.PreviewAddCustomTokenComponent
|
||||
import com.tangem.features.managetokens.entity.AddCustomTokenButtonUM
|
||||
import com.tangem.features.managetokens.entity.AddCustomTokenUM
|
||||
import com.tangem.features.managetokens.entity.SelectedNetworkUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.AddCustomTokenConfig
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
|
||||
@Composable
|
||||
internal fun AddCustomTokenBottomSheet(config: TangemBottomSheetConfig, content: LazyListScope.() -> Unit) {
|
||||
TangemBottomSheet<AddCustomTokenUM>(
|
||||
internal fun AddCustomTokenBottomSheet(config: TangemBottomSheetConfig, content: @Composable (Modifier) -> Unit) {
|
||||
TangemBottomSheet<AddCustomTokenConfig>(
|
||||
config = config,
|
||||
addBottomInsets = false,
|
||||
title = { model ->
|
||||
Title(model)
|
||||
},
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
content = { model ->
|
||||
Content(
|
||||
model = model,
|
||||
content = content,
|
||||
)
|
||||
content = {
|
||||
val contentModifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxSize()
|
||||
|
||||
content(contentModifier)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Title(model: AddCustomTokenUM, modifier: Modifier = Modifier) {
|
||||
val showTokenNetworkTitle = model is AddCustomTokenUM.NetworkSelector && model.selectedNetwork != null
|
||||
|
||||
if (showTokenNetworkTitle) {
|
||||
TangemTopAppBar(
|
||||
modifier = modifier,
|
||||
title = resourceReference(R.string.custom_token_network_selector_title),
|
||||
titleAlignment = Alignment.CenterHorizontally,
|
||||
startButton = TopAppBarButtonUM.Back(model.popBack),
|
||||
height = TangemTopAppBarHeight.BOTTOM_SHEET,
|
||||
)
|
||||
} else {
|
||||
TangemBottomSheetTitle(
|
||||
modifier = modifier,
|
||||
title = resourceReference(R.string.add_custom_token_title),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Content(model: AddCustomTokenUM, content: LazyListScope.() -> Unit, modifier: Modifier = Modifier) {
|
||||
val density = LocalDensity.current
|
||||
val keyboardState by keyboardAsState()
|
||||
|
||||
var fabHeight by remember { mutableStateOf(0.dp) }
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier.imePadding(),
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
floatingActionButtonPosition = FabPosition.Center,
|
||||
floatingActionButton = {
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier.onSizeChanged {
|
||||
fabHeight = with(density) { it.height.toDp() }
|
||||
},
|
||||
visible = model.addTokenButton.isVisible && !keyboardState.isOpened,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
label = "Add button visibility",
|
||||
) {
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.padding(bottom = TangemTheme.dimens.spacing16)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(id = R.string.custom_token_add_token),
|
||||
enabled = model.addTokenButton.isEnabled,
|
||||
onClick = model.addTokenButton.onClick,
|
||||
)
|
||||
}
|
||||
},
|
||||
) { paddingValues ->
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
contentPadding = PaddingValues(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing16,
|
||||
bottom = TangemTheme.dimens.spacing32 + fabHeight,
|
||||
),
|
||||
) {
|
||||
item {
|
||||
if (model is AddCustomTokenUM.NetworkSelector && model.selectedNetwork != null) {
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.spacing12))
|
||||
} else {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = TangemTheme.dimens.spacing16),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(fraction = 0.7f),
|
||||
text = stringResource(id = R.string.custom_token_subtitle),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
content()
|
||||
private fun Title(model: AddCustomTokenConfig, modifier: Modifier = Modifier) {
|
||||
when (model.step) {
|
||||
AddCustomTokenConfig.Step.INITIAL_NETWORK_SELECTOR,
|
||||
AddCustomTokenConfig.Step.FORM,
|
||||
-> {
|
||||
TangemBottomSheetTitle(
|
||||
modifier = modifier,
|
||||
title = resourceReference(R.string.add_custom_token_title),
|
||||
)
|
||||
}
|
||||
AddCustomTokenConfig.Step.NETWORK_SELECTOR -> {
|
||||
TangemTopAppBar(
|
||||
modifier = modifier,
|
||||
title = resourceReference(R.string.custom_token_network_selector_title),
|
||||
titleAlignment = Alignment.CenterHorizontally,
|
||||
startButton = TopAppBarButtonUM.Back(model.popBack),
|
||||
height = TangemTopAppBarHeight.BOTTOM_SHEET,
|
||||
)
|
||||
}
|
||||
AddCustomTokenConfig.Step.DERIVATION_PATH_SELECTOR -> {
|
||||
TangemTopAppBar(
|
||||
modifier = modifier,
|
||||
title = resourceReference(R.string.custom_token_derivation_path),
|
||||
titleAlignment = Alignment.CenterHorizontally,
|
||||
startButton = TopAppBarButtonUM.Back(model.popBack),
|
||||
height = TangemTopAppBarHeight.BOTTOM_SHEET,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -153,7 +87,7 @@ private fun Preview_AddCustomTokenBottomSheet(
|
|||
@PreviewParameter(AddCustomTokenComponentPreviewProvider::class) component: AddCustomTokenComponent,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
component.BottomSheet(isVisible = true, onDismiss = {})
|
||||
component.BottomSheet()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,24 +96,37 @@ private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider<
|
|||
get() = sequenceOf(
|
||||
PreviewAddCustomTokenComponent(),
|
||||
PreviewAddCustomTokenComponent(
|
||||
initialState = AddCustomTokenUM.NetworkSelector(
|
||||
initialState = AddCustomTokenConfig(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
step = AddCustomTokenConfig.Step.FORM,
|
||||
popBack = {},
|
||||
selectedNetwork = SelectedNetworkUM(
|
||||
id = Network.ID(value = "0"),
|
||||
name = "Ethereum",
|
||||
selectedNetwork = SelectedNetwork(
|
||||
id = Network.ID(value = "1"),
|
||||
name = stringReference("Ethereum"),
|
||||
derivationPath = "m/44'/0'/0'/0/0",
|
||||
),
|
||||
),
|
||||
),
|
||||
PreviewAddCustomTokenComponent(
|
||||
initialState = AddCustomTokenUM.Form(
|
||||
initialState = AddCustomTokenConfig(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
step = AddCustomTokenConfig.Step.NETWORK_SELECTOR,
|
||||
popBack = {},
|
||||
selectedNetwork = SelectedNetworkUM(
|
||||
id = Network.ID(value = "1"),
|
||||
name = "Ethereum",
|
||||
selectedNetwork = SelectedNetwork(
|
||||
id = Network.ID(value = "0"),
|
||||
name = stringReference("Ethereum"),
|
||||
derivationPath = "m/44'/0'/0'/0/0",
|
||||
),
|
||||
addTokenButton = AddCustomTokenButtonUM.Visible(
|
||||
isEnabled = false,
|
||||
onClick = {},
|
||||
),
|
||||
),
|
||||
PreviewAddCustomTokenComponent(
|
||||
initialState = AddCustomTokenConfig(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
step = AddCustomTokenConfig.Step.DERIVATION_PATH_SELECTOR,
|
||||
popBack = {},
|
||||
selectedDerivationPath = SelectedDerivationPath(
|
||||
value = "m/44'/0'/0'/0/0",
|
||||
name = stringReference("Ethereum"),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,97 +2,152 @@ package com.tangem.features.managetokens.ui
|
|||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
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.util.fastForEach
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.block.information.InformationBlock
|
||||
import com.tangem.core.ui.components.fields.SimpleTextField
|
||||
import com.tangem.core.ui.components.isOpened
|
||||
import com.tangem.core.ui.components.keyboardAsState
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.managetokens.component.preview.PreviewCustomTokenFormComponent
|
||||
import com.tangem.features.managetokens.entity.ClickableFieldUM
|
||||
import com.tangem.features.managetokens.entity.CustomTokenFormUM
|
||||
import com.tangem.features.managetokens.entity.TextInputFieldUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.ClickableFieldUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.CustomTokenFormUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.TextInputFieldUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
import com.tangem.features.managetokens.ui.component.AddCustomTokenDescription
|
||||
|
||||
internal fun LazyListScope.customTokenFormContent(model: CustomTokenFormUM) {
|
||||
item {
|
||||
ClickableField(
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
model = model.networkName,
|
||||
)
|
||||
}
|
||||
@Composable
|
||||
internal fun CustomTokenFormContent(model: CustomTokenFormUM, modifier: Modifier = Modifier) {
|
||||
val keyboard by keyboardAsState()
|
||||
val bottomBarHeight by animateDpAsState(
|
||||
label = "Bottom bar height",
|
||||
targetValue = if (keyboard.isOpened) {
|
||||
TangemTheme.dimens.spacing0
|
||||
} else {
|
||||
with(LocalDensity.current) {
|
||||
WindowInsets.systemBars.getBottom(density = this).toDp()
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.background(color = TangemTheme.colors.background.secondary),
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
item {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(bottom = TangemTheme.dimens.spacing12)
|
||||
.background(
|
||||
color = TangemTheme.colors.background.action,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
),
|
||||
.verticalScroll(scrollState)
|
||||
.fillMaxSize()
|
||||
.padding(bottom = TangemTheme.dimens.spacing76),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
TextField(
|
||||
model = model.contractAddress,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
imeAction = ImeAction.Next,
|
||||
),
|
||||
)
|
||||
TextField(
|
||||
model = model.tokenName,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
imeAction = ImeAction.Next,
|
||||
),
|
||||
)
|
||||
TextField(
|
||||
model = model.tokenSymbol,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
imeAction = ImeAction.Next,
|
||||
),
|
||||
)
|
||||
TextField(
|
||||
model = model.tokenDecimals,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Decimal,
|
||||
imeAction = ImeAction.Next,
|
||||
),
|
||||
AddCustomTokenDescription()
|
||||
FormContent(model)
|
||||
}
|
||||
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = TangemTheme.dimens.spacing16 + bottomBarHeight)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(id = R.string.custom_token_add_token),
|
||||
enabled = model.canAddToken,
|
||||
onClick = model.saveToken,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FormContent(model: CustomTokenFormUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
|
||||
) {
|
||||
ClickableField(
|
||||
model = model.networkName,
|
||||
)
|
||||
|
||||
val tokenForm = model.tokenForm
|
||||
if (tokenForm != null) {
|
||||
TokenForm(tokenForm)
|
||||
}
|
||||
|
||||
ClickableField(
|
||||
model = model.derivationPath,
|
||||
)
|
||||
|
||||
model.notifications.fastForEach { notification ->
|
||||
Notification(
|
||||
config = notification.config,
|
||||
containerColor = TangemTheme.colors.button.disabled,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
ClickableField(
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
model = model.derivationPath,
|
||||
@Composable
|
||||
private fun TokenForm(tokenForm: CustomTokenFormUM.TokenFormUM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = TangemTheme.colors.background.action,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
),
|
||||
) {
|
||||
TextField(
|
||||
model = tokenForm.contractAddress,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
imeAction = ImeAction.Next,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
items(
|
||||
items = model.notifications,
|
||||
key = { it.id },
|
||||
) { notification ->
|
||||
Notification(
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
config = notification.config,
|
||||
containerColor = TangemTheme.colors.button.disabled,
|
||||
TextField(
|
||||
model = tokenForm.name,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
imeAction = ImeAction.Next,
|
||||
),
|
||||
)
|
||||
TextField(
|
||||
model = tokenForm.symbol,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
imeAction = ImeAction.Next,
|
||||
),
|
||||
)
|
||||
TextField(
|
||||
model = tokenForm.decimals,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Decimal,
|
||||
imeAction = ImeAction.Next,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -124,7 +179,9 @@ private fun TextField(
|
|||
},
|
||||
content = {
|
||||
SimpleTextField(
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
modifier = Modifier
|
||||
.padding(bottom = TangemTheme.dimens.spacing12)
|
||||
.fillMaxWidth(),
|
||||
value = model.value,
|
||||
onValueChange = model.onValueChange,
|
||||
readOnly = false,
|
||||
|
|
@ -170,9 +227,7 @@ private fun Preview_CustomTokenFormContent(
|
|||
component: PreviewCustomTokenFormComponent,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
LazyColumn(
|
||||
modifier = Modifier.background(color = TangemTheme.colors.background.secondary),
|
||||
) { component.content(scope = this) }
|
||||
component.Content(modifier = Modifier)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -183,14 +238,19 @@ private class PreviewCustomTokenFormComponentProvider :
|
|||
get() = sequenceOf(
|
||||
PreviewCustomTokenFormComponent(),
|
||||
PreviewCustomTokenFormComponent(
|
||||
contractAddress = TextInputFieldUM(
|
||||
label = stringReference("Contract address"),
|
||||
value = "0x1234567890",
|
||||
error = stringReference("Contract address is invalid"),
|
||||
placeholder = stringReference("0x1234567890"),
|
||||
onValueChange = {},
|
||||
tokenForm = PreviewCustomTokenFormComponent.tokenForm.copy(
|
||||
contractAddress = TextInputFieldUM(
|
||||
label = stringReference("Contract address"),
|
||||
value = "0x1234567890",
|
||||
error = stringReference("Contract address is invalid"),
|
||||
placeholder = stringReference("0x1234567890"),
|
||||
onValueChange = {},
|
||||
),
|
||||
),
|
||||
),
|
||||
PreviewCustomTokenFormComponent(
|
||||
tokenForm = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
package com.tangem.features.managetokens.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.rows.ChainRow
|
||||
import com.tangem.core.ui.components.rows.model.ChainRowUM
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.CustomTokenNetworkSelectorComponent
|
||||
import com.tangem.features.managetokens.component.preview.PreviewCustomTokenNetworkSelectorComponent
|
||||
import com.tangem.features.managetokens.entity.CurrencyNetworkUM
|
||||
import com.tangem.features.managetokens.entity.CustomTokenNetworkSelectorUM
|
||||
import com.tangem.features.managetokens.entity.SelectedNetworkUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
|
||||
internal fun LazyListScope.customTokenNetworkSelectorContent(model: CustomTokenNetworkSelectorUM) {
|
||||
val lastIndex = model.networks.lastIndex
|
||||
|
||||
if (model.showTitle) {
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = TangemTheme.dimens.size36)
|
||||
.background(
|
||||
color = TangemTheme.colors.background.primary,
|
||||
shape = TangemTheme.shapes.bottomSheet,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
top = TangemTheme.dimens.spacing12,
|
||||
bottom = TangemTheme.dimens.spacing6,
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12),
|
||||
text = stringResource(R.string.add_custom_token_choose_network),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
itemsIndexed(
|
||||
items = model.networks,
|
||||
key = { _, item -> item.id.value },
|
||||
) { index, item ->
|
||||
NetworkItem(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(
|
||||
shape = when {
|
||||
!model.showTitle && index == 0 -> RoundedCornerShape(
|
||||
topStart = TangemTheme.dimens.radius16,
|
||||
topEnd = TangemTheme.dimens.radius16,
|
||||
)
|
||||
index == lastIndex -> RoundedCornerShape(
|
||||
bottomStart = TangemTheme.dimens.radius16,
|
||||
bottomEnd = TangemTheme.dimens.radius16,
|
||||
)
|
||||
else -> RectangleShape
|
||||
},
|
||||
)
|
||||
.background(color = TangemTheme.colors.background.primary)
|
||||
.clickable(onClick = { item.onSelectedStateChange(true) })
|
||||
.padding(horizontal = TangemTheme.dimens.spacing4),
|
||||
model = item,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetworkItem(model: CurrencyNetworkUM, modifier: Modifier = Modifier) {
|
||||
ChainRow(
|
||||
modifier = modifier,
|
||||
model = with(model) {
|
||||
ChainRowUM(
|
||||
name = name,
|
||||
type = type,
|
||||
icon = CurrencyIconState.CoinIcon(
|
||||
url = null,
|
||||
fallbackResId = model.iconResId,
|
||||
isGrayscale = !model.isSelected,
|
||||
showCustomBadge = false,
|
||||
),
|
||||
showCustom = false,
|
||||
)
|
||||
},
|
||||
action = {
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
visible = model.isSelected,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_check_24),
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_CustomTokenNetworkSelectorContent(
|
||||
@PreviewParameter(CustomTokenNetworkSelectorComponentPreviewProvider::class)
|
||||
component: CustomTokenNetworkSelectorComponent,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
LazyColumn {
|
||||
component.content(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomTokenNetworkSelectorComponentPreviewProvider :
|
||||
PreviewParameterProvider<CustomTokenNetworkSelectorComponent> {
|
||||
override val values: Sequence<CustomTokenNetworkSelectorComponent>
|
||||
get() = sequenceOf(
|
||||
PreviewCustomTokenNetworkSelectorComponent(),
|
||||
PreviewCustomTokenNetworkSelectorComponent(
|
||||
params = CustomTokenNetworkSelectorComponent.Params(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
selectedNetwork = SelectedNetworkUM(
|
||||
id = Network.ID(value = "0"),
|
||||
name = "",
|
||||
),
|
||||
onNetworkSelected = {},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
package com.tangem.features.managetokens.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
|
||||
import com.tangem.core.ui.components.rows.ChainRow
|
||||
import com.tangem.core.ui.components.rows.model.ChainRowUM
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.managetokens.component.CustomTokenSelectorComponent
|
||||
import com.tangem.features.managetokens.component.preview.PreviewCustomTokenSelectorComponent
|
||||
import com.tangem.features.managetokens.entity.customtoken.CustomTokenSelectorUM
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedDerivationPath
|
||||
import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork
|
||||
import com.tangem.features.managetokens.entity.item.CurrencyNetworkUM
|
||||
import com.tangem.features.managetokens.entity.item.DerivationPathUM
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
import com.tangem.features.managetokens.ui.component.AddCustomTokenDescription
|
||||
|
||||
@Composable
|
||||
internal fun CustomTokenSelectorContent(model: CustomTokenSelectorUM, modifier: Modifier = Modifier) {
|
||||
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
|
||||
val lastIndex = model.items.lastIndex
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = PaddingValues(
|
||||
bottom = TangemTheme.dimens.spacing16 + bottomBarHeight,
|
||||
),
|
||||
) {
|
||||
item {
|
||||
Header(model.header)
|
||||
}
|
||||
|
||||
itemsIndexed(
|
||||
items = model.items,
|
||||
key = { _, item -> item.id },
|
||||
) { index, item ->
|
||||
val itemModifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(
|
||||
shape = when {
|
||||
model.header !is CustomTokenSelectorUM.HeaderUM.Description && index == 0 -> {
|
||||
RoundedCornerShape(
|
||||
topStart = TangemTheme.dimens.radius16,
|
||||
topEnd = TangemTheme.dimens.radius16,
|
||||
)
|
||||
}
|
||||
index == lastIndex -> {
|
||||
RoundedCornerShape(
|
||||
bottomStart = TangemTheme.dimens.radius16,
|
||||
bottomEnd = TangemTheme.dimens.radius16,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
RectangleShape
|
||||
}
|
||||
},
|
||||
)
|
||||
.background(color = TangemTheme.colors.background.primary)
|
||||
.clickable(onClick = { item.onSelectedStateChange(true) })
|
||||
.padding(horizontal = TangemTheme.dimens.spacing4)
|
||||
|
||||
when (item) {
|
||||
is CurrencyNetworkUM -> {
|
||||
NetworkItem(
|
||||
modifier = itemModifier,
|
||||
model = item,
|
||||
)
|
||||
}
|
||||
is DerivationPathUM -> {
|
||||
DerivationPathItem(
|
||||
modifier = itemModifier,
|
||||
model = item,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Header(header: CustomTokenSelectorUM.HeaderUM, modifier: Modifier = Modifier) {
|
||||
when (header) {
|
||||
is CustomTokenSelectorUM.HeaderUM.CustomDerivationButton -> {
|
||||
CustomDerivationButton(
|
||||
modifier = modifier.padding(vertical = TangemTheme.dimens.spacing16),
|
||||
onClick = header.onClick,
|
||||
)
|
||||
}
|
||||
is CustomTokenSelectorUM.HeaderUM.Description -> {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing16),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
AddCustomTokenDescription()
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = TangemTheme.dimens.size36)
|
||||
.background(
|
||||
color = TangemTheme.colors.background.primary,
|
||||
shape = TangemTheme.shapes.bottomSheet,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing12)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12),
|
||||
text = stringResource(R.string.add_custom_token_choose_network),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is CustomTokenSelectorUM.HeaderUM.None -> {
|
||||
Spacer(modifier = Modifier.size(TangemTheme.dimens.spacing16))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NetworkItem(model: CurrencyNetworkUM, modifier: Modifier = Modifier) {
|
||||
ChainRow(
|
||||
modifier = modifier,
|
||||
model = with(model) {
|
||||
ChainRowUM(
|
||||
name = name,
|
||||
type = type,
|
||||
icon = CurrencyIconState.CoinIcon(
|
||||
url = null,
|
||||
fallbackResId = model.iconResId,
|
||||
isGrayscale = !model.isSelected,
|
||||
showCustomBadge = false,
|
||||
),
|
||||
showCustom = false,
|
||||
)
|
||||
},
|
||||
action = {
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size24),
|
||||
visible = model.isSelected,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_check_24),
|
||||
tint = TangemTheme.colors.icon.accent,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CustomDerivationButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
// TODO: Implement in [REDACTED_JIRA]
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = TangemTheme.dimens.size56)
|
||||
.clip(shape = TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(color = TangemTheme.colors.background.primary)
|
||||
.clickable(onClick = onClick)
|
||||
.padding(all = TangemTheme.dimens.spacing12),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
Text(
|
||||
text = "Custom",
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DerivationPathItem(model: DerivationPathUM, modifier: Modifier = Modifier) {
|
||||
// TODO: Implement in [REDACTED_JIRA]
|
||||
Box(
|
||||
modifier = modifier
|
||||
.heightIn(TangemTheme.dimens.size56)
|
||||
.padding(all = TangemTheme.dimens.spacing12),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
Text(
|
||||
text = "${model.value} ${if (model.isSelected) "- selected" else ""}",
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun Preview_CustomTokenNetworkSelectorContent(
|
||||
@PreviewParameter(CustomTokenNetworkSelectorComponentPreviewProvider::class)
|
||||
component: CustomTokenSelectorComponent,
|
||||
) {
|
||||
TangemThemePreview {
|
||||
component.Content(modifier = Modifier)
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomTokenNetworkSelectorComponentPreviewProvider :
|
||||
PreviewParameterProvider<CustomTokenSelectorComponent> {
|
||||
override val values: Sequence<CustomTokenSelectorComponent>
|
||||
get() = sequenceOf(
|
||||
PreviewCustomTokenSelectorComponent(),
|
||||
PreviewCustomTokenSelectorComponent(
|
||||
params = CustomTokenSelectorComponent.Params.NetworkSelector(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
selectedNetwork = SelectedNetwork(
|
||||
id = Network.ID(value = "0"),
|
||||
name = stringReference(""),
|
||||
derivationPath = "m/44'/0'/0'/0/0",
|
||||
),
|
||||
onNetworkSelected = {},
|
||||
),
|
||||
),
|
||||
PreviewCustomTokenSelectorComponent(
|
||||
params = CustomTokenSelectorComponent.Params.DerivationPathSelector(
|
||||
userWalletId = UserWalletId(stringValue = "321"),
|
||||
selectedDerivationPath = SelectedDerivationPath(
|
||||
value = "m/44'/0'/0'/0/0",
|
||||
name = stringReference(""),
|
||||
),
|
||||
onDerivationPathSelected = {},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
// endregion Preview
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.features.managetokens.ui.component
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.features.managetokens.impl.R
|
||||
|
||||
@Composable
|
||||
internal fun AddCustomTokenDescription(modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
modifier = modifier.fillMaxWidth(fraction = 0.7f),
|
||||
text = stringResource(id = R.string.custom_token_subtitle),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue