Updated on 2026-08-14
This commit is contained in:
parent
6c40b47578
commit
06342d8509
15 changed files with 324 additions and 197 deletions
|
|
@ -12,7 +12,7 @@ import androidx.annotation.DrawableRes
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class ActionConfig(
|
||||
data class ActionButtonConfig(
|
||||
val text: String,
|
||||
@DrawableRes val iconResId: Int,
|
||||
val onClick: () -> Unit,
|
||||
|
|
@ -1,96 +1,150 @@
|
|||
package com.tangem.core.ui.components.buttons.actions
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
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.buttons.common.TangemButton
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
|
||||
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
|
||||
import com.tangem.core.ui.components.SpacerW8
|
||||
import com.tangem.core.ui.components.buttons.common.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=290-305&t=3z98eFnTeyIx5TH5-4)
|
||||
* Rounded action button
|
||||
*
|
||||
* @param config component config
|
||||
* @param modifier modifier
|
||||
* @param color background color
|
||||
*
|
||||
* @see <a href = "https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=290-306&mode=design&t=
|
||||
* cSLQtIbR2J1h5M9U-4">Show in Figma</a>
|
||||
*/
|
||||
@Composable
|
||||
fun RoundedActionButton(config: ActionConfig, modifier: Modifier = Modifier) {
|
||||
TangemButton(
|
||||
fun RoundedActionButton(
|
||||
config: ActionButtonConfig,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = TangemTheme.colors.button.secondary,
|
||||
) {
|
||||
Button(
|
||||
config = config,
|
||||
shape = RoundedCornerShape(size = TangemTheme.dimens.radius24),
|
||||
modifier = modifier,
|
||||
text = config.text,
|
||||
icon = TangemButtonIconPosition.Start(config.iconResId),
|
||||
onClick = config.onClick,
|
||||
enabled = config.enabled,
|
||||
showProgress = false,
|
||||
colors = TangemButtonsDefaults.secondaryButtonColors,
|
||||
size = TangemButtonSize.RoundedAction,
|
||||
color = color,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=1208-1395&t=3z98eFnTeyIx5TH5-4)
|
||||
* Action button
|
||||
*
|
||||
* @param config component config
|
||||
* @param modifier modifier
|
||||
* @param color background color
|
||||
*
|
||||
* @see <a href = "https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=290-306&mode=design&t=
|
||||
* cSLQtIbR2J1h5M9U-4">Show in Figma</a>
|
||||
*/
|
||||
@Composable
|
||||
fun ActionButton(config: ActionConfig, modifier: Modifier = Modifier) {
|
||||
TangemButton(
|
||||
fun ActionButton(
|
||||
config: ActionButtonConfig,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = TangemTheme.colors.button.secondary,
|
||||
) {
|
||||
Button(
|
||||
config = config,
|
||||
shape = RoundedCornerShape(size = TangemTheme.dimens.radius12),
|
||||
modifier = modifier,
|
||||
text = config.text,
|
||||
icon = TangemButtonIconPosition.Start(config.iconResId),
|
||||
onClick = config.onClick,
|
||||
enabled = config.enabled,
|
||||
showProgress = false,
|
||||
colors = TangemButtonsDefaults.secondaryButtonColors,
|
||||
size = TangemButtonSize.Action,
|
||||
color = color,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as [RoundedActionButton] but colored in primary background color
|
||||
*/
|
||||
@Composable
|
||||
fun BackgroundActionButton(config: ActionConfig, modifier: Modifier = Modifier) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
text = config.text,
|
||||
icon = TangemButtonIconPosition.Start(config.iconResId),
|
||||
onClick = config.onClick,
|
||||
enabled = config.enabled,
|
||||
showProgress = false,
|
||||
colors = TangemButtonsDefaults.backgroundButtonColors,
|
||||
size = TangemButtonSize.RoundedAction,
|
||||
)
|
||||
private fun Button(
|
||||
config: ActionButtonConfig,
|
||||
shape: RoundedCornerShape,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = TangemTheme.colors.button.secondary,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.clickable(enabled = config.enabled, onClick = config.onClick)
|
||||
.heightIn(min = TangemTheme.dimens.size36)
|
||||
.background(
|
||||
color = if (config.enabled) color else TangemTheme.colors.button.disabled,
|
||||
shape = shape,
|
||||
)
|
||||
.padding(
|
||||
start = TangemTheme.dimens.spacing16,
|
||||
end = TangemTheme.dimens.spacing24,
|
||||
)
|
||||
.padding(vertical = TangemTheme.dimens.spacing8),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = config.iconResId),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(size = TangemTheme.dimens.size20),
|
||||
tint = if (config.enabled) TangemTheme.colors.icon.primary1 else TangemTheme.colors.icon.informative,
|
||||
)
|
||||
|
||||
SpacerW8()
|
||||
|
||||
Text(
|
||||
text = config.text,
|
||||
color = if (config.enabled) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.disabled,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = TangemTheme.typography.button,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(group = "RoundedActionButton", showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_ActionButton_Light(@PreviewParameter(ActionStateProvider::class) state: ActionConfig) {
|
||||
private fun Preview_RoundedActionButton_Light(@PreviewParameter(ActionStateProvider::class) state: ActionButtonConfig) {
|
||||
TangemTheme(isDark = false) {
|
||||
Column {
|
||||
RoundedActionButton(state)
|
||||
ActionButton(state)
|
||||
BackgroundActionButton(state)
|
||||
}
|
||||
RoundedActionButton(state)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Preview(group = "RoundedActionButton", showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_ActionButton_Dark(@PreviewParameter(ActionStateProvider::class) state: ActionConfig) {
|
||||
TangemTheme {
|
||||
Column {
|
||||
RoundedActionButton(state)
|
||||
ActionButton(state)
|
||||
BackgroundActionButton(state)
|
||||
}
|
||||
private fun Preview_RoundedActionButton_Dark(@PreviewParameter(ActionStateProvider::class) state: ActionButtonConfig) {
|
||||
TangemTheme(isDark = true) {
|
||||
RoundedActionButton(state)
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionStateProvider : CollectionPreviewParameterProvider<ActionConfig>(
|
||||
@Preview(group = "ActionButton", showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_ActionButton_Light(@PreviewParameter(ActionStateProvider::class) state: ActionButtonConfig) {
|
||||
TangemTheme(isDark = false) {
|
||||
ActionButton(state)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(group = "ActionButton", showBackground = true)
|
||||
@Composable
|
||||
private fun Preview_ActionButton_Dark(@PreviewParameter(ActionStateProvider::class) state: ActionButtonConfig) {
|
||||
TangemTheme(isDark = true) {
|
||||
ActionButton(state)
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionStateProvider : CollectionPreviewParameterProvider<ActionButtonConfig>(
|
||||
collection = listOf(
|
||||
ActionConfig(text = "Send", iconResId = R.drawable.ic_arrow_up_24, onClick = {}),
|
||||
ActionConfig(text = "Receive", iconResId = R.drawable.ic_arrow_down_24, enabled = false, onClick = {}),
|
||||
ActionButtonConfig(text = "Enabled", iconResId = R.drawable.ic_arrow_up_24, enabled = true, onClick = {}),
|
||||
ActionButtonConfig(text = "Disabled", iconResId = R.drawable.ic_arrow_down_24, enabled = false, onClick = {}),
|
||||
),
|
||||
)
|
||||
|
|
@ -2,10 +2,11 @@ package com.tangem.core.ui.components.notifications
|
|||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -32,19 +33,23 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
*/
|
||||
@Composable
|
||||
fun Notification(state: NotificationState, modifier: Modifier = Modifier) {
|
||||
Surface(
|
||||
onClick = if (state is NotificationState.Action) {
|
||||
state.onClick
|
||||
} else {
|
||||
{}
|
||||
},
|
||||
modifier = modifier,
|
||||
enabled = when (state) {
|
||||
is NotificationState.Simple -> false
|
||||
is NotificationState.Action -> true
|
||||
},
|
||||
shape = RoundedCornerShape(TangemTheme.dimens.radius18),
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
Box(
|
||||
modifier = modifier
|
||||
.clickable(
|
||||
enabled = when (state) {
|
||||
is NotificationState.Simple -> false
|
||||
is NotificationState.Action -> true
|
||||
},
|
||||
onClick = if (state is NotificationState.Action) {
|
||||
state.onClick
|
||||
} else {
|
||||
{}
|
||||
},
|
||||
)
|
||||
.background(
|
||||
color = TangemTheme.colors.button.secondary,
|
||||
RoundedCornerShape(size = TangemTheme.dimens.radius18),
|
||||
),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ data class TangemDimens internal constructor(
|
|||
val radius12: Dp = 12.dp,
|
||||
val radius16: Dp = 16.dp,
|
||||
val radius18: Dp = 18.dp,
|
||||
val radius24: Dp = 24.dp,
|
||||
val radius28: Dp = 28.dp,
|
||||
// endregion Radius
|
||||
// region Size
|
||||
|
|
|
|||
|
|
@ -49,6 +49,17 @@ internal object WalletPreviewData {
|
|||
onClick = {},
|
||||
)
|
||||
|
||||
val walletListConfig = WalletsListConfig(
|
||||
selectedWalletIndex = 0,
|
||||
wallets = persistentListOf(
|
||||
walletCardContentState,
|
||||
walletCardLoadingState,
|
||||
walletCardHiddenContentState,
|
||||
walletCardErrorState,
|
||||
),
|
||||
onWalletChange = {},
|
||||
)
|
||||
|
||||
val tokenItemVisibleState = TokenItemState.Content(
|
||||
id = UUID.randomUUID().toString(),
|
||||
tokenIconUrl = null,
|
||||
|
|
@ -195,13 +206,7 @@ internal object WalletPreviewData {
|
|||
val multicurrencyWalletScreenState = WalletStateHolder.MultiCurrencyContent(
|
||||
onBackClick = {},
|
||||
topBarConfig = walletTopBarConfig,
|
||||
selectedWallet = walletCardContentState,
|
||||
wallets = persistentListOf(
|
||||
walletCardContentState,
|
||||
walletCardLoadingState,
|
||||
walletCardHiddenContentState,
|
||||
walletCardErrorState,
|
||||
),
|
||||
walletsListConfig = walletListConfig,
|
||||
contentItems = persistentListOf(
|
||||
WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle("Bitcoin"),
|
||||
WalletContentItemState.MultiCurrencyItem.Token(
|
||||
|
|
@ -263,13 +268,7 @@ internal object WalletPreviewData {
|
|||
val singleWalletScreenState = WalletStateHolder.SingleCurrencyContent(
|
||||
onBackClick = {},
|
||||
topBarConfig = walletTopBarConfig,
|
||||
selectedWallet = walletCardContentState,
|
||||
wallets = persistentListOf(
|
||||
walletCardContentState,
|
||||
walletCardLoadingState,
|
||||
walletCardHiddenContentState,
|
||||
walletCardErrorState,
|
||||
),
|
||||
walletsListConfig = walletListConfig,
|
||||
contentItems = persistentListOf(
|
||||
WalletContentItemState.SingleCurrencyItem.Title(onExploreClick = {}),
|
||||
WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle("Today"),
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.PrimaryButton
|
||||
import com.tangem.core.ui.components.SecondaryButton
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionConfig
|
||||
import com.tangem.core.ui.components.buttons.actions.BackgroundActionButton
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.components.buttons.actions.RoundedActionButton
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.WalletPreviewData
|
||||
|
|
@ -206,21 +206,23 @@ private fun TopBar(
|
|||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
BackgroundActionButton(
|
||||
config = ActionConfig(
|
||||
RoundedActionButton(
|
||||
config = ActionButtonConfig(
|
||||
text = stringResource(id = R.string.organize_tokens_sort_by_balance),
|
||||
iconResId = R.drawable.ic_sort_24,
|
||||
onClick = config.onSortByBalanceClick,
|
||||
),
|
||||
modifier = Modifier.weight(1f),
|
||||
color = TangemTheme.colors.background.primary,
|
||||
)
|
||||
BackgroundActionButton(
|
||||
config = ActionConfig(
|
||||
RoundedActionButton(
|
||||
config = ActionButtonConfig(
|
||||
text = stringResource(id = R.string.organize_tokens_group),
|
||||
iconResId = R.drawable.ic_group_24,
|
||||
onClick = config.onGroupByNetworkClick,
|
||||
),
|
||||
modifier = Modifier.weight(1f),
|
||||
color = TangemTheme.colors.background.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@ internal class DefaultWalletRouter : InnerWalletRouter {
|
|||
) {
|
||||
composable(WalletScreens.WALLET.name) {
|
||||
val viewModel = hiltViewModel<WalletViewModel>().apply { router = this@DefaultWalletRouter }
|
||||
WalletScreen(
|
||||
modifier = Modifier.systemBarsPadding(),
|
||||
state = viewModel.uiState,
|
||||
)
|
||||
WalletScreen(state = viewModel.uiState)
|
||||
}
|
||||
|
||||
composable(WalletScreens.ORGANIZE_TOKENS.name) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionConfig
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
|
||||
/**
|
||||
|
|
@ -10,7 +10,7 @@ import com.tangem.feature.wallet.impl.R
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class WalletManageButton(val config: ActionConfig) {
|
||||
sealed class WalletManageButton(val config: ActionButtonConfig) {
|
||||
|
||||
/**
|
||||
* Buy
|
||||
|
|
@ -18,7 +18,7 @@ sealed class WalletManageButton(val config: ActionConfig) {
|
|||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class Buy(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
config = ActionButtonConfig(
|
||||
text = "Buy",
|
||||
iconResId = R.drawable.ic_plus_24,
|
||||
onClick = onClick,
|
||||
|
|
@ -31,7 +31,7 @@ sealed class WalletManageButton(val config: ActionConfig) {
|
|||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class Send(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
config = ActionButtonConfig(
|
||||
text = "Send",
|
||||
iconResId = R.drawable.ic_arrow_up_24,
|
||||
onClick = onClick,
|
||||
|
|
@ -44,7 +44,7 @@ sealed class WalletManageButton(val config: ActionConfig) {
|
|||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class Receive(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
config = ActionButtonConfig(
|
||||
text = "Receive",
|
||||
iconResId = R.drawable.ic_arrow_down_24,
|
||||
onClick = onClick,
|
||||
|
|
@ -57,7 +57,7 @@ sealed class WalletManageButton(val config: ActionConfig) {
|
|||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class Exchange(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
config = ActionButtonConfig(
|
||||
text = "Exchange",
|
||||
iconResId = R.drawable.ic_exchange_vertical_24,
|
||||
onClick = onClick,
|
||||
|
|
@ -70,7 +70,7 @@ sealed class WalletManageButton(val config: ActionConfig) {
|
|||
* @param onClick lambda be invoked when manage button is clicked
|
||||
*/
|
||||
data class CopyAddress(val onClick: () -> Unit) : WalletManageButton(
|
||||
config = ActionConfig(
|
||||
config = ActionButtonConfig(
|
||||
text = "Copy address",
|
||||
iconResId = R.drawable.ic_copy_24,
|
||||
onClick = onClick,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
|
|
@ -20,14 +21,16 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
* Wallet manage buttons
|
||||
*
|
||||
* @param buttons manage buttons
|
||||
* @param modifier modifier
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
internal fun WalletManageButtons(buttons: ImmutableList<WalletManageButton>) {
|
||||
internal fun WalletManageButtons(buttons: ImmutableList<WalletManageButton>, modifier: Modifier = Modifier) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
modifier = modifier
|
||||
.horizontalScroll(state = rememberScrollState())
|
||||
.background(color = TangemTheme.colors.background.secondary)
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -5,20 +5,18 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
/**
|
||||
* Wallet screen state holder
|
||||
*
|
||||
* @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
|
||||
* @property notifications notifications
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
* @property topBarConfig top bar config
|
||||
* @property walletsListConfig wallets list config
|
||||
* @property contentItems content items
|
||||
* @property notifications notifications
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal sealed class WalletStateHolder(
|
||||
open val onBackClick: () -> Unit,
|
||||
open val topBarConfig: WalletTopBarConfig,
|
||||
open val selectedWallet: WalletCardState,
|
||||
open val wallets: ImmutableList<WalletCardState>,
|
||||
open val walletsListConfig: WalletsListConfig,
|
||||
open val contentItems: ImmutableList<WalletContentItemState>,
|
||||
open val notifications: ImmutableList<WalletNotification>,
|
||||
) {
|
||||
|
|
@ -28,8 +26,7 @@ internal sealed class WalletStateHolder(
|
|||
*
|
||||
* @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 walletsListConfig wallets list config
|
||||
* @property contentItems content items
|
||||
* @property notifications notifications
|
||||
* @property onOrganizeTokensClick lambda be invoked when organize tokens button is clicked
|
||||
|
|
@ -37,31 +34,28 @@ internal sealed class WalletStateHolder(
|
|||
data class MultiCurrencyContent(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val selectedWallet: WalletCardState,
|
||||
override val wallets: ImmutableList<WalletCardState>,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val contentItems: ImmutableList<WalletContentItemState.MultiCurrencyItem>,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
val onOrganizeTokensClick: () -> Unit,
|
||||
) : WalletStateHolder(onBackClick, topBarConfig, selectedWallet, wallets, contentItems, notifications)
|
||||
) : WalletStateHolder(onBackClick, topBarConfig, walletsListConfig, contentItems, notifications)
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @property notifications notifications
|
||||
* @property buttons manage buttons
|
||||
* @property onBackClick lambda be invoked when back button is clicked
|
||||
* @property topBarConfig top bar config
|
||||
* @property walletsListConfig wallets list config
|
||||
* @property contentItems content items
|
||||
* @property notifications notifications
|
||||
* @property buttons manage buttons
|
||||
*/
|
||||
data class SingleCurrencyContent(
|
||||
override val onBackClick: () -> Unit,
|
||||
override val topBarConfig: WalletTopBarConfig,
|
||||
override val selectedWallet: WalletCardState,
|
||||
override val wallets: ImmutableList<WalletCardState>,
|
||||
override val walletsListConfig: WalletsListConfig,
|
||||
override val contentItems: ImmutableList<WalletContentItemState.SingleCurrencyItem>,
|
||||
override val notifications: ImmutableList<WalletNotification>,
|
||||
val buttons: ImmutableList<WalletManageButton>,
|
||||
) : WalletStateHolder(onBackClick, topBarConfig, selectedWallet, wallets, contentItems, notifications)
|
||||
) : WalletStateHolder(onBackClick, topBarConfig, walletsListConfig, contentItems, notifications)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.state
|
||||
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
/**
|
||||
* Wallets list config
|
||||
*
|
||||
* @property selectedWalletIndex selected wallet index
|
||||
* @property wallets wallets list
|
||||
* @property onWalletChange lambda be invoked when wallet is swiped
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal data class WalletsListConfig(
|
||||
val selectedWalletIndex: Int,
|
||||
val wallets: ImmutableList<WalletCardState>,
|
||||
val onWalletChange: (Int) -> Unit,
|
||||
)
|
||||
|
|
@ -4,11 +4,8 @@ import androidx.activity.compose.BackHandler
|
|||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -18,7 +15,7 @@ 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.buttons.actions.ActionConfig
|
||||
import com.tangem.core.ui.components.buttons.actions.ActionButtonConfig
|
||||
import com.tangem.core.ui.components.buttons.actions.RoundedActionButton
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.components.transactions.Transaction
|
||||
|
|
@ -30,9 +27,10 @@ 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.WalletManageButtons
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateHolder
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletCardsList
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletTopBar
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.components.WalletsList
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletContentItemDecoration
|
||||
import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletNotificationDecoration
|
||||
|
||||
/**
|
||||
* Wallet screen
|
||||
|
|
@ -42,7 +40,7 @@ import com.tangem.feature.wallet.presentation.wallet.ui.decorations.walletConten
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Composable
|
||||
internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifier) {
|
||||
internal fun WalletScreen(state: WalletStateHolder) {
|
||||
BackHandler(onBack = state.onBackClick)
|
||||
|
||||
Scaffold(
|
||||
|
|
@ -51,27 +49,42 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie
|
|||
) { scaffoldPaddings ->
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.padding(paddingValues = scaffoldPaddings)
|
||||
.fillMaxSize(),
|
||||
contentPadding = PaddingValues(
|
||||
horizontal = TangemTheme.dimens.spacing16,
|
||||
vertical = TangemTheme.dimens.spacing8,
|
||||
),
|
||||
contentPadding = PaddingValues(vertical = TangemTheme.dimens.spacing8),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
item {
|
||||
WalletCardsList(
|
||||
wallets = state.wallets,
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
|
||||
WalletsList(
|
||||
config = state.walletsListConfig,
|
||||
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing14),
|
||||
)
|
||||
}
|
||||
|
||||
if (state is WalletStateHolder.SingleCurrencyContent) {
|
||||
item { WalletManageButtons(buttons = state.buttons) }
|
||||
item {
|
||||
WalletManageButtons(
|
||||
buttons = state.buttons,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.padding(bottom = TangemTheme.dimens.spacing14),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
items(items = state.notifications, itemContent = { Notification(state = it.state) })
|
||||
itemsIndexed(
|
||||
items = state.notifications,
|
||||
itemContent = { index, item ->
|
||||
Notification(
|
||||
state = item.state,
|
||||
modifier = Modifier.walletNotificationDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.notifications.lastIndex,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
itemsIndexed(
|
||||
items = state.contentItems,
|
||||
|
|
@ -85,45 +98,40 @@ internal fun WalletScreen(state: WalletStateHolder, modifier: Modifier = Modifie
|
|||
}
|
||||
},
|
||||
itemContent = { index, item ->
|
||||
ContentItem(currentIndex = index, lastIndex = state.contentItems.lastIndex, item = item)
|
||||
ContentItem(
|
||||
item = item,
|
||||
modifier = Modifier.walletContentItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = state.contentItems.lastIndex,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
if (state is WalletStateHolder.MultiCurrencyContent) {
|
||||
item {
|
||||
RoundedActionButton(
|
||||
config = ActionConfig(
|
||||
text = stringResource(id = R.string.organize_tokens_title),
|
||||
iconResId = R.drawable.ic_filter_24,
|
||||
onClick = state.onOrganizeTokensClick,
|
||||
),
|
||||
modifier = Modifier.padding(top = TangemTheme.dimens.spacing14),
|
||||
)
|
||||
}
|
||||
item { OrganizeTokensButton(onClick = state.onOrganizeTokensClick) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentItem(currentIndex: Int, lastIndex: Int, item: WalletContentItemState) {
|
||||
val itemModifier = Modifier.walletContentItemDecoration(currentIndex, lastIndex)
|
||||
|
||||
private fun ContentItem(item: WalletContentItemState, modifier: Modifier = Modifier) {
|
||||
when (item) {
|
||||
is WalletContentItemState.MultiCurrencyItem.NetworkGroupTitle -> {
|
||||
NetworkGroupItem(networkName = item.networkName, modifier = itemModifier)
|
||||
NetworkGroupItem(networkName = item.networkName, modifier = modifier)
|
||||
}
|
||||
is WalletContentItemState.MultiCurrencyItem.Token -> {
|
||||
TokenItem(state = item.state, modifier = itemModifier)
|
||||
TokenItem(state = item.state, modifier = modifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.Title -> {
|
||||
SingleCurrencyTitle(config = item, modifier = itemModifier)
|
||||
SingleCurrencyTitle(config = item, modifier = modifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.TransactionGroupTitle -> {
|
||||
TransactionGroupTitle(config = item, modifier = itemModifier)
|
||||
TransactionGroupTitle(config = item, modifier = modifier)
|
||||
}
|
||||
is WalletContentItemState.SingleCurrencyItem.Transaction -> {
|
||||
Transaction(state = item.state, modifier = itemModifier)
|
||||
Transaction(state = item.state, modifier = modifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -186,8 +194,22 @@ private fun TransactionGroupTitle(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OrganizeTokensButton(onClick: () -> Unit) {
|
||||
RoundedActionButton(
|
||||
config = ActionButtonConfig(
|
||||
text = stringResource(id = R.string.organize_tokens_title),
|
||||
iconResId = R.drawable.ic_filter_24,
|
||||
onClick = onClick,
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(top = TangemTheme.dimens.spacing8)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview
|
||||
@Composable
|
||||
private fun WalletScreenPreview_Light(
|
||||
@PreviewParameter(WalletScreenParameterProvider::class) state: WalletStateHolder,
|
||||
|
|
@ -197,7 +219,7 @@ private fun WalletScreenPreview_Light(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview
|
||||
@Composable
|
||||
private fun WalletScreenPreview_Dark(
|
||||
@PreviewParameter(WalletScreenParameterProvider::class) state: WalletStateHolder,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
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.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.width
|
||||
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.LaunchedEffect
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -17,20 +19,24 @@ 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
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletsListConfig
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
|
||||
private const val MIN_OFFSET = -2
|
||||
private const val MAX_OFFSET = 2
|
||||
|
||||
/**
|
||||
* Wallets list
|
||||
* Wallets list component
|
||||
*
|
||||
* @param wallets list of wallet state
|
||||
* @param config config
|
||||
* @param modifier modifier
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@OptIn(ExperimentalFoundationApi::class, InternalCoroutinesApi::class)
|
||||
@Composable
|
||||
internal fun WalletCardsList(wallets: ImmutableList<WalletCardState>, modifier: Modifier = Modifier) {
|
||||
internal fun WalletsList(config: WalletsListConfig, modifier: Modifier = Modifier) {
|
||||
val horizontalCardPadding = TangemTheme.dimens.spacing16
|
||||
val itemWidth = LocalConfiguration.current.screenWidthDp.dp - horizontalCardPadding * 2
|
||||
|
||||
|
|
@ -38,27 +44,35 @@ internal fun WalletCardsList(wallets: ImmutableList<WalletCardState>, modifier:
|
|||
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 ->
|
||||
items(items = config.wallets, key = WalletCardState::id) { state ->
|
||||
WalletCard(state = state, modifier = Modifier.width(itemWidth))
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(lazyListState) {
|
||||
snapshotFlow(lazyListState::firstVisibleItemScrollOffset)
|
||||
.collect(
|
||||
collector = FlowCollector { firstVisibleItemScrollOffset ->
|
||||
val itemSize = lazyListState.layoutInfo.visibleItemsInfo.firstOrNull()?.size ?: 1
|
||||
val offset = lazyListState.firstVisibleItemIndex * itemSize + firstVisibleItemScrollOffset
|
||||
val currentIndex = offset / itemSize
|
||||
if (offset - currentIndex * itemSize in MIN_OFFSET..MAX_OFFSET) {
|
||||
config.onWalletChange(currentIndex)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun Preview_WalletHeader_LightTheme() {
|
||||
TangemTheme(isDark = false) {
|
||||
WalletCardsList(
|
||||
wallets = persistentListOf(
|
||||
WalletPreviewData.walletCardContentState,
|
||||
WalletPreviewData.walletCardLoadingState,
|
||||
WalletPreviewData.walletCardHiddenContentState,
|
||||
WalletPreviewData.walletCardErrorState,
|
||||
),
|
||||
)
|
||||
WalletsList(config = WalletPreviewData.walletListConfig)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,13 +80,6 @@ private fun Preview_WalletHeader_LightTheme() {
|
|||
@Composable
|
||||
private fun Preview_WalletHeader_DarkTheme() {
|
||||
TangemTheme(isDark = true) {
|
||||
WalletCardsList(
|
||||
wallets = persistentListOf(
|
||||
WalletPreviewData.walletCardContentState,
|
||||
WalletPreviewData.walletCardLoadingState,
|
||||
WalletPreviewData.walletCardHiddenContentState,
|
||||
WalletPreviewData.walletCardErrorState,
|
||||
),
|
||||
)
|
||||
WalletsList(config = WalletPreviewData.walletListConfig)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,10 +10,11 @@ import com.tangem.core.ui.res.TangemTheme
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastItemIndex: Int): Modifier = composed {
|
||||
internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastIndex: Int): Modifier = composed {
|
||||
val modifierWithHorizontalPadding = this.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
when (currentIndex) {
|
||||
0 -> {
|
||||
this
|
||||
modifierWithHorizontalPadding
|
||||
.padding(top = TangemTheme.dimens.spacing14)
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
|
|
@ -22,8 +23,8 @@ internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastItemInd
|
|||
),
|
||||
)
|
||||
}
|
||||
lastItemIndex -> {
|
||||
this
|
||||
lastIndex -> {
|
||||
modifierWithHorizontalPadding
|
||||
.clip(
|
||||
RoundedCornerShape(
|
||||
bottomStart = TangemTheme.dimens.radius16,
|
||||
|
|
@ -31,6 +32,6 @@ internal fun Modifier.walletContentItemDecoration(currentIndex: Int, lastItemInd
|
|||
),
|
||||
)
|
||||
}
|
||||
else -> this
|
||||
else -> modifierWithHorizontalPadding
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.decorations
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* Wallet notification decoration
|
||||
*
|
||||
* @param currentIndex current index
|
||||
* @param lastIndex last index
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal fun Modifier.walletNotificationDecoration(currentIndex: Int, lastIndex: Int): Modifier = composed {
|
||||
val modifierWithHorizontalPadding = this.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
|
||||
if (currentIndex != lastIndex) {
|
||||
modifierWithHorizontalPadding.padding(bottom = TangemTheme.dimens.spacing14)
|
||||
} else {
|
||||
modifierWithHorizontalPadding
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue