From 53100fe46a31f4511b89d21af29391a7d062cd08 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 21 Jun 2023 14:54:43 +0800 Subject: [PATCH] Updated on 2026-08-14 --- .../presentation/states/TokenItemState.kt | 6 +- .../states/TokensListStateHolder.kt | 2 + .../states/TokensListToolbarState.kt | 9 +- .../com/tangem/core/ui/components/Buttons.kt | 183 +++++------------- .../core/ui/extensions/TextReference.kt | 32 ++- .../tangem/core/ui/extensions/WrappedList.kt | 10 + .../ui/src/main/res/drawable/ic_filter_24.xml | 9 + features/wallet/impl/build.gradle.kts | 2 + .../presentation/common/WalletPreviewData.kt | 120 +++++++----- .../common/component/NetworkGroupItem.kt | 46 ++--- .../common/component/TokenItem.kt | 2 +- .../common/state/NetworkGroupState.kt | 21 -- .../organizetokens/OrganizeTokensScreen.kt | 2 +- .../OrganizeTokensStateHolder.kt | 8 +- .../wallet/state/WalletCardState.kt | 3 + .../wallet/state/WalletContentItemState.kt | 13 ++ .../wallet/state/WalletStateHolder.kt | 22 ++- .../presentation/wallet/ui/WalletScreen.kt | 135 ++++++++++++- .../wallet/ui/components/WalletCard.kt | 10 +- .../wallet/ui/components/WalletCardsList.kt | 78 ++++++++ .../wallet/ui/components/WalletHeader.kt | 123 ------------ .../wallet/ui/components/WalletTopBar.kt | 55 ++++++ .../wallet/viewmodels/WalletViewModel.kt | 4 +- 23 files changed, 495 insertions(+), 400 deletions(-) create mode 100644 core/ui/src/main/java/com/tangem/core/ui/extensions/WrappedList.kt create mode 100644 core/ui/src/main/res/drawable/ic_filter_24.xml delete mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/state/NetworkGroupState.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletContentItemState.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCardsList.kt delete mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletHeader.kt create mode 100644 features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletTopBar.kt diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokenItemState.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokenItemState.kt index df128ac9b4..790a83fb5f 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokenItemState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokenItemState.kt @@ -1,12 +1,16 @@ package com.tangem.tap.features.tokens.impl.presentation.states +import androidx.compose.runtime.Immutable import kotlinx.collections.immutable.ImmutableList /** - * Network item state + * Token item state. + * All subclasses is stable, but @Immutable annotation is required to use this sealed class like as + * field of TokensListStateHolder. * [REDACTED_AUTHOR] */ +@Immutable sealed interface TokenItemState { /** Token id */ diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt index e083f7991b..101cdc8f52 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListStateHolder.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.tokens.impl.presentation.states +import androidx.compose.runtime.Immutable import androidx.paging.LoadState import androidx.paging.PagingData import kotlinx.coroutines.flow.Flow @@ -9,6 +10,7 @@ import kotlinx.coroutines.flow.Flow * [REDACTED_AUTHOR] */ +@Immutable internal sealed interface TokensListStateHolder { /** Toolbar state */ diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListToolbarState.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListToolbarState.kt index b4104f692b..a269659991 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListToolbarState.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/presentation/states/TokensListToolbarState.kt @@ -1,6 +1,13 @@ package com.tangem.tap.features.tokens.impl.presentation.states -/** Toolbar state */ +import androidx.compose.runtime.Immutable + +/** + * Toolbar state. + * All subclasses is stable, but @Immutable annotation is required to use this sealed class like as + * field of TokensListStateHolder. + */ +@Immutable sealed interface TokensListToolbarState { /** Callback to be invoked when BackButton is being clicked */ diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt index 00a6b2ac03..5ca9a16de8 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt @@ -312,14 +312,8 @@ private fun TangemButton( textStyle: TextStyle = TangemTheme.typography.button, ) { Button( - modifier = modifier - .width(IntrinsicSize.Min) - .heightIn(min = size.toHeightDp()), - onClick = { - if (!showProgress) { - onClick() - } - }, + modifier = modifier.heightIn(min = size.toHeightDp()), + onClick = { if (!showProgress) onClick() }, enabled = enabled, elevation = elevation, shape = size.toShape(), @@ -588,59 +582,44 @@ private open class TangemButtonColors( // region Preview @Composable -private fun PrimaryButtonSample(modifier: Modifier = Modifier) { +private fun PrimaryButtonSample() { Column( - modifier = modifier - .background(TangemTheme.colors.background.primary), + modifier = Modifier.background(TangemTheme.colors.background.primary), + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), ) { - PrimaryButton( - modifier = Modifier.fillMaxWidth(), - text = "Manage tokens", - onClick = { /* no-op */ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - PrimaryButton( - modifier = Modifier.fillMaxWidth(), - showProgress = true, - text = "Manage tokens", - onClick = { /* no-op */ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) + PrimaryButton(modifier = Modifier.fillMaxWidth(), text = "Manage tokens", onClick = { }) + PrimaryButton(modifier = Modifier.fillMaxWidth(), showProgress = true, text = "Manage tokens", onClick = { }) PrimaryButtonIconEnd( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", iconResId = R.drawable.ic_tangem_24, - onClick = { /* no-op */ }, + onClick = { }, ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) PrimaryButtonIconStart( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", iconResId = R.drawable.ic_tangem_24, - onClick = { /* no-op */ }, + onClick = { }, ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) PrimaryButton( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", enabled = false, - onClick = { /* no-op */ }, + onClick = { }, ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) PrimaryButtonIconEnd( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", iconResId = R.drawable.ic_tangem_24, enabled = false, - onClick = { /* no-op */ }, + onClick = { }, ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) PrimaryButtonIconStart( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", iconResId = R.drawable.ic_tangem_24, enabled = false, - onClick = { /* no-op */ }, + onClick = { }, ) } } @@ -662,59 +641,44 @@ private fun PrimaryButtonPreview_Dark() { } @Composable -private fun SecondaryButtonSample(modifier: Modifier = Modifier) { +private fun SecondaryButtonSample() { Column( - modifier = modifier - .background(TangemTheme.colors.background.primary), + modifier = Modifier.background(TangemTheme.colors.background.primary), + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), ) { - SecondaryButton( - modifier = Modifier.fillMaxWidth(), - text = "Manage tokens", - onClick = { /* no-op */ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - SecondaryButton( - modifier = Modifier.fillMaxWidth(), - showProgress = true, - text = "Manage tokens", - onClick = { /* no-op */ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) + SecondaryButton(modifier = Modifier.fillMaxWidth(), text = "Manage tokens", onClick = { }) + SecondaryButton(modifier = Modifier.fillMaxWidth(), showProgress = true, text = "Manage tokens", onClick = { }) SecondaryButtonIconEnd( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", iconResId = R.drawable.ic_tangem_24, - onClick = { /* no-op */ }, + onClick = { }, ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) SecondaryButtonIconStart( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", iconResId = R.drawable.ic_tangem_24, - onClick = { /* no-op */ }, + onClick = { }, ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) SecondaryButton( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", enabled = false, - onClick = { /* no-op */ }, + onClick = { }, ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) SecondaryButtonIconEnd( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", iconResId = R.drawable.ic_tangem_24, enabled = false, - onClick = { /* no-op */ }, + onClick = { }, ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) SecondaryButtonIconStart( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", iconResId = R.drawable.ic_tangem_24, enabled = false, - onClick = { /* no-op */ }, + onClick = { }, ) } } @@ -736,50 +700,23 @@ private fun SecondaryButtonPreview_Dark() { } @Composable -private fun TextButtonSample(modifier: Modifier = Modifier) { +private fun TextButtonSample() { Column( - modifier = modifier - .background(TangemTheme.colors.background.primary), + modifier = Modifier.background(TangemTheme.colors.background.primary), + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), ) { - TextButton( - text = "Enabled", - onClick = { /* no-op */ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - TextButtonIconStart( - text = "Enabled", - iconResId = R.drawable.ic_plus_24, - onClick = { /* no-op */ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - TextButton( - text = "Enabled", - enabled = false, - onClick = { /* no-op */ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - TextButtonIconStart( - text = "Enabled", - iconResId = R.drawable.ic_plus_24, - enabled = false, - onClick = { /* no-op */ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - WarningTextButton( - text = "Delete", - onClick = { /* no-op */ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - SelectorButton( - text = "USD", - onClick = { /* no-op */ }, - ) + TextButton(text = "Enabled", onClick = { }) + TextButtonIconStart(text = "Enabled", iconResId = R.drawable.ic_plus_24, onClick = { }) + TextButton(text = "Enabled", enabled = false, onClick = { }) + TextButtonIconStart(text = "Enabled", iconResId = R.drawable.ic_plus_24, enabled = false, onClick = { }) + WarningTextButton(text = "Delete", onClick = { }) + SelectorButton(text = "USD", onClick = { }) } } @Preview(showBackground = true, widthDp = 360) @Composable -private fun TextButtonPreview_Light() { +private fun TextButtonPreview_LightTheme() { TangemTheme { TextButtonSample() } @@ -787,62 +724,30 @@ private fun TextButtonPreview_Light() { @Preview(showBackground = true, widthDp = 360) @Composable -private fun TextButtonPreview_Dark() { +private fun TextButtonPreview_DarkTheme() { TangemTheme(isDark = true) { TextButtonSample() } } @Composable -private fun ActionButtonSample(modifier: Modifier = Modifier) { +private fun ActionButtonSample() { Column( - modifier = modifier - .background(TangemTheme.colors.background.primary), + modifier = Modifier.background(TangemTheme.colors.background.primary), + verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), ) { - RoundedActionButton( - text = "Send", - iconResId = R.drawable.ic_arrow_up_24, - onClick = { /* [REDACTED_TODO_COMMENT]*/ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - ActionButton( - text = "Send", - iconResId = R.drawable.ic_arrow_up_24, - onClick = { /* [REDACTED_TODO_COMMENT]*/ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - BackgroundActionButton( - text = "Send", - iconResId = R.drawable.ic_arrow_up_24, - onClick = { /* [REDACTED_TODO_COMMENT]*/ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - RoundedActionButton( - text = "Send", - iconResId = R.drawable.ic_arrow_up_24, - enabled = false, - onClick = { /* [REDACTED_TODO_COMMENT]*/ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - ActionButton( - text = "Send", - iconResId = R.drawable.ic_arrow_up_24, - enabled = false, - onClick = { /* [REDACTED_TODO_COMMENT]*/ }, - ) - Divider(modifier = Modifier.padding(vertical = TangemTheme.dimens.spacing8)) - BackgroundActionButton( - text = "Send", - iconResId = R.drawable.ic_arrow_up_24, - enabled = false, - onClick = { /* [REDACTED_TODO_COMMENT]*/ }, - ) + RoundedActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = { }) + ActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = { }) + BackgroundActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = { }) + RoundedActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, enabled = false, onClick = { }) + ActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, enabled = false, onClick = { }) + BackgroundActionButton(text = "Send", iconResId = R.drawable.ic_arrow_up_24, enabled = false, onClick = { }) } } @Preview(showBackground = true, widthDp = 360) @Composable -private fun ActionButtonPreview_Light() { +private fun ActionButtonPreview_LightTheme() { TangemTheme { ActionButtonSample() } @@ -850,7 +755,7 @@ private fun ActionButtonPreview_Light() { @Preview(showBackground = true, widthDp = 360) @Composable -private fun ActionButtonPreview_Dark() { +private fun ActionButtonPreview_DarkTheme() { TangemTheme(isDark = true) { ActionButtonSample() } diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/TextReference.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/TextReference.kt index e70b0d7015..a27dcb58c4 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/extensions/TextReference.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/TextReference.kt @@ -2,22 +2,42 @@ package com.tangem.core.ui.extensions import androidx.annotation.StringRes import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.ui.res.stringResource +/** + * Utility class for creating text as [String] or [StringRes]. + * It necessary to use [Immutable] annotation because all sealed interface has runtime stability. + * All subclasses are stable. + */ +@Immutable sealed interface TextReference { - class Res(@StringRes val id: Int, val formatArgs: List = emptyList()) : TextReference { - constructor(@StringRes id: Int, vararg formatArgs: Any) : this(id, formatArgs.toList()) - } - class Str(val value: String) : TextReference + /** + * Text resource id + * + * @property id resource id + * @property formatArgs arguments + * + * Impossible to use [kotlinx.collections.immutable.ImmutableList] because [Any] is unstable. + */ + data class Res(@StringRes val id: Int, val formatArgs: WrappedList = WrappedList(emptyList())) : TextReference + + /** + * Text string + * + * @property value value + */ + data class Str(val value: String) : TextReference } +/** Get text */ @Composable @ReadOnlyComposable fun TextReference.resolveReference(): String { return when (this) { - is TextReference.Res -> stringResource(this.id, *this.formatArgs.toTypedArray()) - is TextReference.Str -> this.value + is TextReference.Res -> stringResource(id, *formatArgs.toTypedArray()) + is TextReference.Str -> value } } \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/WrappedList.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/WrappedList.kt new file mode 100644 index 0000000000..6f529c9574 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/WrappedList.kt @@ -0,0 +1,10 @@ +package com.tangem.core.ui.extensions + +import androidx.compose.runtime.Immutable + +/** +[REDACTED_AUTHOR] + */ +@JvmInline +@Immutable +value class WrappedList(val data: List) : List by data \ No newline at end of file diff --git a/core/ui/src/main/res/drawable/ic_filter_24.xml b/core/ui/src/main/res/drawable/ic_filter_24.xml new file mode 100644 index 0000000000..b88ca7dcef --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_filter_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/features/wallet/impl/build.gradle.kts b/features/wallet/impl/build.gradle.kts index 183e43c174..c639f23ac8 100644 --- a/features/wallet/impl/build.gradle.kts +++ b/features/wallet/impl/build.gradle.kts @@ -22,6 +22,8 @@ dependencies { implementation(deps.compose.ui.tooling) implementation(deps.compose.shimmer) implementation(deps.compose.accompanist.systemUiController) + + /** Other libraries */ implementation(deps.kotlin.immutable.collections) /** DI */ diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt index cdd8d70132..92c8d8f644 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/WalletPreviewData.kt @@ -1,13 +1,13 @@ package com.tangem.feature.wallet.presentation.common import com.tangem.core.ui.R -import com.tangem.feature.wallet.presentation.common.state.NetworkGroupState import com.tangem.feature.wallet.presentation.common.state.TokenItemState import com.tangem.feature.wallet.presentation.common.state.TokenItemState.TokenOptionsState import com.tangem.feature.wallet.presentation.organizetokens.DraggableItem import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensListState import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensStateHolder import com.tangem.feature.wallet.presentation.wallet.state.WalletCardState +import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList @@ -15,7 +15,9 @@ import java.util.UUID internal object WalletPreviewData { - val walletCardContent = WalletCardState.Content( + val walletTopBarConfig = WalletStateHolder.TopBarConfig(onScanCardClick = {}, onMoreClick = {}) + + val walletCardContentState = WalletCardState.Content( id = UUID.randomUUID().toString(), title = "Wallet 1", balance = "8923,05 $", @@ -24,7 +26,7 @@ internal object WalletPreviewData { onClick = {}, ) - val walletCardLoading = WalletCardState.Loading( + val walletCardLoadingState = WalletCardState.Loading( id = UUID.randomUUID().toString(), title = "Wallet 1", additionalInfo = "3 cards • Seed enabled", @@ -32,7 +34,7 @@ internal object WalletPreviewData { onClick = {}, ) - val walletCardHiddenContent = WalletCardState.HiddenContent( + val walletCardHiddenContentState = WalletCardState.HiddenContent( id = UUID.randomUUID().toString(), title = "Wallet 1", additionalInfo = "3 cards • Seed enabled", @@ -40,7 +42,7 @@ internal object WalletPreviewData { onClick = {}, ) - val walletCardError = WalletCardState.Error( + val walletCardErrorState = WalletCardState.Error( id = UUID.randomUUID().toString(), title = "Wallet 1", additionalInfo = "3 cards • Seed enabled", @@ -48,15 +50,6 @@ internal object WalletPreviewData { onClick = {}, ) - val walletScreenState = WalletStateHolder( - onBackClick = {}, - headerConfig = WalletStateHolder.HeaderConfig( - wallets = persistentListOf(walletCardContent, walletCardLoading, walletCardHiddenContent, walletCardError), - onScanCardClick = {}, - onMoreClick = {}, - ), - ) - val tokenItemVisibleState = TokenItemState.Content( id = UUID.randomUUID().toString(), tokenIconUrl = null, @@ -109,37 +102,6 @@ internal object WalletPreviewData { val loadingTokenItemState = TokenItemState.Loading(id = UUID.randomUUID().toString()) - val networkGroup = NetworkGroupState.Content( - id = UUID.randomUUID().toString(), - networkName = "Ethereum", - tokens = persistentListOf( - tokenItemVisibleState.copy( - id = "token_1", - name = "Ethereum", - tokenIconResId = R.drawable.img_eth_22, - networkIconResId = null, - amount = "1,89340821 ETH", - ), - tokenItemVisibleState.copy( - id = "token_2", - networkIconResId = R.drawable.img_eth_22, - amount = "733,71097 MATIC", - ), - tokenItemVisibleState.copy( - id = "token_3", - name = "USDT", - tokenIconResId = R.drawable.img_arbitrum_22, - networkIconResId = R.drawable.img_eth_22, - amount = "0,25404523 ARB", - ), - ), - ) - - val draggableNetworkGroup = NetworkGroupState.Draggable( - id = "group_1", - networkName = "Ethereum", - ) - private const val networksSize = 10 private const val tokensSize = 3 val draggableItems = List(networksSize) { it } @@ -147,10 +109,8 @@ internal object WalletPreviewData { val n = index + 1 val group = DraggableItem.GroupHeader( - groupState = NetworkGroupState.Draggable( - id = "group_$n", - networkName = "$n", - ), + id = "group_$n", + networkName = "$n", ) val tokens: MutableList = mutableListOf() @@ -198,4 +158,66 @@ internal object WalletPreviewData { items = draggableTokens, ), ) + + val groupedWalletScreenState = WalletStateHolder( + onBackClick = {}, + topBarConfig = walletTopBarConfig, + selectedWallet = walletCardContentState, + wallets = persistentListOf( + walletCardContentState, + walletCardLoadingState, + walletCardHiddenContentState, + walletCardErrorState, + ), + contentItems = persistentListOf( + WalletContentItemState.NetworkGroupTitle("Bitcoin"), + WalletContentItemState.Token( + tokenItemVisibleState.copy( + id = "token_1", + name = "Ethereum", + tokenIconResId = R.drawable.img_eth_22, + networkIconResId = null, + amount = "1,89340821 ETH", + ), + ), + WalletContentItemState.Token( + tokenItemVisibleState.copy( + id = "token_2", + name = "Ethereum", + tokenIconResId = R.drawable.img_eth_22, + networkIconResId = null, + amount = "1,89340821 ETH", + ), + ), + WalletContentItemState.Token( + tokenItemVisibleState.copy( + id = "token_3", + name = "Ethereum", + tokenIconResId = R.drawable.img_eth_22, + networkIconResId = null, + amount = "1,89340821 ETH", + ), + ), + WalletContentItemState.Token( + tokenItemVisibleState.copy( + id = "token_4", + name = "Ethereum", + tokenIconResId = R.drawable.img_eth_22, + networkIconResId = null, + amount = "1,89340821 ETH", + ), + ), + WalletContentItemState.NetworkGroupTitle("Ethereum"), + WalletContentItemState.Token( + tokenItemVisibleState.copy( + id = "token_5", + name = "Ethereum", + tokenIconResId = R.drawable.img_eth_22, + networkIconResId = null, + amount = "1,89340821 ETH", + ), + ), + ), + onOrganizeTokensClick = {}, + ) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/NetworkGroupItem.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/NetworkGroupItem.kt index 70e1eeb242..82e40737c5 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/NetworkGroupItem.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/NetworkGroupItem.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.* import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.key import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource @@ -15,29 +14,20 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.wallet.impl.R -import com.tangem.feature.wallet.presentation.common.WalletPreviewData -import com.tangem.feature.wallet.presentation.common.state.NetworkGroupState @Composable -internal fun NetworkGroupItem(state: NetworkGroupState.Content, modifier: Modifier = Modifier) { +internal fun NetworkGroupItem(networkName: String, modifier: Modifier = Modifier) { InternalNetworkGroupItem( modifier = modifier, - networkName = state.networkName, - tokens = { - state.tokens.forEach { token -> - key(token.id) { - TokenItem(state = token) - } - } - }, + networkName = networkName, ) } @Composable -internal fun DraggableNetworkGroupItem(state: NetworkGroupState.Draggable, modifier: Modifier = Modifier) { +internal fun DraggableNetworkGroupItem(networkName: String, modifier: Modifier = Modifier) { InternalNetworkGroupItem( modifier = modifier, - networkName = state.networkName, + networkName = networkName, endIcon = { Icon( painter = painterResource(id = R.drawable.ic_group_drop_24), @@ -52,14 +42,13 @@ internal fun DraggableNetworkGroupItem(state: NetworkGroupState.Draggable, modif private fun InternalNetworkGroupItem( networkName: String, modifier: Modifier = Modifier, - tokens: @Composable ColumnScope.() -> Unit = {}, endIcon: @Composable RowScope.() -> Unit = {}, ) { Column(modifier = modifier) { Row( modifier = Modifier .background(TangemTheme.colors.background.primary) - .padding(horizontal = TangemTheme.dimens.spacing12) + .padding(horizontal = TangemTheme.dimens.spacing14) .fillMaxWidth() .heightIn(min = TangemTheme.dimens.size48), verticalAlignment = Alignment.CenterVertically, @@ -72,39 +61,36 @@ private fun InternalNetworkGroupItem( ) endIcon() } - tokens() } } // region Preview @Composable -private fun NetworkGroupItemSample(group: NetworkGroupState) { - when (group) { - is NetworkGroupState.Content -> NetworkGroupItem(group) - is NetworkGroupState.Draggable -> DraggableNetworkGroupItem(group) +private fun NetworkGroupItemSample(isDraggable: Boolean) { + if (isDraggable) { + DraggableNetworkGroupItem(networkName = "Ethereum") + } else { + NetworkGroupItem(networkName = "Ethereum") } } @Preview(showBackground = true, widthDp = 360) @Composable -private fun NetworkGroupItemPreview_Light(@PreviewParameter(NetworkGroupProvider::class) group: NetworkGroupState) { +private fun NetworkGroupItemPreview_Light(@PreviewParameter(NetworkGroupProvider::class) isDraggable: Boolean) { TangemTheme { - NetworkGroupItemSample(group) + NetworkGroupItemSample(isDraggable) } } @Preview(showBackground = true, widthDp = 360) @Composable -private fun NetworkGroupItemPreview_Dark(@PreviewParameter(NetworkGroupProvider::class) group: NetworkGroupState) { +private fun NetworkGroupItemPreview_Dark(@PreviewParameter(NetworkGroupProvider::class) isDraggable: Boolean) { TangemTheme(isDark = true) { - NetworkGroupItemSample(group) + NetworkGroupItemSample(isDraggable) } } -private class NetworkGroupProvider : CollectionPreviewParameterProvider( - collection = listOf( - WalletPreviewData.networkGroup, - WalletPreviewData.draggableNetworkGroup, - ), +private class NetworkGroupProvider : CollectionPreviewParameterProvider( + collection = listOf(true, false), ) // endregion Preview \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/TokenItem.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/TokenItem.kt index b2cb67a6d1..de8daa9cb8 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/TokenItem.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/component/TokenItem.kt @@ -206,7 +206,7 @@ private fun InternalTokenItem( modifier = Modifier .fillMaxWidth() .padding( - horizontal = TangemTheme.dimens.spacing12, + horizontal = TangemTheme.dimens.spacing14, vertical = TangemTheme.dimens.spacing4, ), ) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/state/NetworkGroupState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/state/NetworkGroupState.kt deleted file mode 100644 index 854730e663..0000000000 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/state/NetworkGroupState.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.feature.wallet.presentation.common.state - -import androidx.compose.runtime.Immutable -import kotlinx.collections.immutable.ImmutableList - -@Immutable -internal sealed interface NetworkGroupState { - val id: String - val networkName: String - - data class Draggable( - override val id: String, - override val networkName: String, - ) : NetworkGroupState - - data class Content( - override val id: String, - override val networkName: String, - val tokens: ImmutableList, - ) : NetworkGroupState -} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt index cea7c1211a..ac4d146213 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensScreen.kt @@ -93,7 +93,7 @@ private fun DraggableItem(index: Int, item: DraggableItem, lastItemIndex: Int) { when (item) { is DraggableItem.GroupHeader -> DraggableNetworkGroupItem( modifier = itemModifier, - state = item.groupState, + networkName = item.networkName, ) is DraggableItem.Token -> DraggableTokenItem( modifier = itemModifier, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensStateHolder.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensStateHolder.kt index 9e76b66248..0e0a07d2e6 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensStateHolder.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/OrganizeTokensStateHolder.kt @@ -1,7 +1,6 @@ package com.tangem.feature.wallet.presentation.organizetokens import androidx.compose.runtime.Immutable -import com.tangem.feature.wallet.presentation.common.state.NetworkGroupState import com.tangem.feature.wallet.presentation.common.state.TokenItemState import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList @@ -51,10 +50,9 @@ internal sealed interface DraggableItem { val id: String data class GroupHeader( - val groupState: NetworkGroupState.Draggable, - ) : DraggableItem { - override val id: String = groupState.id - } + override val id: String, + val networkName: String, + ) : DraggableItem data class Token( val tokenItemState: TokenItemState.Draggable, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletCardState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletCardState.kt index 7685a267da..2f000581e2 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletCardState.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletCardState.kt @@ -1,9 +1,12 @@ package com.tangem.feature.wallet.presentation.wallet.state import androidx.annotation.DrawableRes +import androidx.compose.runtime.Immutable /** Wallet card state */ +@Immutable internal sealed interface WalletCardState { + /** Id */ val id: String diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletContentItemState.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletContentItemState.kt new file mode 100644 index 0000000000..66a426f04a --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletContentItemState.kt @@ -0,0 +1,13 @@ +package com.tangem.feature.wallet.presentation.wallet.state + +import com.tangem.feature.wallet.presentation.common.state.TokenItemState + +/** +[REDACTED_AUTHOR] + */ +internal sealed interface WalletContentItemState { + + data class NetworkGroupTitle(val networkName: String) : WalletContentItemState + + data class Token(val tokenItemState: TokenItemState) : WalletContentItemState +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateHolder.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateHolder.kt index 8142667ad3..061647e21b 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateHolder.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletStateHolder.kt @@ -5,26 +5,28 @@ import kotlinx.collections.immutable.ImmutableList /** * Wallet state holder * - * @property onBackClick lambda be invoked when back button is clicked - * @property headerConfig header config + * @property onBackClick lambda be invoked when back button is clicked + * @property topBarConfig top bar config + * @property selectedWallet selected wallet + * @property wallets list of wallets states + * @property contentItems content items * [REDACTED_AUTHOR] */ internal data class WalletStateHolder( val onBackClick: () -> Unit, - val headerConfig: HeaderConfig, + val topBarConfig: TopBarConfig, + val selectedWallet: WalletCardState, + val wallets: ImmutableList, + val contentItems: ImmutableList, + val onOrganizeTokensClick: () -> Unit, ) { /** - * Header config + * Top bar config * - * @property wallets list of wallets states * @property onScanCardClick lambda be invoked when scan card button is clicked * @property onMoreClick lambda be invoked when more button is clicked */ - data class HeaderConfig( - val wallets: ImmutableList, - val onScanCardClick: () -> Unit, - val onMoreClick: () -> Unit, - ) + data class TopBarConfig(val onScanCardClick: () -> Unit, val onMoreClick: () -> Unit) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt index ba17e6e692..701f730a14 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/WalletScreen.kt @@ -1,10 +1,32 @@ package com.tangem.feature.wallet.presentation.wallet.ui import androidx.activity.compose.BackHandler -import androidx.compose.material.Scaffold +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.draw.clip +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.datasource.CollectionPreviewParameterProvider +import com.tangem.core.ui.components.RoundedActionButton +import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.wallet.impl.R +import com.tangem.feature.wallet.presentation.common.WalletPreviewData +import com.tangem.feature.wallet.presentation.common.component.NetworkGroupItem +import com.tangem.feature.wallet.presentation.common.component.TokenItem +import com.tangem.feature.wallet.presentation.wallet.state.WalletContentItemState import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder -import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletHeader +import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletCardsList +import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletTopBar /** * Wallet screen @@ -18,8 +40,109 @@ internal fun WalletScreen(state: WalletStateHolder) { BackHandler(onBack = state.onBackClick) Scaffold( - topBar = { WalletHeader(config = state.headerConfig) }, - ) { - // TODO: [REDACTED_TASK_KEY] Design a body with tokens and transactions + topBar = { WalletTopBar(config = state.topBarConfig) }, + containerColor = TangemTheme.colors.background.secondary, + ) { scaffoldPaddings -> + val lastContentItemIndex = remember(state.contentItems) { + state.contentItems.lastIndex + } + + LazyColumn( + modifier = Modifier + .padding(scaffoldPaddings) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + item { WalletCardsList(wallets = state.wallets) } + + itemsIndexed( + items = state.contentItems, + key = { _, item -> + when (item) { + is WalletContentItemState.NetworkGroupTitle -> item.networkName + is WalletContentItemState.Token -> item.tokenItemState.id + } + }, + ) { index, item -> + val itemModifier = Modifier + .padding(horizontal = TangemTheme.dimens.spacing16) + .clipFirstAndLastItems(index, lastContentItemIndex) + + when (item) { + is WalletContentItemState.NetworkGroupTitle -> { + NetworkGroupItem( + networkName = item.networkName, + modifier = itemModifier, + ) + } + is WalletContentItemState.Token -> { + TokenItem( + state = item.tokenItemState, + modifier = itemModifier, + ) + } + } + } + + item { + RoundedActionButton( + text = stringResource(id = R.string.organize_tokens_title), + iconResId = R.drawable.ic_filter_24, + onClick = state.onOrganizeTokensClick, + modifier = Modifier.padding(top = TangemTheme.dimens.spacing14), + ) + } + } } -} \ No newline at end of file +} + +private fun Modifier.clipFirstAndLastItems(index: Int, lastItemIndex: Int): Modifier = composed { + when (index) { + 0 -> { + this + .padding(top = TangemTheme.dimens.spacing14) + .clip( + RoundedCornerShape( + topStart = TangemTheme.dimens.radius16, + topEnd = TangemTheme.dimens.radius16, + ), + ) + } + lastItemIndex -> { + this + .clip( + RoundedCornerShape( + bottomStart = TangemTheme.dimens.radius16, + bottomEnd = TangemTheme.dimens.radius16, + ), + ) + } + else -> this + } +} + +// region Preview +@Preview(showBackground = true, widthDp = 360) +@Composable +private fun WalletScreenPreview_Light( + @PreviewParameter(WalletScreenParameterProvider::class) state: WalletStateHolder, +) { + TangemTheme { + WalletScreen(state) + } +} + +@Preview(showBackground = true, widthDp = 360) +@Composable +private fun WalletScreenPreview_Dark( + @PreviewParameter(WalletScreenParameterProvider::class) state: WalletStateHolder, +) { + TangemTheme(isDark = true) { + WalletScreen(state) + } +} + +private class WalletScreenParameterProvider : CollectionPreviewParameterProvider( + collection = listOf(WalletPreviewData.groupedWalletScreenState), +) +// endregion Preview \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCard.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCard.kt index 562c954023..d92651ac6f 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCard.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCard.kt @@ -44,7 +44,7 @@ internal fun WalletCard(state: WalletCardState, modifier: Modifier = Modifier) { ConstraintLayout( modifier = Modifier .fillMaxWidth() - .padding(horizontal = TangemTheme.dimens.spacing12), + .padding(horizontal = TangemTheme.dimens.spacing14), ) { val (balanceBlock, imageItem) = createRefs() Column( @@ -182,10 +182,10 @@ private fun Preview_WalletCard_DarkTheme(@PreviewParameter(WalletCardStateProvid private class WalletCardStateProvider : CollectionPreviewParameterProvider( collection = listOf( - WalletPreviewData.walletCardContent, - WalletPreviewData.walletCardLoading, - WalletPreviewData.walletCardHiddenContent, - WalletPreviewData.walletCardError, + WalletPreviewData.walletCardContentState, + WalletPreviewData.walletCardLoadingState, + WalletPreviewData.walletCardHiddenContentState, + WalletPreviewData.walletCardErrorState, ), ) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCardsList.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCardsList.kt new file mode 100644 index 0000000000..d37d359252 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCardsList.kt @@ -0,0 +1,78 @@ +package com.tangem.feature.wallet.presentation.wallet.ui.components + +import androidx.compose.animation.core.* +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.wallet.presentation.common.WalletPreviewData +import com.tangem.feature.wallet.presentation.wallet.state.WalletCardState +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +/** + * Wallets list + * + * @param wallets list of wallet state + * +[REDACTED_AUTHOR] + */ +@OptIn(ExperimentalFoundationApi::class) +@Composable +internal fun WalletCardsList(wallets: ImmutableList) { + val horizontalCardPadding = TangemTheme.dimens.spacing16 + val itemWidth = LocalConfiguration.current.screenWidthDp.dp - horizontalCardPadding * 2 + + val lazyListState = rememberLazyListState() + LazyRow( + modifier = Modifier.background(color = TangemTheme.colors.background.secondary), + state = lazyListState, + contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16), + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), + flingBehavior = rememberSnapFlingBehavior(lazyListState = lazyListState), + ) { + items(items = wallets, key = WalletCardState::id) { state -> + WalletCard(state = state, modifier = Modifier.width(itemWidth)) + } + } +} + +@Preview +@Composable +private fun Preview_WalletHeader_LightTheme() { + TangemTheme(isDark = false) { + WalletCardsList( + wallets = persistentListOf( + WalletPreviewData.walletCardContentState, + WalletPreviewData.walletCardLoadingState, + WalletPreviewData.walletCardHiddenContentState, + WalletPreviewData.walletCardErrorState, + ), + ) + } +} + +@Preview +@Composable +private fun Preview_WalletHeader_DarkTheme() { + TangemTheme(isDark = true) { + WalletCardsList( + wallets = persistentListOf( + WalletPreviewData.walletCardContentState, + WalletPreviewData.walletCardLoadingState, + WalletPreviewData.walletCardHiddenContentState, + WalletPreviewData.walletCardErrorState, + ), + ) + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletHeader.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletHeader.kt deleted file mode 100644 index cb01b48377..0000000000 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletHeader.kt +++ /dev/null @@ -1,123 +0,0 @@ -package com.tangem.feature.wallet.presentation.wallet.ui.components - -import androidx.compose.animation.core.* -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.LocalOverscrollConfiguration -import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material3.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalConfiguration -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 androidx.compose.ui.unit.dp -import com.tangem.core.ui.res.TangemTheme -import com.tangem.feature.wallet.impl.R -import com.tangem.feature.wallet.presentation.common.WalletPreviewData -import com.tangem.feature.wallet.presentation.wallet.state.WalletCardState -import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder -import kotlinx.collections.immutable.persistentListOf - -/** - * Wallet screen header - * - * @param config config - * -[REDACTED_AUTHOR] - */ -@OptIn(ExperimentalFoundationApi::class) -@Composable -internal fun WalletHeader(config: WalletStateHolder.HeaderConfig) { - Column( - modifier = Modifier - .background(color = TangemTheme.colors.background.secondary) - .padding(bottom = TangemTheme.dimens.spacing14), - ) { - TopBar(onScanCardClick = config.onScanCardClick, onMoreClick = config.onMoreClick) - - CompositionLocalProvider(LocalOverscrollConfiguration provides null) { - val lazyListState = rememberLazyListState() - LazyRow( - state = lazyListState, - contentPadding = PaddingValues(horizontal = TangemTheme.dimens.spacing16), - horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), - flingBehavior = rememberSnapFlingBehavior(lazyListState = lazyListState), - ) { - items(items = config.wallets, key = WalletCardState::id) { state -> - WalletCard( - state = state, - modifier = Modifier.width( - LocalConfiguration.current.screenWidthDp.dp - TangemTheme.dimens.size32, - ), - ) - } - } - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun TopBar(onScanCardClick: () -> Unit, onMoreClick: () -> Unit) { - TopAppBar( - title = { - Icon(painter = painterResource(id = R.drawable.img_tangem_logo_90_24), contentDescription = null) - }, - actions = { - IconButton(onClick = onScanCardClick) { - Icon(painter = painterResource(id = R.drawable.ic_tap_card_24), contentDescription = "Scan card") - } - IconButton(onClick = onMoreClick) { - Icon(painter = painterResource(id = R.drawable.ic_more_vertical_24), contentDescription = "More") - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = TangemTheme.colors.background.secondary, - titleContentColor = TangemTheme.colors.icon.primary1, - actionIconContentColor = TangemTheme.colors.icon.primary1, - ), - ) -} - -@Preview -@Composable -private fun Preview_WalletHeader_LightTheme( - @PreviewParameter(WalletHeaderProvider::class) state: WalletStateHolder.HeaderConfig, -) { - TangemTheme(isDark = false) { - WalletHeader(state) - } -} - -@Preview -@Composable -private fun Preview_WalletHeader_DarkTheme( - @PreviewParameter(WalletHeaderProvider::class) state: WalletStateHolder.HeaderConfig, -) { - TangemTheme(isDark = true) { - WalletHeader(state) - } -} - -private class WalletHeaderProvider : CollectionPreviewParameterProvider( - collection = listOf( - WalletStateHolder.HeaderConfig( - wallets = persistentListOf( - WalletPreviewData.walletCardContent, - WalletPreviewData.walletCardLoading, - WalletPreviewData.walletCardHiddenContent, - WalletPreviewData.walletCardError, - ), - onScanCardClick = {}, - onMoreClick = {}, - ), - ), -) \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletTopBar.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletTopBar.kt new file mode 100644 index 0000000000..29b91f97bd --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletTopBar.kt @@ -0,0 +1,55 @@ +package com.tangem.feature.wallet.presentation.wallet.ui.components + +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.wallet.impl.R +import com.tangem.feature.wallet.presentation.common.WalletPreviewData +import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder + +/** + * Wallet screen top bar + * + * @param config top bar config + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun WalletTopBar(config: WalletStateHolder.TopBarConfig) { + TopAppBar( + title = { + Icon(painter = painterResource(id = R.drawable.img_tangem_logo_90_24), contentDescription = null) + }, + actions = { + IconButton(onClick = config.onScanCardClick) { + Icon(painter = painterResource(id = R.drawable.ic_tap_card_24), contentDescription = "Scan card") + } + IconButton(onClick = config.onMoreClick) { + Icon(painter = painterResource(id = R.drawable.ic_more_vertical_24), contentDescription = "More") + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = TangemTheme.colors.background.secondary, + titleContentColor = TangemTheme.colors.icon.primary1, + actionIconContentColor = TangemTheme.colors.icon.primary1, + ), + scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), + ) +} + +@Preview +@Composable +private fun Preview_WalletTopBar_LightTheme() { + TangemTheme(isDark = false) { + WalletTopBar(config = WalletPreviewData.walletTopBarConfig) + } +} + +@Preview +@Composable +private fun Preview_WalletTopBar_DarkTheme() { + TangemTheme(isDark = true) { + WalletTopBar(config = WalletPreviewData.walletTopBarConfig) + } +} \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index a565bb8c91..9cb70bd530 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -27,9 +27,9 @@ internal class WalletViewModel @Inject constructor() : ViewModel() { private set // TODO: [REDACTED_TASK_KEY] Use production data instead of WalletPreviewData - private fun getInitialState(): WalletStateHolder = WalletPreviewData.walletScreenState.copy( + private fun getInitialState(): WalletStateHolder = WalletPreviewData.groupedWalletScreenState.copy( onBackClick = { router.popBackStack() }, - headerConfig = WalletPreviewData.walletScreenState.headerConfig.copy( + topBarConfig = WalletPreviewData.groupedWalletScreenState.topBarConfig.copy( onScanCardClick = { router.openOrganizeTokensScreen() }, ), )