From f8884d521f9646f94c897c07e3ae20fbba935c35 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Jun 2024 15:12:57 +0400 Subject: [PATCH 1/8] Updated on 2026-08-14 --- features/details/impl/build.gradle.kts | 1 - features/manage-tokens/api/build.gradle.kts | 7 +- .../component/ManageTokensComponent.kt | 14 ++++ features/manage-tokens/impl/build.gradle.kts | 70 ++++++------------- .../preview/PreviewManageTokensComponent.kt | 23 ++++++ .../managetokens/ui/ManageTokensScreen.kt | 35 ++++++++++ .../extension/BaseExtensionConfigurations.kt | 1 - 7 files changed, 98 insertions(+), 53 deletions(-) create mode 100644 features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensComponent.kt create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt diff --git a/features/details/impl/build.gradle.kts b/features/details/impl/build.gradle.kts index c6694323ba..82ca657a96 100644 --- a/features/details/impl/build.gradle.kts +++ b/features/details/impl/build.gradle.kts @@ -48,7 +48,6 @@ dependencies { implementation(deps.tangem.blockchain) /* AndroidX */ - implementation(deps.androidx.fragment.ktx) implementation(deps.androidx.activity.compose) implementation(deps.lifecycle.compose) diff --git a/features/manage-tokens/api/build.gradle.kts b/features/manage-tokens/api/build.gradle.kts index cbfb3f7b1f..0cf94d3840 100644 --- a/features/manage-tokens/api/build.gradle.kts +++ b/features/manage-tokens/api/build.gradle.kts @@ -9,5 +9,10 @@ android { } dependencies { - implementation(deps.compose.foundation) + /* Project - Domain */ + implementation(projects.domain.wallets.models) + + /* Project - Core */ + implementation(projects.core.ui) + implementation(projects.core.decompose) } \ No newline at end of file diff --git a/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensComponent.kt b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensComponent.kt new file mode 100644 index 0000000000..54cb358614 --- /dev/null +++ b/features/manage-tokens/api/src/main/kotlin/com/tangem/features/managetokens/component/ManageTokensComponent.kt @@ -0,0 +1,14 @@ +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 + +interface ManageTokensComponent : ComposableContentComponent { + + data class Params( + val userWalletId: UserWalletId, + ) + + interface Factory : ComponentFactory +} \ No newline at end of file diff --git a/features/manage-tokens/impl/build.gradle.kts b/features/manage-tokens/impl/build.gradle.kts index 88d462b52c..8e3cc2bddb 100644 --- a/features/manage-tokens/impl/build.gradle.kts +++ b/features/manage-tokens/impl/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(deps.plugins.android.library) alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.serialization) alias(deps.plugins.kotlin.kapt) alias(deps.plugins.hilt.android) id("configuration") @@ -11,61 +12,30 @@ android { } dependencies { - /** AndroidX */ - implementation(deps.androidx.activity.compose) - implementation(deps.material) + /* Project - API */ + implementation(projects.features.manageTokens.api) - /** Compose */ - implementation(deps.compose.accompanist.systemUiController) - implementation(deps.compose.coil) - implementation(deps.compose.constraintLayout) - implementation(deps.compose.foundation) - implementation(deps.compose.material) - implementation(deps.compose.material3) - implementation(deps.compose.navigation) - implementation(deps.compose.navigation.hilt) - implementation(deps.compose.paging) - implementation(deps.compose.reorderable) - implementation(deps.compose.shimmer) + /* Project - Core */ + implementation(projects.core.decompose) + implementation(projects.core.ui) + implementation(projects.common.routing) + + /* AndroidX */ + implementation(deps.androidx.activity.compose) + implementation(deps.lifecycle.compose) + + /* Compose */ implementation(deps.compose.ui) implementation(deps.compose.ui.tooling) + implementation(deps.compose.foundation) + implementation(deps.compose.material3) + implementation(deps.compose.shimmer) - /** Other libraries */ - implementation(deps.arrow.core) - implementation(deps.jodatime) - implementation(deps.kotlin.immutable.collections) - implementation(deps.tangem.card.core) - implementation(deps.timber) - - /** DI */ + /* DI */ implementation(deps.hilt.android) kapt(deps.hilt.kapt) - /** Core modules */ - implementation(projects.core.analytics) - implementation(projects.core.analytics.models) - implementation(projects.core.featuretoggles) - implementation(projects.core.navigation) - implementation(projects.core.ui) - implementation(projects.core.utils) - - /** Project - Data */ - implementation(projects.data.tokens) - - /** Domain modules */ - implementation(projects.domain.card) - implementation(projects.domain.demo) - implementation(projects.domain.legacy) - implementation(projects.libs.blockchainSdk) - implementation(projects.domain.models) - implementation(projects.domain.settings) - implementation(projects.domain.tokens) - implementation(projects.domain.tokens.models) - implementation(projects.domain.wallets) - implementation(projects.domain.wallets.models) - implementation(projects.domain.appCurrency) - implementation(projects.domain.appCurrency.models) - - /** Feature Apis */ - implementation(projects.features.manageTokens.api) + /* Other */ + implementation(deps.kotlin.immutable.collections) + implementation(deps.timber) } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt new file mode 100644 index 0000000000..5bf83bf727 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt @@ -0,0 +1,23 @@ +package com.tangem.features.managetokens.component.preview + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.tangem.features.managetokens.component.ManageTokensComponent +import com.tangem.features.managetokens.entity.ManageTokensUM +import com.tangem.features.managetokens.ui.ManageTokensScreen +import kotlinx.collections.immutable.persistentListOf + +internal class PreviewManageTokensComponent : ManageTokensComponent { + + private val previewState: ManageTokensUM = ManageTokensUM( + popBack = {}, + ) + + @Composable + override fun Content(modifier: Modifier) { + ManageTokensScreen( + modifier = modifier, + state = previewState, + ) + } +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt new file mode 100644 index 0000000000..8a4be14f9c --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt @@ -0,0 +1,35 @@ +package com.tangem.features.managetokens.ui + +import android.content.res.Configuration +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.res.TangemThemePreview +import com.tangem.feature.managetokens.component.preview.PreviewManageTokensComponent +import com.tangem.feature.managetokens.entity.ManageTokensUM + +@Composable +internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modifier) { + BackHandler(onBack = state.popBack) + + Scaffold( + modifier = modifier, + content = { + TODO("Not yet implemented") + }, + ) +} + +// region Preview +@Preview(showBackground = true, widthDp = 360, heightDp = 800) +@Preview(showBackground = true, widthDp = 360, heightDp = 800, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun Preview_ManageTokens() { + TangemThemePreview { + PreviewManageTokensComponent().Content(Modifier.fillMaxWidth()) + } +} +// endregion Preview \ No newline at end of file diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/BaseExtensionConfigurations.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/BaseExtensionConfigurations.kt index 1612e170ed..49a6869c47 100644 --- a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/BaseExtensionConfigurations.kt +++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/BaseExtensionConfigurations.kt @@ -24,7 +24,6 @@ internal fun BaseExtension.configureCompose(project: Project) { contains(":features:onboarding") || // TODO: divide on api/impl after migrating all onboarding to module contains(Regex(pattern = ":presentation\$")) || contains(Regex(pattern = ":app\$")) || // TODO: [REDACTED_JIRA] - contains(Regex(pattern = ":features:manage-tokens:api\$")) || // provides Composable function contains(Regex(pattern = ":features:markets:api\$")) || // provides Composable function contains(Regex(pattern = ":impl\$")) } From 0c2999918a9ca377206e9a468c1fdee4fe74628b Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Jun 2024 19:42:09 +0400 Subject: [PATCH 2/8] Updated on 2026-08-14 --- .../preview/PreviewManageTokensComponent.kt | 45 ++++++++- .../managetokens/entity/CurrencyItemUM.kt | 23 +++++ .../managetokens/entity/ManageTokensUM.kt | 10 ++ .../managetokens/ui/ManageTokensScreen.kt | 95 ++++++++++++++++++- 4 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/ManageTokensUM.kt diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt index 5bf83bf727..7fad0628a4 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt @@ -2,15 +2,58 @@ package com.tangem.features.managetokens.component.preview import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import com.tangem.core.ui.components.currency.tokenicon.TokenIconState +import com.tangem.core.ui.components.rows.model.ChainRowUM +import com.tangem.core.ui.extensions.stringReference import com.tangem.features.managetokens.component.ManageTokensComponent +import com.tangem.features.managetokens.entity.CurrencyItemUM import com.tangem.features.managetokens.entity.ManageTokensUM +import com.tangem.features.managetokens.impl.R import com.tangem.features.managetokens.ui.ManageTokensScreen -import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList internal class PreviewManageTokensComponent : ManageTokensComponent { private val previewState: ManageTokensUM = ManageTokensUM( popBack = {}, + items = List(size = 30) { index -> + if (index < 2) { + CurrencyItemUM.Custom( + id = index.toString(), + model = ChainRowUM( + name = stringReference("Custom $index"), + type = stringReference("CM$index"), + icon = TokenIconState.CustomTokenIcon( + tint = Color.White, + background = Color.Black, + networkBadgeIconResId = R.drawable.img_eth_22, + isGrayscale = false, + showCustomBadge = true, + ), + showCustom = true, + ), + onRemoveClick = {}, + ) + } else { + CurrencyItemUM.Basic( + id = index.toString(), + model = ChainRowUM( + name = stringReference("Basic $index"), + type = stringReference("BT$index"), + icon = TokenIconState.CoinIcon( + url = null, + fallbackResId = R.drawable.img_btc_22, + isGrayscale = false, + showCustomBadge = false, + ), + showCustom = false, + ), + isExpanded = false, + onExpandClick = {}, + ) + } + }.toImmutableList(), ) @Composable diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt new file mode 100644 index 0000000000..1fd59cebc8 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt @@ -0,0 +1,23 @@ +package com.tangem.features.managetokens.entity + +import androidx.compose.runtime.Immutable +import com.tangem.core.ui.components.rows.model.ChainRowUM + +@Immutable +internal sealed class CurrencyItemUM { + + abstract val id: String + + data class Basic( + override val id: String, + val model: ChainRowUM, + val isExpanded: Boolean, + val onExpandClick: () -> Unit, + ) : CurrencyItemUM() + + data class Custom( + override val id: String, + val model: ChainRowUM, + val onRemoveClick: () -> Unit, + ) : CurrencyItemUM() +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/ManageTokensUM.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/ManageTokensUM.kt new file mode 100644 index 0000000000..3bd1757c82 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/ManageTokensUM.kt @@ -0,0 +1,10 @@ +package com.tangem.features.managetokens.entity + +import androidx.compose.runtime.Immutable +import kotlinx.collections.immutable.ImmutableList + +@Immutable +internal data class ManageTokensUM( + val popBack: () -> Unit, + val items: ImmutableList, +) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt index 8a4be14f9c..7ceeac64f8 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt @@ -2,14 +2,33 @@ package com.tangem.features.managetokens.ui import android.content.res.Configuration import androidx.activity.compose.BackHandler +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.buttons.SecondarySmallButton +import com.tangem.core.ui.components.buttons.SmallButtonConfig +import com.tangem.core.ui.components.rows.ChainRow +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview -import com.tangem.feature.managetokens.component.preview.PreviewManageTokensComponent -import com.tangem.feature.managetokens.entity.ManageTokensUM +import com.tangem.features.managetokens.component.preview.PreviewManageTokensComponent +import com.tangem.features.managetokens.entity.CurrencyItemUM +import com.tangem.features.managetokens.entity.ManageTokensUM +import com.tangem.features.managetokens.impl.R +import kotlinx.collections.immutable.ImmutableList @Composable internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modifier) { @@ -17,12 +36,80 @@ internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modi Scaffold( modifier = modifier, - content = { - TODO("Not yet implemented") + containerColor = TangemTheme.colors.background.primary, + content = { innerPadding -> + Currencies( + modifier = Modifier + .padding(innerPadding) + .fillMaxSize(), + items = state.items, + ) }, ) } +private const val CHEVRON_ROTATION_EXPANDED = 180f +private const val CHEVRON_ROTATION_COLLAPSED = 0f + +@Composable +private fun Currencies(items: ImmutableList, modifier: Modifier = Modifier) { + LazyColumn( + modifier = modifier, + ) { + items( + items = items, + key = CurrencyItemUM::id, + ) { item -> + when (item) { + is CurrencyItemUM.Basic -> { + ChainRow( + modifier = Modifier.fillMaxWidth(), + model = item.model, + action = { + IconButton( + modifier = Modifier.size(TangemTheme.dimens.size32), + onClick = item.onExpandClick, + ) { + val rotation by animateFloatAsState( + targetValue = if (item.isExpanded) { + CHEVRON_ROTATION_EXPANDED + } else { + CHEVRON_ROTATION_COLLAPSED + }, + label = "chevron_rotation", + ) + + Icon( + modifier = Modifier + .rotate(rotation) + .size(TangemTheme.dimens.size24), + painter = painterResource(id = R.drawable.ic_chevron_24), + tint = TangemTheme.colors.icon.informative, + contentDescription = null, + ) + } + }, + ) + } + is CurrencyItemUM.Custom -> { + ChainRow( + modifier = Modifier.fillMaxWidth(), + model = item.model, + action = { + SecondarySmallButton( + config = SmallButtonConfig( + text = resourceReference(R.string.manage_tokens_remove), + onClick = item.onRemoveClick, + ), + ) + }, + ) + } + } + } + } +} + // region Preview @Preview(showBackground = true, widthDp = 360, heightDp = 800) @Preview(showBackground = true, widthDp = 360, heightDp = 800, uiMode = Configuration.UI_MODE_NIGHT_YES) From 88f84097f7f90957bb8e1a3c643c662655322771 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 26 Jun 2024 20:19:55 +0400 Subject: [PATCH 3/8] Updated on 2026-08-14 --- .../preview/PreviewManageTokensComponent.kt | 172 +++++++++++++----- .../managetokens/entity/CurrencyItemUM.kt | 16 +- .../managetokens/entity/CurrencyNetworkUM.kt | 12 ++ .../managetokens/ui/ManageTokensScreen.kt | 147 ++++++++++----- 4 files changed, 261 insertions(+), 86 deletions(-) create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyNetworkUM.kt diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt index 7fad0628a4..9abc1cde2c 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt @@ -1,66 +1,156 @@ package com.tangem.features.managetokens.component.preview import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import com.tangem.core.ui.components.currency.tokenicon.TokenIconState +import androidx.compose.ui.util.fastForEachIndexed +import com.tangem.core.ui.components.currency.icon.CurrencyIconState +import com.tangem.core.ui.components.rows.model.BlockchainRowUM import com.tangem.core.ui.components.rows.model.ChainRowUM import com.tangem.core.ui.extensions.stringReference 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.ManageTokensUM import com.tangem.features.managetokens.impl.R import com.tangem.features.managetokens.ui.ManageTokensScreen +import kotlinx.collections.immutable.mutate import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.update +import kotlin.random.Random internal class PreviewManageTokensComponent : ManageTokensComponent { - private val previewState: ManageTokensUM = ManageTokensUM( - popBack = {}, - items = List(size = 30) { index -> - if (index < 2) { - CurrencyItemUM.Custom( - id = index.toString(), - model = ChainRowUM( - name = stringReference("Custom $index"), - type = stringReference("CM$index"), - icon = TokenIconState.CustomTokenIcon( - tint = Color.White, - background = Color.Black, - networkBadgeIconResId = R.drawable.img_eth_22, - isGrayscale = false, - showCustomBadge = true, - ), - showCustom = true, - ), - onRemoveClick = {}, - ) - } else { - CurrencyItemUM.Basic( - id = index.toString(), - model = ChainRowUM( - name = stringReference("Basic $index"), - type = stringReference("BT$index"), - icon = TokenIconState.CoinIcon( - url = null, - fallbackResId = R.drawable.img_btc_22, - isGrayscale = false, - showCustomBadge = false, - ), - showCustom = false, - ), - isExpanded = false, - onExpandClick = {}, - ) - } - }.toImmutableList(), + private var items = List(size = 30) { index -> + if (index < 2) { + getCustomItem(index) + } else { + getBasicItem(index) + } + }.toPersistentList() + + private val previewState = MutableStateFlow( + value = ManageTokensUM( + popBack = {}, + items = items, + ), ) @Composable override fun Content(modifier: Modifier) { + val state by previewState.collectAsState() + ManageTokensScreen( modifier = modifier, - state = previewState, + state = state, ) } + + private fun getCustomItem(index: Int) = CurrencyItemUM.Custom( + id = index.toString(), + model = ChainRowUM( + name = stringReference("Custom token $index"), + type = stringReference("CT$index"), + icon = CurrencyIconState.CustomTokenIcon( + tint = Color.White, + background = Color.Black, + networkBadgeIconResId = R.drawable.img_eth_22, + isGrayscale = false, + showCustomBadge = true, + ), + showCustom = true, + ), + onRemoveClick = {}, + ) + + private fun getBasicItem(index: Int) = CurrencyItemUM.Basic( + id = index.toString(), + model = ChainRowUM( + name = stringReference("Currency $index"), + type = stringReference("C$index"), + icon = CurrencyIconState.CoinIcon( + url = null, + fallbackResId = R.drawable.img_btc_22, + isGrayscale = false, + showCustomBadge = false, + ), + showCustom = false, + ), + networks = CurrencyItemUM.Basic.NetworksUM.Collapsed, + onExpandClick = { toggleCurrency(index) }, + ) + + private fun getCurrencyNetworks(currencyIndex: Int) = List(size = 5) { networkIndex -> + val selectedIndex = Random.nextInt(from = 0, until = 5) + + CurrencyNetworkUM( + id = networkIndex.toString(), + model = BlockchainRowUM( + name = stringReference("NETWORK$networkIndex"), + type = stringReference("N$networkIndex"), + icon = CurrencyIconState.Locked, + isAccented = networkIndex == 0, + usePrimaryTextColor = networkIndex == selectedIndex, + ), + isSelected = networkIndex == selectedIndex, + onSelectedStateChange = { toggleNetwork(currencyIndex, networkIndex, isSelected = it) }, + ) + }.toImmutableList() + + private fun toggleCurrency(index: Int) { + val updatedItem = when (val item = items[index]) { + is CurrencyItemUM.Basic -> item.copy( + networks = if (item.networks is CurrencyItemUM.Basic.NetworksUM.Collapsed) { + CurrencyItemUM.Basic.NetworksUM.Expanded(getCurrencyNetworks(index)) + } else { + CurrencyItemUM.Basic.NetworksUM.Collapsed + }, + ) + is CurrencyItemUM.Custom -> return + } + + previewState.update { state -> + items = items.mutate { + it[index] = updatedItem + } + state.copy(items = items) + } + } + + private fun toggleNetwork(currencyIndex: Int, networkIndex: Int, isSelected: Boolean) { + val updatedItem = when (val item = items[currencyIndex]) { + is CurrencyItemUM.Basic -> { + val updatedNetworks = (item.networks as? CurrencyItemUM.Basic.NetworksUM.Expanded) + ?.copy( + networks = item.networks.networks.toPersistentList().mutate { + it.fastForEachIndexed { index, network -> + if (index == networkIndex) { + it[index] = network.copy( + model = network.model.copy( + usePrimaryTextColor = isSelected, + ), + isSelected = isSelected, + ) + } + } + }, + ) + ?: return + + item.copy(networks = updatedNetworks) + } + is CurrencyItemUM.Custom -> return + } + + previewState.update { state -> + items = items.mutate { + it[currencyIndex] = updatedItem + } + state.copy(items = items) + } + } } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt index 1fd59cebc8..3cd78d349a 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt @@ -2,6 +2,7 @@ package com.tangem.features.managetokens.entity import androidx.compose.runtime.Immutable import com.tangem.core.ui.components.rows.model.ChainRowUM +import kotlinx.collections.immutable.ImmutableList @Immutable internal sealed class CurrencyItemUM { @@ -11,9 +12,20 @@ internal sealed class CurrencyItemUM { data class Basic( override val id: String, val model: ChainRowUM, - val isExpanded: Boolean, + val networks: NetworksUM, val onExpandClick: () -> Unit, - ) : CurrencyItemUM() + ) : CurrencyItemUM() { + + @Immutable + sealed class NetworksUM { + + data object Collapsed : NetworksUM() + + data class Expanded( + val networks: ImmutableList, + ) : NetworksUM() + } + } data class Custom( override val id: String, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyNetworkUM.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyNetworkUM.kt new file mode 100644 index 0000000000..8ed8dc5f9d --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyNetworkUM.kt @@ -0,0 +1,12 @@ +package com.tangem.features.managetokens.entity + +import androidx.compose.runtime.Immutable +import com.tangem.core.ui.components.rows.model.BlockchainRowUM + +@Immutable +internal data class CurrencyNetworkUM( + val id: String, + val model: BlockchainRowUM, + val isSelected: Boolean, + val onSelectedStateChange: (Boolean) -> Unit, +) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt index 7ceeac64f8..af11b22917 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt @@ -2,11 +2,9 @@ package com.tangem.features.managetokens.ui import android.content.res.Configuration import androidx.activity.compose.BackHandler +import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Icon @@ -14,22 +12,31 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.util.fastForEachIndexed +import com.tangem.core.ui.components.TangemSwitch import com.tangem.core.ui.components.buttons.SecondarySmallButton import com.tangem.core.ui.components.buttons.SmallButtonConfig +import com.tangem.core.ui.components.rows.ArrowRow +import com.tangem.core.ui.components.rows.BlockchainRow import com.tangem.core.ui.components.rows.ChainRow import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.features.managetokens.component.preview.PreviewManageTokensComponent import com.tangem.features.managetokens.entity.CurrencyItemUM +import com.tangem.features.managetokens.entity.CurrencyItemUM.Basic.NetworksUM import com.tangem.features.managetokens.entity.ManageTokensUM import com.tangem.features.managetokens.impl.R import kotlinx.collections.immutable.ImmutableList +private const val CHEVRON_ROTATION_EXPANDED = 180f +private const val CHEVRON_ROTATION_COLLAPSED = 0f + @Composable internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modifier) { BackHandler(onBack = state.popBack) @@ -48,9 +55,6 @@ internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modi ) } -private const val CHEVRON_ROTATION_EXPANDED = 180f -private const val CHEVRON_ROTATION_COLLAPSED = 0f - @Composable private fun Currencies(items: ImmutableList, modifier: Modifier = Modifier) { LazyColumn( @@ -62,47 +66,15 @@ private fun Currencies(items: ImmutableList, modifier: Modifier ) { item -> when (item) { is CurrencyItemUM.Basic -> { - ChainRow( + BasicCurrencyItem( modifier = Modifier.fillMaxWidth(), - model = item.model, - action = { - IconButton( - modifier = Modifier.size(TangemTheme.dimens.size32), - onClick = item.onExpandClick, - ) { - val rotation by animateFloatAsState( - targetValue = if (item.isExpanded) { - CHEVRON_ROTATION_EXPANDED - } else { - CHEVRON_ROTATION_COLLAPSED - }, - label = "chevron_rotation", - ) - - Icon( - modifier = Modifier - .rotate(rotation) - .size(TangemTheme.dimens.size24), - painter = painterResource(id = R.drawable.ic_chevron_24), - tint = TangemTheme.colors.icon.informative, - contentDescription = null, - ) - } - }, + item = item, ) } is CurrencyItemUM.Custom -> { - ChainRow( + CustomCurrencyItem( modifier = Modifier.fillMaxWidth(), - model = item.model, - action = { - SecondarySmallButton( - config = SmallButtonConfig( - text = resourceReference(R.string.manage_tokens_remove), - onClick = item.onRemoveClick, - ), - ) - }, + item = item, ) } } @@ -110,6 +82,95 @@ private fun Currencies(items: ImmutableList, modifier: Modifier } } +@Composable +private fun CustomCurrencyItem(item: CurrencyItemUM.Custom, modifier: Modifier = Modifier) { + ChainRow( + modifier = modifier, + model = item.model, + action = { + SecondarySmallButton( + config = SmallButtonConfig( + text = resourceReference(R.string.manage_tokens_remove), + onClick = item.onRemoveClick, + ), + ) + }, + ) +} + +@Composable +private fun BasicCurrencyItem(item: CurrencyItemUM.Basic, modifier: Modifier = Modifier) { + val isExpanded = item.networks is NetworksUM.Expanded + + Column(modifier = modifier) { + ChainRow( + model = item.model, + action = { + IconButton( + modifier = Modifier.size(TangemTheme.dimens.size32), + onClick = item.onExpandClick, + ) { + val rotation by animateFloatAsState( + targetValue = if (isExpanded) { + CHEVRON_ROTATION_EXPANDED + } else { + CHEVRON_ROTATION_COLLAPSED + }, + label = "chevron_rotation", + ) + + Icon( + modifier = Modifier + .rotate(rotation) + .size(TangemTheme.dimens.size24), + painter = painterResource(id = R.drawable.ic_chevron_24), + tint = TangemTheme.colors.icon.informative, + contentDescription = null, + ) + } + }, + ) + + NetworksList( + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing12), + networks = item.networks, + currencyId = item.id, + ) + } +} + +@Composable +private fun ColumnScope.NetworksList(networks: NetworksUM, currencyId: String, modifier: Modifier = Modifier) { + AnimatedVisibility( + modifier = modifier, + visible = networks is NetworksUM.Expanded, + label = "networks_visibility", + ) { + Column { + val items = (networks as? NetworksUM.Expanded)?.networks + // to keep items on collapse, and avoid animation cancellation + val rememberedItems = remember(key1 = currencyId) { items } + + (items ?: rememberedItems)?.fastForEachIndexed { index, network -> + ArrowRow( + isLastItem = index == items?.lastIndex, + content = { + BlockchainRow( + model = network.model, + action = { + TangemSwitch( + checked = network.isSelected, + onCheckedChange = network.onSelectedStateChange, + ) + }, + ) + }, + ) + } + } + } +} + // region Preview @Preview(showBackground = true, widthDp = 360, heightDp = 800) @Preview(showBackground = true, widthDp = 360, heightDp = 800, uiMode = Configuration.UI_MODE_NIGHT_YES) From 21f95cf1b35128f5f609d278ad129ede8cba54b0 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 27 Jun 2024 13:12:31 +0400 Subject: [PATCH 4/8] Updated on 2026-08-14 --- .../preview/PreviewManageTokensComponent.kt | 100 ++++++++--- .../managetokens/entity/CurrencyItemUM.kt | 5 +- .../managetokens/entity/ManageTokensUM.kt | 5 + .../managetokens/ui/ManageTokensScreen.kt | 162 ++++++++++++++++-- 4 files changed, 232 insertions(+), 40 deletions(-) diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt index 9abc1cde2c..d68e6ca5d0 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt @@ -7,9 +7,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.util.fastForEachIndexed import com.tangem.core.ui.components.currency.icon.CurrencyIconState +import com.tangem.core.ui.components.fields.entity.SearchBarUM import com.tangem.core.ui.components.rows.model.BlockchainRowUM import com.tangem.core.ui.components.rows.model.ChainRowUM -import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.resourceReference import com.tangem.features.managetokens.component.ManageTokensComponent import com.tangem.features.managetokens.entity.CurrencyItemUM import com.tangem.features.managetokens.entity.CurrencyNetworkUM @@ -21,25 +22,55 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update -import kotlin.random.Random internal class PreviewManageTokensComponent : ManageTokensComponent { - private var items = List(size = 30) { index -> - if (index < 2) { - getCustomItem(index) - } else { - getBasicItem(index) - } - }.toPersistentList() + private val changedItemsIds: MutableSet = mutableSetOf() + + private var items = initItems() private val previewState = MutableStateFlow( value = ManageTokensUM( popBack = {}, items = items, + search = SearchBarUM( + placeholderText = resourceReference(R.string.manage_tokens_search_placeholder), + query = "", + onQueryChange = ::searchCurrencies, + isActive = false, + onActiveChange = ::toggleSearchBar, + ), + hasChanges = false, + onSaveClick = {}, + onAddCustomToken = {}, ), ) + private fun searchCurrencies(query: String) { + previewState.update { state -> + items = if (query.isBlank()) { + initItems() + } else { + items.filter { currency -> + currency.model.name.contains(query, ignoreCase = true) + }.toPersistentList() + } + + state.copy( + search = state.search.copy(query = query), + items = items, + ) + } + } + + private fun toggleSearchBar(isActive: Boolean) { + previewState.update { state -> + state.copy( + search = state.search.copy(isActive = isActive), + ) + } + } + @Composable override fun Content(modifier: Modifier) { val state by previewState.collectAsState() @@ -50,15 +81,23 @@ internal class PreviewManageTokensComponent : ManageTokensComponent { ) } + private fun initItems() = List(size = 30) { index -> + if (index < 2) { + getCustomItem(index) + } else { + getBasicItem(index) + } + }.toPersistentList() + private fun getCustomItem(index: Int) = CurrencyItemUM.Custom( id = index.toString(), model = ChainRowUM( - name = stringReference("Custom token $index"), - type = stringReference("CT$index"), + name = "Custom token $index", + type = "CT$index", icon = CurrencyIconState.CustomTokenIcon( tint = Color.White, background = Color.Black, - networkBadgeIconResId = R.drawable.img_eth_22, + topBadgeIconResId = R.drawable.img_eth_22, isGrayscale = false, showCustomBadge = true, ), @@ -70,8 +109,8 @@ internal class PreviewManageTokensComponent : ManageTokensComponent { private fun getBasicItem(index: Int) = CurrencyItemUM.Basic( id = index.toString(), model = ChainRowUM( - name = stringReference("Currency $index"), - type = stringReference("C$index"), + name = "Currency $index", + type = "C$index", icon = CurrencyIconState.CoinIcon( url = null, fallbackResId = R.drawable.img_btc_22, @@ -85,18 +124,16 @@ internal class PreviewManageTokensComponent : ManageTokensComponent { ) private fun getCurrencyNetworks(currencyIndex: Int) = List(size = 5) { networkIndex -> - val selectedIndex = Random.nextInt(from = 0, until = 5) - CurrencyNetworkUM( id = networkIndex.toString(), model = BlockchainRowUM( - name = stringReference("NETWORK$networkIndex"), - type = stringReference("N$networkIndex"), - icon = CurrencyIconState.Locked, - isAccented = networkIndex == 0, - usePrimaryTextColor = networkIndex == selectedIndex, + name = "NETWORK$networkIndex", + type = "N$networkIndex", + iconResId = R.drawable.ic_eth_16, + isMainNetwork = networkIndex == 0, + isSelected = false, ), - isSelected = networkIndex == selectedIndex, + isSelected = false, onSelectedStateChange = { toggleNetwork(currencyIndex, networkIndex, isSelected = it) }, ) }.toImmutableList() @@ -131,7 +168,12 @@ internal class PreviewManageTokensComponent : ManageTokensComponent { if (index == networkIndex) { it[index] = network.copy( model = network.model.copy( - usePrimaryTextColor = isSelected, + iconResId = if (isSelected) { + R.drawable.img_eth_22 + } else { + R.drawable.ic_eth_16 + }, + isSelected = isSelected, ), isSelected = isSelected, ) @@ -146,11 +188,21 @@ internal class PreviewManageTokensComponent : ManageTokensComponent { is CurrencyItemUM.Custom -> return } + val id = "${currencyIndex}_$networkIndex" + if (changedItemsIds.contains(id)) { + changedItemsIds.remove(id) + } else { + changedItemsIds.add(id) + } + previewState.update { state -> items = items.mutate { it[currencyIndex] = updatedItem } - state.copy(items = items) + state.copy( + items = items, + hasChanges = changedItemsIds.isNotEmpty(), + ) } } } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt index 3cd78d349a..0cfc505545 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/CurrencyItemUM.kt @@ -8,10 +8,11 @@ import kotlinx.collections.immutable.ImmutableList internal sealed class CurrencyItemUM { abstract val id: String + abstract val model: ChainRowUM data class Basic( override val id: String, - val model: ChainRowUM, + override val model: ChainRowUM, val networks: NetworksUM, val onExpandClick: () -> Unit, ) : CurrencyItemUM() { @@ -29,7 +30,7 @@ internal sealed class CurrencyItemUM { data class Custom( override val id: String, - val model: ChainRowUM, + override val model: ChainRowUM, val onRemoveClick: () -> Unit, ) : CurrencyItemUM() } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/ManageTokensUM.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/ManageTokensUM.kt index 3bd1757c82..c8678bdd38 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/ManageTokensUM.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/ManageTokensUM.kt @@ -1,10 +1,15 @@ package com.tangem.features.managetokens.entity import androidx.compose.runtime.Immutable +import com.tangem.core.ui.components.fields.entity.SearchBarUM import kotlinx.collections.immutable.ImmutableList @Immutable internal data class ManageTokensUM( val popBack: () -> Unit, val items: ImmutableList, + val search: SearchBarUM, + val hasChanges: Boolean, + val onAddCustomToken: () -> Unit, + val onSaveClick: () -> Unit, ) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt index af11b22917..462b1e2e79 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt @@ -2,25 +2,33 @@ package com.tangem.features.managetokens.ui import android.content.res.Configuration import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.* import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Scaffold +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.util.fastForEachIndexed +import com.tangem.core.ui.components.BottomFade +import com.tangem.core.ui.components.PrimaryButtonIconEnd import com.tangem.core.ui.components.TangemSwitch +import com.tangem.core.ui.components.appbar.models.TangemTopAppBarColors import com.tangem.core.ui.components.buttons.SecondarySmallButton import com.tangem.core.ui.components.buttons.SmallButtonConfig +import com.tangem.core.ui.components.fields.SearchBar +import com.tangem.core.ui.components.fields.entity.SearchBarUM import com.tangem.core.ui.components.rows.ArrowRow import com.tangem.core.ui.components.rows.BlockchainRow import com.tangem.core.ui.components.rows.ChainRow @@ -37,29 +45,151 @@ import kotlinx.collections.immutable.ImmutableList private const val CHEVRON_ROTATION_EXPANDED = 180f private const val CHEVRON_ROTATION_COLLAPSED = 0f +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modifier) { + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + BackHandler(onBack = state.popBack) Scaffold( - modifier = modifier, + modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), containerColor = TangemTheme.colors.background.primary, + topBar = { + TopBar( + scrollBehavior = scrollBehavior, + onAddCustomToken = state.onAddCustomToken, + onPopBack = state.popBack, + ) + }, content = { innerPadding -> - Currencies( + Content( modifier = Modifier .padding(innerPadding) .fillMaxSize(), - items = state.items, + state = state, + ) + }, + floatingActionButtonPosition = FabPosition.Center, + floatingActionButton = { + SaveChangesButton( + modifier = Modifier + .padding(horizontal = TangemTheme.dimens.spacing16) + .fillMaxWidth(), + isVisible = state.hasChanges, + onClick = state.onSaveClick, ) }, ) } @Composable -private fun Currencies(items: ImmutableList, modifier: Modifier = Modifier) { +@OptIn(ExperimentalMaterial3Api::class) +private fun TopBar( + scrollBehavior: TopAppBarScrollBehavior, + onPopBack: () -> Unit, + onAddCustomToken: () -> Unit, + modifier: Modifier = Modifier, +) { + TopAppBar( + modifier = modifier, + scrollBehavior = scrollBehavior, + colors = TangemTopAppBarColors.copy( + containerColor = TangemTheme.colors.background.primary, + scrolledContainerColor = TangemTheme.colors.background.primary, + ), + navigationIcon = { + IconButton( + modifier = Modifier.size(TangemTheme.dimens.size32), + onClick = onPopBack, + ) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = R.drawable.ic_back_24), + contentDescription = null, + ) + } + }, + title = { + Text( + text = stringResource(id = R.string.main_manage_tokens), + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + ) + }, + actions = { + IconButton( + modifier = Modifier.size(TangemTheme.dimens.size32), + onClick = onAddCustomToken, + ) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size24), + painter = painterResource(id = R.drawable.ic_plus_24), + contentDescription = null, + ) + } + }, + ) +} + +@Composable +private fun SaveChangesButton(isVisible: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { + AnimatedVisibility( + modifier = modifier, + visible = isVisible, + enter = fadeIn(), + exit = fadeOut(), + label = "save_button_visibility", + ) { + PrimaryButtonIconEnd( + text = stringResource(id = R.string.common_save), + iconResId = R.drawable.ic_tangem_24, + onClick = onClick, + ) + } +} + +@Composable +private fun Content(state: ManageTokensUM, modifier: Modifier = Modifier) { + Box(modifier = modifier) { + Currencies( + modifier = Modifier.fillMaxSize(), + items = state.items, + search = state.search, + ) + + AnimatedVisibility( + modifier = Modifier + .align(Alignment.BottomCenter) + .fillMaxWidth(), + visible = state.hasChanges, + label = "bottom_fade_visibility", + ) { + BottomFade() + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +private fun Currencies(items: ImmutableList, search: SearchBarUM, modifier: Modifier = Modifier) { LazyColumn( modifier = modifier, ) { + stickyHeader(key = "search") { + Column( + modifier = Modifier + .background(TangemTheme.colors.background.primary) + .padding( + vertical = TangemTheme.dimens.spacing12, + horizontal = TangemTheme.dimens.spacing16, + ) + .fillMaxWidth(), + ) { + SearchBar(state = search) + } + } + items( items = items, key = CurrencyItemUM::id, @@ -132,7 +262,7 @@ private fun BasicCurrencyItem(item: CurrencyItemUM.Basic, modifier: Modifier = M ) NetworksList( - modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing12), + modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16), networks = item.networks, currencyId = item.id, ) @@ -140,20 +270,24 @@ private fun BasicCurrencyItem(item: CurrencyItemUM.Basic, modifier: Modifier = M } @Composable -private fun ColumnScope.NetworksList(networks: NetworksUM, currencyId: String, modifier: Modifier = Modifier) { +private fun NetworksList(networks: NetworksUM, currencyId: String, modifier: Modifier = Modifier) { AnimatedVisibility( modifier = modifier, visible = networks is NetworksUM.Expanded, + enter = fadeIn() + expandVertically(), + exit = fadeOut() + shrinkVertically(), label = "networks_visibility", ) { Column { val items = (networks as? NetworksUM.Expanded)?.networks - // to keep items on collapse, and avoid animation cancellation - val rememberedItems = remember(key1 = currencyId) { items } - (items ?: rememberedItems)?.fastForEachIndexed { index, network -> + // To keep items on collapse and avoid animation cancellation + val rememberedItems = remember(key1 = currencyId) { items } + val currentItems = items ?: rememberedItems + + currentItems?.fastForEachIndexed { index, network -> ArrowRow( - isLastItem = index == items?.lastIndex, + isLastItem = index == currentItems.lastIndex, content = { BlockchainRow( model = network.model, From 2c8b85a34ff3d7c135443229c9b21f9447c90c8a Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 11 Jul 2024 13:14:52 +0400 Subject: [PATCH 5/8] Updated on 2026-08-14 --- .../managetokens/ui/ManageTokensScreen.kt | 75 ++++--------------- 1 file changed, 15 insertions(+), 60 deletions(-) diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt index 462b1e2e79..bfe586ebd9 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt @@ -9,14 +9,16 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material3.* +import androidx.compose.material3.FabPosition +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -24,7 +26,8 @@ import androidx.compose.ui.util.fastForEachIndexed import com.tangem.core.ui.components.BottomFade import com.tangem.core.ui.components.PrimaryButtonIconEnd import com.tangem.core.ui.components.TangemSwitch -import com.tangem.core.ui.components.appbar.models.TangemTopAppBarColors +import com.tangem.core.ui.components.appbar.TangemTopAppBar +import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM import com.tangem.core.ui.components.buttons.SecondarySmallButton import com.tangem.core.ui.components.buttons.SmallButtonConfig import com.tangem.core.ui.components.fields.SearchBar @@ -45,21 +48,22 @@ import kotlinx.collections.immutable.ImmutableList private const val CHEVRON_ROTATION_EXPANDED = 180f private const val CHEVRON_ROTATION_COLLAPSED = 0f -@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modifier) { - val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() - BackHandler(onBack = state.popBack) Scaffold( - modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + modifier = modifier, containerColor = TangemTheme.colors.background.primary, topBar = { - TopBar( - scrollBehavior = scrollBehavior, - onAddCustomToken = state.onAddCustomToken, - onPopBack = state.popBack, + TangemTopAppBar( + modifier = Modifier.statusBarsPadding(), + title = stringResource(id = R.string.main_manage_tokens), + startButton = TopAppBarButtonUM.Back(state.popBack), + endButton = TopAppBarButtonUM( + iconRes = R.drawable.ic_plus_24, + onIconClicked = state.onAddCustomToken, + ), ) }, content = { innerPadding -> @@ -83,55 +87,6 @@ internal fun ManageTokensScreen(state: ManageTokensUM, modifier: Modifier = Modi ) } -@Composable -@OptIn(ExperimentalMaterial3Api::class) -private fun TopBar( - scrollBehavior: TopAppBarScrollBehavior, - onPopBack: () -> Unit, - onAddCustomToken: () -> Unit, - modifier: Modifier = Modifier, -) { - TopAppBar( - modifier = modifier, - scrollBehavior = scrollBehavior, - colors = TangemTopAppBarColors.copy( - containerColor = TangemTheme.colors.background.primary, - scrolledContainerColor = TangemTheme.colors.background.primary, - ), - navigationIcon = { - IconButton( - modifier = Modifier.size(TangemTheme.dimens.size32), - onClick = onPopBack, - ) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size24), - painter = painterResource(id = R.drawable.ic_back_24), - contentDescription = null, - ) - } - }, - title = { - Text( - text = stringResource(id = R.string.main_manage_tokens), - style = TangemTheme.typography.subtitle1, - color = TangemTheme.colors.text.primary1, - ) - }, - actions = { - IconButton( - modifier = Modifier.size(TangemTheme.dimens.size32), - onClick = onAddCustomToken, - ) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size24), - painter = painterResource(id = R.drawable.ic_plus_24), - contentDescription = null, - ) - } - }, - ) -} - @Composable private fun SaveChangesButton(isVisible: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { AnimatedVisibility( From e416e2bb5b02618fc63d67b1b780cfea12fca209 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Jul 2024 15:06:47 +0400 Subject: [PATCH 6/8] Updated on 2026-08-14 --- .../core/ui/components/rows/BlockchainRow.kt | 2 +- .../core/ui/components/rows/ChainRow.kt | 26 +++++++------------ .../preview/PreviewManageTokensComponent.kt | 8 ++++-- .../managetokens/ui/ManageTokensScreen.kt | 5 +++- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/rows/BlockchainRow.kt b/core/ui/src/main/java/com/tangem/core/ui/components/rows/BlockchainRow.kt index d0341755a7..4f8edf75c4 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/rows/BlockchainRow.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/rows/BlockchainRow.kt @@ -29,7 +29,7 @@ fun BlockchainRow(model: BlockchainRowUM, action: @Composable BoxScope.() -> Uni modifier = modifier .heightIn(min = TangemTheme.dimens.size52) .padding( - vertical = TangemTheme.dimens.spacing16, + vertical = TangemTheme.dimens.spacing8, horizontal = TangemTheme.dimens.spacing8, ), icon = { diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/rows/ChainRow.kt b/core/ui/src/main/java/com/tangem/core/ui/components/rows/ChainRow.kt index 175ace75f5..c57b6ebc1a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/rows/ChainRow.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/rows/ChainRow.kt @@ -2,16 +2,17 @@ package com.tangem.core.ui.components.rows import android.content.res.Configuration import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import com.tangem.core.ui.R +import com.tangem.core.ui.components.TangemSwitch import com.tangem.core.ui.components.currency.icon.CurrencyIcon import com.tangem.core.ui.components.currency.icon.CurrencyIconState import com.tangem.core.ui.components.rows.model.ChainRowUM @@ -27,9 +28,10 @@ fun ChainRow(model: ChainRowUM, modifier: Modifier = Modifier, action: @Composab RowContentContainer( modifier = modifier .heightIn(min = TangemTheme.dimens.size68) + .padding(vertical = TangemTheme.dimens.spacing8) .padding( - vertical = TangemTheme.dimens.spacing12, - horizontal = TangemTheme.dimens.spacing14, + start = TangemTheme.dimens.spacing8, + end = TangemTheme.dimens.spacing12, ), horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), icon = { @@ -65,17 +67,7 @@ private fun Preview_ChainRow(@PreviewParameter(ChainRowParameterProvider::class) modifier = Modifier.background(TangemTheme.colors.background.primary), model = state, action = { - IconButton( - modifier = Modifier.size(TangemTheme.dimens.size32), - onClick = { /* [REDACTED_TODO_COMMENT]*/ }, - ) { - Icon( - modifier = Modifier.size(TangemTheme.dimens.size24), - tint = TangemTheme.colors.icon.informative, - painter = painterResource(id = R.drawable.ic_chevron_24), - contentDescription = null, - ) - } + TangemSwitch(onCheckedChange = {}, checked = false) }, ) } diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt index d68e6ca5d0..8fabf7cfd4 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewManageTokensComponent.kt @@ -119,11 +119,15 @@ internal class PreviewManageTokensComponent : ManageTokensComponent { ), showCustom = false, ), - networks = CurrencyItemUM.Basic.NetworksUM.Collapsed, + networks = if (index == 2) { + CurrencyItemUM.Basic.NetworksUM.Expanded(getCurrencyNetworks(index)) + } else { + CurrencyItemUM.Basic.NetworksUM.Collapsed + }, onExpandClick = { toggleCurrency(index) }, ) - private fun getCurrencyNetworks(currencyIndex: Int) = List(size = 5) { networkIndex -> + private fun getCurrencyNetworks(currencyIndex: Int) = List(size = 3) { networkIndex -> CurrencyNetworkUM( id = networkIndex.toString(), model = BlockchainRowUM( diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt index bfe586ebd9..5a29f66f24 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt @@ -217,7 +217,10 @@ private fun BasicCurrencyItem(item: CurrencyItemUM.Basic, modifier: Modifier = M ) NetworksList( - modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing16), + modifier = Modifier.padding( + start = TangemTheme.dimens.spacing10, + end = TangemTheme.dimens.spacing8, + ), networks = item.networks, currencyId = item.id, ) From 9cbe154b8efc18fdff4a815679fb2d36fe6da6ae Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Jul 2024 16:32:18 +0400 Subject: [PATCH 7/8] Updated on 2026-08-14 --- .../core/ui/components/fields/SearchBar.kt | 49 +++++++++++++++++-- .../managetokens/ui/ManageTokensScreen.kt | 5 +- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/fields/SearchBar.kt b/core/ui/src/main/java/com/tangem/core/ui/components/fields/SearchBar.kt index cf2abf3f5f..3de373a0e3 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/fields/SearchBar.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/fields/SearchBar.kt @@ -1,13 +1,17 @@ package com.tangem.core.ui.components.fields import android.content.res.Configuration +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.size +import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.focus.onFocusChanged @@ -18,6 +22,7 @@ import androidx.compose.ui.platform.SoftwareKeyboardController import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -33,8 +38,9 @@ import com.tangem.core.ui.res.TangemThemePreview fun SearchBar(state: SearchBarUM, modifier: Modifier = Modifier, colors: TextFieldColors = TangemSearchBarColors) { val keyboardController = LocalSoftwareKeyboardController.current val focusManager = LocalFocusManager.current + val interactionSource = remember { MutableInteractionSource() } - TextField( + BasicTextField( modifier = modifier .fillMaxWidth() .heightIn(min = TangemTheme.dimens.size48) @@ -47,6 +53,7 @@ fun SearchBar(state: SearchBarUM, modifier: Modifier = Modifier, colors: TextFie }, value = state.query, onValueChange = state.onQueryChange, + interactionSource = interactionSource, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Text, imeAction = ImeAction.Search, @@ -59,7 +66,43 @@ fun SearchBar(state: SearchBarUM, modifier: Modifier = Modifier, colors: TextFie ), singleLine = true, maxLines = 1, - textStyle = TangemTheme.typography.body2, + textStyle = TangemTheme.typography.body2.copy( + color = TangemTheme.colors.text.primary1, + ), + decorationBox = @Composable { innerTextField -> + DecorationBox( + state = state, + innerTextField = innerTextField, + interactionSource = interactionSource, + colors = colors, + focusManager = focusManager, + keyboardController = keyboardController, + ) + }, + ) +} + +@Suppress("LongParameterList") +@Composable +@OptIn(ExperimentalMaterial3Api::class) +private fun DecorationBox( + state: SearchBarUM, + innerTextField: @Composable () -> Unit, + interactionSource: MutableInteractionSource, + colors: TextFieldColors, + focusManager: FocusManager, + keyboardController: SoftwareKeyboardController?, +) { + TextFieldDefaults.DecorationBox( + value = state.query, + innerTextField = innerTextField, + enabled = true, + singleLine = true, + visualTransformation = VisualTransformation.None, + interactionSource = interactionSource, + shape = TangemTheme.shapes.roundedCornersXLarge, + colors = colors, + contentPadding = PaddingValues(all = TangemTheme.dimens.spacing12), leadingIcon = { Icon( modifier = Modifier.size(TangemTheme.dimens.size20), @@ -84,8 +127,6 @@ fun SearchBar(state: SearchBarUM, modifier: Modifier = Modifier, colors: TextFie overflow = TextOverflow.Ellipsis, ) }, - shape = TangemTheme.shapes.roundedCornersXLarge, - colors = colors, ) } diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt index 5a29f66f24..4f9b2f3874 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt @@ -136,9 +136,10 @@ private fun Currencies(items: ImmutableList, search: SearchBarUM modifier = Modifier .background(TangemTheme.colors.background.primary) .padding( - vertical = TangemTheme.dimens.spacing12, - horizontal = TangemTheme.dimens.spacing16, + top = TangemTheme.dimens.spacing16, + bottom = TangemTheme.dimens.spacing12, ) + .padding(horizontal = TangemTheme.dimens.spacing16) .fillMaxWidth(), ) { SearchBar(state = search) From adddbad4ae5c2dfe1cb60b362ba62b4694053e5a Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 18 Jul 2024 17:54:39 +0400 Subject: [PATCH 8/8] Updated on 2026-08-14 --- .../tangem/core/ui/components/TangemSwitch.kt | 18 ++++----- .../managetokens/ui/ManageTokensScreen.kt | 40 +++++++++---------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/TangemSwitch.kt b/core/ui/src/main/java/com/tangem/core/ui/components/TangemSwitch.kt index 8e0081a633..7b3c924e95 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/TangemSwitch.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/TangemSwitch.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.tangem.core.ui.res.TangemTheme @@ -23,6 +24,8 @@ import com.tangem.core.ui.res.TangemTheme @Composable fun TangemSwitch( onCheckedChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, checkedColor: Color = TangemTheme.colors.control.checked, uncheckedColor: Color = TangemTheme.colors.icon.informative, size: Dp = 48.dp, @@ -39,23 +42,20 @@ fun TangemSwitch( (if (isChecked) checkedColor else uncheckedColor) .copy(alpha = if (enabled) 1f else .4f) } - val interactionSource = remember { MutableInteractionSource() } Box( - modifier = Modifier + modifier = modifier .clickable( - interactionSource = interactionSource, - indication = null, - enabled = enabled, - ) { - onCheckedChange(!checked) - } - .indication( interactionSource = interactionSource, indication = rememberRipple( bounded = false, color = Color.Transparent, ), + enabled = enabled, + role = Role.Switch, + onClick = { + onCheckedChange(!checked) + }, ), ) { BoxWithConstraints( diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt index 4f9b2f3874..63a14af8d4 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/ManageTokensScreen.kt @@ -6,12 +6,12 @@ import androidx.compose.animation.* import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.ExperimentalFoundationApi 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.items import androidx.compose.material3.FabPosition import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -190,30 +190,26 @@ private fun BasicCurrencyItem(item: CurrencyItemUM.Basic, modifier: Modifier = M Column(modifier = modifier) { ChainRow( + modifier = Modifier.clickable(onClick = item.onExpandClick), model = item.model, action = { - IconButton( - modifier = Modifier.size(TangemTheme.dimens.size32), - onClick = item.onExpandClick, - ) { - val rotation by animateFloatAsState( - targetValue = if (isExpanded) { - CHEVRON_ROTATION_EXPANDED - } else { - CHEVRON_ROTATION_COLLAPSED - }, - label = "chevron_rotation", - ) + val rotation by animateFloatAsState( + targetValue = if (isExpanded) { + CHEVRON_ROTATION_EXPANDED + } else { + CHEVRON_ROTATION_COLLAPSED + }, + label = "chevron_rotation", + ) - Icon( - modifier = Modifier - .rotate(rotation) - .size(TangemTheme.dimens.size24), - painter = painterResource(id = R.drawable.ic_chevron_24), - tint = TangemTheme.colors.icon.informative, - contentDescription = null, - ) - } + Icon( + modifier = Modifier + .rotate(rotation) + .size(TangemTheme.dimens.size24), + painter = painterResource(id = R.drawable.ic_chevron_24), + tint = TangemTheme.colors.icon.informative, + contentDescription = null, + ) }, )