diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/ActionConfig.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/ActionButtonConfig.kt similarity index 93% rename from core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/ActionConfig.kt rename to core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/ActionButtonConfig.kt index dbfc71c767..3e69942c7f 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/ActionConfig.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/ActionButtonConfig.kt @@ -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, diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt index e755e7c8b9..027bad2d0c 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/actions/Actions.kt @@ -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 Show in Figma */ @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 Show in Figma */ @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( +@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( 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 = {}), ), ) \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt index db338c9721..5bc16b167a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt @@ -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 diff --git a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt index 14449b2c45..27a26b7c76 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/res/TangemDimens.kt @@ -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 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 42f47eeb7f..883b5c626d 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 @@ -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"), 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 8aacb95163..d0967c3046 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 @@ -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, ) } } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt index b963f8f7b7..0e1c8436b3 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/router/DefaultWalletRouter.kt @@ -34,10 +34,7 @@ internal class DefaultWalletRouter : InnerWalletRouter { ) { composable(WalletScreens.WALLET.name) { val viewModel = hiltViewModel().apply { router = this@DefaultWalletRouter } - WalletScreen( - modifier = Modifier.systemBarsPadding(), - state = viewModel.uiState, - ) + WalletScreen(state = viewModel.uiState) } composable(WalletScreens.ORGANIZE_TOKENS.name) { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButton.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButton.kt index c4e41ed1b6..e5f6115aaa 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButton.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButton.kt @@ -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, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt index 966ff09e16..1fd2c49db9 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletManageButtons.kt @@ -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) { +internal fun WalletManageButtons(buttons: ImmutableList, 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), ) { 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 a1bcc27c31..0e9c80a61a 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,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, + open val walletsListConfig: WalletsListConfig, open val contentItems: ImmutableList, open val notifications: ImmutableList, ) { @@ -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, + override val walletsListConfig: WalletsListConfig, override val contentItems: ImmutableList, override val notifications: ImmutableList, 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, + override val walletsListConfig: WalletsListConfig, override val contentItems: ImmutableList, override val notifications: ImmutableList, val buttons: ImmutableList, - ) : WalletStateHolder(onBackClick, topBarConfig, selectedWallet, wallets, contentItems, notifications) + ) : WalletStateHolder(onBackClick, topBarConfig, walletsListConfig, contentItems, notifications) } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletsListConfig.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletsListConfig.kt new file mode 100644 index 0000000000..0349eb57bd --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/WalletsListConfig.kt @@ -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, + val onWalletChange: (Int) -> 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 7378c104e0..2246159c2f 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 @@ -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, 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/WalletsList.kt similarity index 50% rename from features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletCardsList.kt rename to features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/components/WalletsList.kt index bbb62e7aa9..bba70f8c1a 100644 --- 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/WalletsList.kt @@ -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, 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, 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) } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletContentItemDecoration.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletContentItemDecoration.kt index 9ec810b323..ea04e144c4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletContentItemDecoration.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletContentItemDecoration.kt @@ -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 } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletNotificationDecoration.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletNotificationDecoration.kt new file mode 100644 index 0000000000..cd2cc0a5f1 --- /dev/null +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/ui/decorations/WalletNotificationDecoration.kt @@ -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 + } +} \ No newline at end of file