Updated on 2026-08-14
This commit is contained in:
parent
aa19739725
commit
6c396362e4
12 changed files with 284 additions and 69 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.feature.wallet.presentation.common
|
||||
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.transactions.TransactionState
|
||||
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
|
||||
|
|
@ -9,13 +10,14 @@ import com.tangem.feature.wallet.presentation.organizetokens.OrganizeTokensState
|
|||
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 com.tangem.feature.wallet.presentation.wallet.state.WalletTopBarConfig
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import java.util.UUID
|
||||
|
||||
internal object WalletPreviewData {
|
||||
|
||||
val walletTopBarConfig = WalletStateHolder.TopBarConfig(onScanCardClick = {}, onMoreClick = {})
|
||||
val walletTopBarConfig = WalletTopBarConfig(onScanCardClick = {}, onMoreClick = {})
|
||||
|
||||
val walletCardContentState = WalletCardState.Content(
|
||||
id = UUID.randomUUID().toString(),
|
||||
|
|
@ -159,7 +161,7 @@ internal object WalletPreviewData {
|
|||
),
|
||||
)
|
||||
|
||||
val groupedWalletScreenState = WalletStateHolder(
|
||||
val multicurrencyWalletScreenState = WalletStateHolder.MultiCurrencyContent(
|
||||
onBackClick = {},
|
||||
topBarConfig = walletTopBarConfig,
|
||||
selectedWallet = walletCardContentState,
|
||||
|
|
@ -170,8 +172,8 @@ internal object WalletPreviewData {
|
|||
walletCardErrorState,
|
||||
),
|
||||
contentItems = persistentListOf(
|
||||
WalletContentItemState.NetworkGroupTitle("Bitcoin"),
|
||||
WalletContentItemState.Token(
|
||||
WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle("Bitcoin"),
|
||||
WalletContentItemState.MultiCurrencyItem.Token(
|
||||
tokenItemVisibleState.copy(
|
||||
id = "token_1",
|
||||
name = "Ethereum",
|
||||
|
|
@ -180,7 +182,7 @@ internal object WalletPreviewData {
|
|||
amount = "1,89340821 ETH",
|
||||
),
|
||||
),
|
||||
WalletContentItemState.Token(
|
||||
WalletContentItemState.MultiCurrencyItem.Token(
|
||||
tokenItemVisibleState.copy(
|
||||
id = "token_2",
|
||||
name = "Ethereum",
|
||||
|
|
@ -189,7 +191,7 @@ internal object WalletPreviewData {
|
|||
amount = "1,89340821 ETH",
|
||||
),
|
||||
),
|
||||
WalletContentItemState.Token(
|
||||
WalletContentItemState.MultiCurrencyItem.Token(
|
||||
tokenItemVisibleState.copy(
|
||||
id = "token_3",
|
||||
name = "Ethereum",
|
||||
|
|
@ -198,7 +200,7 @@ internal object WalletPreviewData {
|
|||
amount = "1,89340821 ETH",
|
||||
),
|
||||
),
|
||||
WalletContentItemState.Token(
|
||||
WalletContentItemState.MultiCurrencyItem.Token(
|
||||
tokenItemVisibleState.copy(
|
||||
id = "token_4",
|
||||
name = "Ethereum",
|
||||
|
|
@ -207,8 +209,8 @@ internal object WalletPreviewData {
|
|||
amount = "1,89340821 ETH",
|
||||
),
|
||||
),
|
||||
WalletContentItemState.NetworkGroupTitle("Ethereum"),
|
||||
WalletContentItemState.Token(
|
||||
WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle("Ethereum"),
|
||||
WalletContentItemState.MultiCurrencyItem.Token(
|
||||
tokenItemVisibleState.copy(
|
||||
id = "token_5",
|
||||
name = "Ethereum",
|
||||
|
|
@ -220,4 +222,35 @@ internal object WalletPreviewData {
|
|||
),
|
||||
onOrganizeTokensClick = {},
|
||||
)
|
||||
|
||||
val singleWalletScreenState = WalletStateHolder.SingleCurrencyContent(
|
||||
onBackClick = {},
|
||||
topBarConfig = walletTopBarConfig,
|
||||
selectedWallet = walletCardContentState,
|
||||
wallets = persistentListOf(
|
||||
walletCardContentState,
|
||||
walletCardLoadingState,
|
||||
walletCardHiddenContentState,
|
||||
walletCardErrorState,
|
||||
),
|
||||
contentItems = persistentListOf(
|
||||
WalletContentItemState.SingleCurrencyItem.Title(onExploreClick = {}),
|
||||
WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle("Today"),
|
||||
WalletContentItemState.SingleCurrencyItem.Transaction(
|
||||
TransactionState.Sending(
|
||||
address = "33BddS...ga2B",
|
||||
amount = "-0.500913 BTC",
|
||||
timestamp = "8:41",
|
||||
),
|
||||
),
|
||||
WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle("Yesterday"),
|
||||
WalletContentItemState.SingleCurrencyItem.Transaction(
|
||||
TransactionState.Sending(
|
||||
address = "33BddS...ga2B",
|
||||
amount = "-0.500913 BTC",
|
||||
timestamp = "8:41",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,13 +1,55 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import com.tangem.core.ui.components.transactions.TransactionState
|
||||
import com.tangem.feature.wallet.presentation.common.state.TokenItemState
|
||||
|
||||
/**
|
||||
* Wallet screen content item state
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal sealed interface WalletContentItemState {
|
||||
|
||||
data class NetworkGroupTitle(val networkName: String) : WalletContentItemState
|
||||
/** Multi currency wallet content state */
|
||||
sealed interface MultiCurrencyItem : WalletContentItemState {
|
||||
|
||||
data class Token(val tokenItemState: TokenItemState) : WalletContentItemState
|
||||
/**
|
||||
* Network group title item
|
||||
*
|
||||
* @property networkName network name
|
||||
*/
|
||||
data class NetworkGroupTitle(val networkName: String) : MultiCurrencyItem
|
||||
|
||||
/**
|
||||
* Token item
|
||||
*
|
||||
* @property state token item state
|
||||
*/
|
||||
data class Token(val state: TokenItemState) : MultiCurrencyItem
|
||||
}
|
||||
|
||||
/** Single currency wallet content state */
|
||||
sealed interface SingleCurrencyItem : WalletContentItemState {
|
||||
|
||||
/**
|
||||
* Title item
|
||||
*
|
||||
* @property onExploreClick lambda be invoke when explore button was clicked
|
||||
*/
|
||||
data class Title(val onExploreClick: () -> Unit) : SingleCurrencyItem
|
||||
|
||||
/**
|
||||
* Transaction group title item
|
||||
*
|
||||
* @property title title
|
||||
*/
|
||||
data class TransactionGroupTitle(val title: String) : SingleCurrencyItem
|
||||
|
||||
/**
|
||||
* Transaction item
|
||||
*
|
||||
* @property state transaction state
|
||||
*/
|
||||
data class Transaction(val state: TransactionState) : SingleCurrencyItem
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.state
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
/**
|
||||
* Wallet state holder
|
||||
* Wallet screen state holder
|
||||
*
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
* @property topBarConfig top bar config
|
||||
|
|
@ -13,20 +13,46 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal data class WalletStateHolder(
|
||||
val onBackClick: () -> Unit,
|
||||
val topBarConfig: TopBarConfig,
|
||||
val selectedWallet: WalletCardState,
|
||||
val wallets: ImmutableList<WalletCardState>,
|
||||
val contentItems: ImmutableList<WalletContentItemState>,
|
||||
val onOrganizeTokensClick: () -> Unit,
|
||||
internal sealed class WalletStateHolder(
|
||||
open val onBackClick: () -> Unit,
|
||||
open val topBarConfig: WalletTopBarConfig,
|
||||
open val selectedWallet: WalletCardState,
|
||||
open val wallets: ImmutableList<WalletCardState>,
|
||||
open val contentItems: ImmutableList<WalletContentItemState>,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Top bar config
|
||||
* Multi currency wallet content state
|
||||
*
|
||||
* @property onScanCardClick lambda be invoked when scan card button is clicked
|
||||
* @property onMoreClick lambda be invoked when more button is clicked
|
||||
* @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
|
||||
*/
|
||||
data class TopBarConfig(val onScanCardClick: () -> Unit, val onMoreClick: () -> Unit)
|
||||
data class MultiCurrencyContent(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val selectedWallet: WalletCardState,
|
||||
override val wallets: ImmutableList<WalletCardState>,
|
||||
override val contentItems: ImmutableList<WalletContentItemState.MultiCurrencyItem>,
|
||||
val onOrganizeTokensClick: () -> Unit,
|
||||
) : WalletStateHolder(onBackClick, topBarConfig, selectedWallet, wallets, contentItems)
|
||||
|
||||
/**
|
||||
* Single currency wallet content state
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
data class SingleCurrencyContent(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val selectedWallet: WalletCardState,
|
||||
override val wallets: ImmutableList<WalletCardState>,
|
||||
override val contentItems: ImmutableList<WalletContentItemState.SingleCurrencyItem>,
|
||||
) : WalletStateHolder(onBackClick, topBarConfig, selectedWallet, wallets, contentItems)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
/**
|
||||
* Wallet screen top bar config
|
||||
*
|
||||
* @property onScanCardClick lambda be invoked when scan card button is clicked
|
||||
* @property onMoreClick lambda be invoked when more button is clicked
|
||||
*/
|
||||
data class WalletTopBarConfig(val onScanCardClick: () -> Unit, val onMoreClick: () -> Unit)
|
||||
|
|
@ -1,23 +1,29 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.RoundedActionButton
|
||||
import com.tangem.core.ui.components.transactions.Transaction
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
|
|
@ -43,9 +49,7 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie
|
|||
topBar = { WalletTopBar(config = state.topBarConfig) },
|
||||
containerColor = TangemTheme.colors.background.secondary,
|
||||
) { scaffoldPaddings ->
|
||||
val lastContentItemIndex = remember(state.contentItems) {
|
||||
state.contentItems.lastIndex
|
||||
}
|
||||
val lastContentItemIndex = remember(state.contentItems) { state.contentItems.lastIndex }
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
|
|
@ -57,10 +61,13 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie
|
|||
|
||||
itemsIndexed(
|
||||
items = state.contentItems,
|
||||
key = { _, item ->
|
||||
key = { index, item ->
|
||||
when (item) {
|
||||
is WalletContentItemState.NetworkGroupTitle -> item.networkName
|
||||
is WalletContentItemState.Token -> item.tokenItemState.id
|
||||
is WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle -> item.networkName
|
||||
is WalletContentItemState.MultiCurrencyItem.Token -> item.state.id
|
||||
is WalletContentItemState.SingleCurrencyItem.Title -> index
|
||||
is WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle -> item.title
|
||||
is WalletContentItemState.SingleCurrencyItem.Transaction -> index
|
||||
}
|
||||
},
|
||||
) { index, item ->
|
||||
|
|
@ -69,33 +76,96 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie
|
|||
.clipFirstAndLastItems(index, lastContentItemIndex)
|
||||
|
||||
when (item) {
|
||||
is WalletContentItemState.NetworkGroupTitle -> {
|
||||
NetworkGroupItem(
|
||||
networkName = item.networkName,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
is WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle -> {
|
||||
NetworkGroupItem(networkName = item.networkName, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.Token -> {
|
||||
TokenItem(
|
||||
state = item.tokenItemState,
|
||||
modifier = itemModifier,
|
||||
)
|
||||
is WalletContentItemState.MultiCurrencyItem.Token -> {
|
||||
TokenItem(state = item.state, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.Title -> {
|
||||
SingleCurrencyTitle(config = item, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle -> {
|
||||
TransactionGroupTitle(config = item, modifier = itemModifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.Transaction -> {
|
||||
Transaction(state = item.state, 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),
|
||||
)
|
||||
if (state is WalletStateHolder.MultiCurrencyContent) {
|
||||
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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SingleCurrencyTitle(
|
||||
config: WalletContentItemState.SingleCurrencyItem.Title,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.fillMaxWidth()
|
||||
.padding(top = TangemTheme.dimens.spacing12)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.common_transactions),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.clickable(onClick = config.onExploreClick),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing4),
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_compass_24),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(size = TangemTheme.dimens.size18),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = R.string.common_explorer),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TransactionGroupTitle(
|
||||
config: WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Text(
|
||||
text = config.title,
|
||||
modifier = modifier
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = TangemTheme.dimens.spacing16,
|
||||
vertical = TangemTheme.dimens.spacing14,
|
||||
),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
textAlign = TextAlign.Start,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
|
||||
private fun Modifier.clipFirstAndLastItems(index: Int, lastItemIndex: Int): Modifier = composed {
|
||||
when (index) {
|
||||
0 -> {
|
||||
|
|
@ -143,6 +213,9 @@ private fun WalletScreenPreview_Dark(
|
|||
}
|
||||
|
||||
private class WalletScreenParameterProvider : CollectionPreviewParameterProvider<WalletStateHolder>(
|
||||
collection = listOf(WalletPreviewData.groupedWalletScreenState),
|
||||
collection = listOf(
|
||||
WalletPreviewData.multicurrencyWalletScreenState,
|
||||
WalletPreviewData.singleWalletScreenState,
|
||||
),
|
||||
)
|
||||
// endregion Preview
|
||||
|
|
@ -7,7 +7,7 @@ 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
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletTopBarConfig
|
||||
|
||||
/**
|
||||
* Wallet screen top bar
|
||||
|
|
@ -16,7 +16,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
|
|||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
internal fun WalletTopBar(config: WalletStateHolder.TopBarConfig) {
|
||||
internal fun WalletTopBar(config: WalletTopBarConfig) {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Icon(painter = painterResource(id = R.drawable.img_tangem_logo_90_24), contentDescription = null)
|
||||
|
|
|
|||
|
|
@ -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.groupedWalletScreenState.copy(
|
||||
private fun getInitialState(): WalletStateHolder = WalletPreviewData.multicurrencyWalletScreenState.copy(
|
||||
onBackClick = { router.popBackStack() },
|
||||
topBarConfig = WalletPreviewData.groupedWalletScreenState.topBarConfig.copy(
|
||||
topBarConfig = WalletPreviewData.multicurrencyWalletScreenState.topBarConfig.copy(
|
||||
onScanCardClick = { router.openOrganizeTokensScreen() },
|
||||
),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue