Modern Payment App Dashboard UI in Jetpack Compose - Complete Code Tutorial
Building a payment app with an eye-catching user interface has become essential in today's competitive fintech landscape. In this comprehensive tutorial, you'll learn how to create a premium payment dashboard using Jetpack Compose with glassmorphism effects, smooth animations, and Material Design 3 principles.
Why Choose Jetpack Compose for Payment Apps?
Jetpack Compose revolutionizes Android UI development by offering a declarative approach that makes creating complex interfaces much simpler. For payment applications, Compose provides excellent performance, smooth animations, and a modern design system that users expect from financial apps.
The code we're building today focuses on creating a visually stunning dashboard that includes balance displays, card carousels, transaction lists, and quick action buttons - all essential components of modern payment applications.
Project Overview and Core Components
Our payment dashboard consists of several key sections that work together to create a cohesive user experience:
Main Dashboard Structure
The foundation starts with a PremiumPaymentDashboard composable that uses a Box with a vertical gradient background. This creates an elegant dark theme that's popular in financial apps because it reduces eye strain and makes colorful elements stand out.
@Composable
fun PremiumPaymentDashboard() {
Box(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color(0xFF1A1A2E),
Color(0xFF16213E),
Color(0xFF0F3460)
)
)
)
)
The gradient uses three deep blue shades that transition smoothly from top to bottom. This approach creates visual depth and gives your app a professional appearance right from the start.
Understanding Glassmorphism Effects
One of the standout features in this design is the glassmorphism effect - a modern UI trend that creates a frosted glass appearance. Let's break down how this works:
The GlassmorphismCard Component
This reusable component applies a translucent background with subtle borders to create the glass effect:
@Composable
fun GlassmorphismCard(
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Box(
modifier = modifier
.clip(RoundedCornerShape(24.dp))
.background(
brush = Brush.linearGradient(
colors = listOf(
Color.White.copy(alpha = 0.15f),
Color.White.copy(alpha = 0.05f)
)
)
)
The key to glassmorphism lies in the alpha transparency values. By setting white color with low alpha (0.15f and 0.05f), we create a semi-transparent overlay that looks like frosted glass. The gradient from lighter to darker opacity adds depth and makes the effect more realistic.
The border is equally important:
.border(
width = 1.5.dp,
brush = Brush.linearGradient(
colors = listOf(
Color.White.copy(alpha = 0.3f),
Color.White.copy(alpha = 0.1f)
)
),
shape = RoundedCornerShape(24.dp)
)
This creates a subtle rim around the card that enhances the glass appearance. The gradient on the border makes it fade naturally, avoiding harsh lines.
Building the Balance Display Card
The balance card is the focal point of any payment dashboard. Our implementation includes several thoughtful features:
Privacy Toggle Feature
Users appreciate the ability to hide their balance when needed. We achieve this with animated visibility:
var isVisible by remember { mutableStateOf(true) }
AnimatedContent(
targetState = isVisible,
label = "balance_animation"
) { visible ->
if (visible) {
Text(text = "₹1,24,850.75", ...)
} else {
Text(text = "••••••", ...)
}
}
The AnimatedContent composable provides smooth transitions when toggling between visible and hidden states. The remember function maintains the visibility state across recompositions, ensuring the user's preference persists as they interact with other parts of the UI.
Income and Expense Indicators
The BalanceChange component displays income and expense summaries with color-coded icons:
@Composable
fun BalanceChange(
label: String,
amount: String,
icon: ImageVector,
color: Color
) {
Row(...) {
Box(
modifier = Modifier
.size(32.dp)
.clip(CircleShape)
.background(color.copy(alpha = 0.2f))
)
Green indicates income while pink/red shows expenses - a universally understood color convention. The semi-transparent circular backgrounds create visual consistency with the overall glassmorphism theme.
Creating Premium Payment Cards
The card carousel is where users view their linked payment methods. Our implementation supports multiple cards with smooth horizontal scrolling:
Card Design Philosophy
Each payment card uses vibrant gradients to differentiate between card types:
gradient = when (index) {
0 -> listOf(Color(0xFF667EEA), Color(0xFF764BA2))
1 -> listOf(Color(0xFFFF6B9D), Color(0xFFFFC371))
else -> listOf(Color(0xFF00D9FF), Color(0xFF7B2FF7))
}
These gradient combinations create visually distinct cards that users can quickly recognize. The purple gradient works well for Visa, the pink-orange for Mastercard, and the cyan-purple for RuPay or other card types.
Card Information Layout
The card displays essential information in a hierarchy that matches physical cards:
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween
) {
// Card type and icon at top
// Card number in middle
// Holder name and expiry at bottom
}
This spacing creates natural reading zones. Users immediately see the card type, then the number, and finally the holder details - exactly how they'd read a physical card.
Analytics Dashboard Section
Financial apps need to provide quick insights. The analytics section displays three key metrics side by side:
Metrics Display
The AnalyticsItem component shows growth percentage, spending, and savings:
@Composable
fun AnalyticsItem(
icon: ImageVector,
value: String,
label: String,
color: Color
) {
Column(...) {
Box(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.background(color.copy(alpha = 0.2f))
)
Each metric has its own color - green for growth, cyan for spending, and orange for savings. The circular icon containers maintain visual consistency while the translucent backgrounds tie into our glassmorphism theme.
Visual Separation
The VerticalDivider creates subtle separation between metrics:
@Composable
fun VerticalDivider() {
Box(
modifier = Modifier
.width(1.dp)
.height(80.dp)
.background(Color.White.copy(alpha = 0.2f))
)
}
This approach is cleaner than using heavy borders or cards for each metric.
Quick Action Buttons
Modern payment apps prioritize common actions. Our quick action grid makes frequent tasks accessible:
Button Layout Strategy
The buttons are arranged in a 2x2 grid using weighted rows:
Row(...) {
PremiumActionButton(..., modifier = Modifier.weight(1f))
PremiumActionButton(..., modifier = Modifier.weight(1f))
}
The weight(1f) modifier ensures buttons share space equally, creating a balanced layout that adapts to different screen sizes.
Gradient Backgrounds
Each action button uses unique gradients to maintain visual interest:
@Composable
fun PremiumActionButton(
icon: ImageVector,
label: String,
gradient: List<Color>,
modifier: Modifier = Modifier
) {
Box(
modifier = modifier
.height(100.dp)
.clip(RoundedCornerShape(20.dp))
.background(brush = Brush.linearGradient(colors = gradient))
The rounded corners (20.dp) are slightly less than the cards (24.dp), creating subtle visual hierarchy. The gradients make each button feel distinct and clickable.
Transaction List Implementation
The transaction list shows recent payment activity with rich details:
Transaction Item Design
Each transaction uses the glassmorphism card with detailed information:
@Composable
fun PremiumTransactionItem(
title: String,
category: String,
time: String,
amount: String,
isCredit: Boolean,
icon: String
) {
GlassmorphismCard(
modifier = Modifier.fillMaxWidth()
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(56.dp)
.clip(RoundedCornerShape(16.dp))
.background(
if (isCredit)
Color(0xFF00FFA3).copy(alpha = 0.2f)
else
Color(0xFFFF6B9D).copy(alpha = 0.2f)
),
contentAlignment = Alignment.Center
) {
Text(text = icon, fontSize = 24.sp)
}
The emoji icons (🎵, 💰, 🛍️, 🍽️) add personality and help users quickly identify transaction types. The color-coded backgrounds (green for credits, pink for debits) provide instant visual feedback.
Information Hierarchy
Each transaction displays three levels of information:
- Transaction title (most prominent)
- Category (medium emphasis)
- Time stamp (least prominent)
This hierarchy uses typography and opacity to guide the user's eye naturally through the information.
Decorative Background Elements
The floating circular gradients add visual depth:
@Composable
fun DecorativeBackgroundElements() {
Box(
modifier = Modifier
.size(300.dp)
.offset(x = (-100).dp, y = 100.dp)
.clip(CircleShape)
.background(
brush = Brush.radialGradient(
colors = listOf(
Color(0xFFE94560).copy(alpha = 0.3f),
Color.Transparent
)
)
)
)
These elements are purely aesthetic but significantly enhance the premium feel. The negative offset positions them partially off-screen, creating the illusion they extend beyond the viewport. The radial gradients fade to transparency, ensuring they don't overpower content.
Performance Considerations
When building payment UIs, performance matters:
LazyColumn for Scrolling
We use LazyColumn instead of regular Column for the main dashboard:
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
item { PremiumTopBar() }
item { BalanceGlassCard() }
// More items...
}
This composable only renders visible items, making scrolling smooth even with many transactions. The spacedBy(20.dp) provides consistent spacing without manual spacer components for most sections.
LazyRow for Card Carousel
Similarly, horizontal card scrolling uses LazyRow:
LazyRow(
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
items(3) { index ->
PremiumPaymentCard(...)
}
}
This ensures smooth horizontal scrolling and efficient memory usage, especially important if users have many cards.
Customization Tips
This code provides an excellent foundation that you can customize:
Color Scheme Changes
All colors are defined inline, making them easy to modify. Consider creating a custom ColorScheme for consistent theming:
val PaymentColors = lightColorScheme(
primary = Color(0xFF667EEA),
secondary = Color(0xFF00D9FF),
// Define your brand colors
)
Typography Adjustments
You can replace MaterialTheme.typography with custom text styles for unique branding. Consider using Google Fonts through Compose to add distinctive typography.
Adding Real Data
Currently, the code uses hardcoded values. In production, you'd fetch data from your backend:
val transactions by viewModel.transactions.collectAsState()
items(transactions) { transaction ->
PremiumTransactionItem(
title = transaction.title,
amount = transaction.amount,
// Map your data model
)
}
Accessibility Improvements
For production apps, enhance accessibility:
Content Descriptions
Ensure all icons have meaningful descriptions:
Icon(
imageVector = Icons.Default.Visibility,
contentDescription = "Hide balance for privacy",
tint = Color.White
)
Touch Targets
The minimum touch target size is 48dp. Our buttons meet this requirement, but verify all interactive elements do.
Color Contrast
While our dark theme with white text generally has good contrast, test with accessibility tools to ensure compliance with WCAG guidelines.
Icons
The icons come from the Material Icons Extended artifact. Add that dependency and sync.
For Groovy build.gradle (module app):
implementation "androidx.compose.material:material-icons-extended:1.4.3"For Kotlin DSL build.gradle.kts (module app):
implementation("androidx.compose.material:material-icons-extended:1.4.3")
Add the line inside the dependencies block of app/build.gradle or app/build.gradle.kts, then sync Gradle and rebuild the project.
Full Code :
import androidx.compose.animation.AnimatedContent
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.foundation.lazy.*
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun PaymentDashboardScreen(onBackToLogin: () -> Unit) {
Box(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color(0xFF1A1A2E),
Color(0xFF16213E),
Color(0xFF0F3460)
)
)
)
) {
// Background decorative circles
DecorativeBackgroundElements()
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 20.dp),
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
item { Spacer(modifier = Modifier.height(40.dp)) }
item { PremiumTopBar() }
item { BalanceGlassCard() }
item { PremiumCardsCarousel() }
item { AnalyticsSection() }
item { PremiumQuickActions() }
item { TransactionListPremium() }
item { Spacer(modifier = Modifier.height(80.dp)) }
}
}
}
@Composable
fun DecorativeBackgroundElements() {
Box(
modifier = Modifier
.size(300.dp)
.offset(x = (-100).dp, y = 100.dp)
.clip(CircleShape)
.background(
brush = Brush.radialGradient(
colors = listOf(
Color(0xFFE94560).copy(alpha = 0.3f),
Color.Transparent
)
)
)
)
Box(
modifier = Modifier
.size(250.dp)
.offset(x = 250.dp, y = 400.dp)
.clip(CircleShape)
.background(
brush = Brush.radialGradient(
colors = listOf(
Color(0xFF00D9FF).copy(alpha = 0.2f),
Color.Transparent
)
)
)
)
}
@Composable
fun PremiumTopBar() {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(
text = "Welcome Back 👋",
style = MaterialTheme.typography.bodyLarge,
color = Color.White.copy(alpha = 0.7f)
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = "Satheesh Kumar",
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.Bold,
color = Color.White
)
}
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
GlassIconButton(icon = Icons.Default.Search)
GlassIconButton(icon = Icons.Default.Notifications)
}
}
}
@Composable
fun GlassIconButton(icon: ImageVector) {
Box(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.background(
brush = Brush.linearGradient(
colors = listOf(
Color.White.copy(alpha = 0.15f),
Color.White.copy(alpha = 0.05f)
)
)
)
.border(
width = 1.dp,
color = Color.White.copy(alpha = 0.2f),
shape = CircleShape
)
.clickable { },
contentAlignment = Alignment.Center
) {
Icon(
imageVector = icon,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(24.dp)
)
}
}
@Composable
fun BalanceGlassCard() {
var isVisible by remember { mutableStateOf(true) }
GlassmorphismCard(
modifier = Modifier
.fillMaxWidth()
.height(180.dp)
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
verticalArrangement = Arrangement.SpaceBetween
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "Total Balance",
style = MaterialTheme.typography.bodyLarge,
color = Color.White.copy(alpha = 0.8f)
)
IconButton(onClick = { isVisible = !isVisible }) {
Icon(
imageVector = if (isVisible) Icons.Default.Visibility else Icons.Default.VisibilityOff,
contentDescription = "Toggle visibility",
tint = Color.White.copy(alpha = 0.7f)
)
}
}
AnimatedContent(
targetState = isVisible,
label = "balance_animation"
) { visible ->
if (visible) {
Text(
text = "₹1,24,850.75",
style = MaterialTheme.typography.headlineLarge.copy(
fontSize = 42.sp,
fontWeight = FontWeight.Bold
),
color = Color.White
)
} else {
Text(
text = "••••••",
style = MaterialTheme.typography.headlineLarge.copy(
fontSize = 42.sp,
fontWeight = FontWeight.Bold
),
color = Color.White
)
}
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(24.dp)
) {
BalanceChange(
label = "Income",
amount = "+₹24,500",
icon = Icons.Default.TrendingUp,
color = Color(0xFF00FFA3)
)
BalanceChange(
label = "Expenses",
amount = "-₹8,320",
icon = Icons.Default.TrendingDown,
color = Color(0xFFFF6B9D)
)
}
}
}
}
@Composable
fun BalanceChange(
label: String,
amount: String,
icon: ImageVector,
color: Color
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Box(
modifier = Modifier
.size(32.dp)
.clip(CircleShape)
.background(color.copy(alpha = 0.2f)),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = icon,
contentDescription = null,
tint = color,
modifier = Modifier.size(18.dp)
)
}
Column {
Text(
text = label,
style = MaterialTheme.typography.bodySmall,
color = Color.White.copy(alpha = 0.6f)
)
Text(
text = amount,
style = MaterialTheme.typography.bodyMedium,
color = color,
fontWeight = FontWeight.SemiBold
)
}
}
}
@Composable
fun GlassmorphismCard(
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Box(
modifier = modifier
.clip(RoundedCornerShape(24.dp))
.background(
brush = Brush.linearGradient(
colors = listOf(
Color.White.copy(alpha = 0.15f),
Color.White.copy(alpha = 0.05f)
)
)
)
.border(
width = 1.5.dp,
brush = Brush.linearGradient(
colors = listOf(
Color.White.copy(alpha = 0.3f),
Color.White.copy(alpha = 0.1f)
)
),
shape = RoundedCornerShape(24.dp)
)
) {
content()
}
}
@Composable
fun PremiumCardsCarousel() {
Column {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 12.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "My Cards",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
color = Color.White
)
TextButton(onClick = { }) {
Text(
text = "Add New",
color = Color(0xFF00D9FF)
)
}
}
LazyRow(
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
items(3) { index ->
PremiumPaymentCard(
cardType = if (index == 0) "Visa" else if (index == 1) "Mastercard" else "RuPay",
cardNumber = "**** **** **** ${2345 + index}",
cardHolder = "SATHEESH KUMAR",
expiryDate = "12/30",
gradient = when (index) {
0 -> listOf(Color(0xFF667EEA), Color(0xFF764BA2))
1 -> listOf(Color(0xFFFF6B9D), Color(0xFFFFC371))
else -> listOf(Color(0xFF00D9FF), Color(0xFF7B2FF7))
}
)
}
}
}
}
@Composable
fun PremiumPaymentCard(
cardType: String,
cardNumber: String,
cardHolder: String,
expiryDate: String,
gradient: List<Color>
) {
Box(
modifier = Modifier
.width(340.dp)
.height(220.dp)
.clip(RoundedCornerShape(24.dp))
.background(
brush = Brush.linearGradient(
colors = gradient + listOf(gradient[1].copy(alpha = 0.7f))
)
)
.border(
width = 1.dp,
brush = Brush.linearGradient(
colors = listOf(
Color.White.copy(alpha = 0.5f),
Color.Transparent
)
),
shape = RoundedCornerShape(24.dp)
)
.padding(28.dp)
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Box(
modifier = Modifier
.size(56.dp)
.clip(RoundedCornerShape(12.dp))
.background(Color.White.copy(alpha = 0.2f)),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Default.CreditCard,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(32.dp)
)
}
Text(
text = cardType,
style = MaterialTheme.typography.titleMedium,
color = Color.White,
fontWeight = FontWeight.Bold
)
}
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
Text(
text = cardNumber,
style = MaterialTheme.typography.headlineSmall,
color = Color.White,
fontWeight = FontWeight.Medium,
letterSpacing = 3.sp
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
CardDetail(label = "Card Holder", value = cardHolder)
CardDetail(label = "Expires", value = expiryDate)
}
}
}
}
}
@Composable
fun CardDetail(label: String, value: String) {
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
Text(
text = label,
style = MaterialTheme.typography.bodySmall,
color = Color.White.copy(alpha = 0.7f)
)
Text(
text = value,
style = MaterialTheme.typography.bodyLarge,
color = Color.White,
fontWeight = FontWeight.Medium
)
}
}
@Composable
fun AnalyticsSection() {
GlassmorphismCard(
modifier = Modifier
.fillMaxWidth()
.height(140.dp)
) {
Row(
modifier = Modifier
.fillMaxSize()
.padding(20.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
) {
AnalyticsItem(
icon = Icons.Default.TrendingUp,
value = "32.5%",
label = "Growth",
color = Color(0xFF00FFA3)
)
VerticalDivider()
AnalyticsItem(
icon = Icons.Default.Payments,
value = "₹45.2K",
label = "Spent",
color = Color(0xFF00D9FF)
)
VerticalDivider()
AnalyticsItem(
icon = Icons.Default.Savings,
value = "₹18.5K",
label = "Saved",
color = Color(0xFFFFC371)
)
}
}
}
@Composable
fun AnalyticsItem(
icon: ImageVector,
value: String,
label: String,
color: Color
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Box(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.background(color.copy(alpha = 0.2f)),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = icon,
contentDescription = null,
tint = color,
modifier = Modifier.size(24.dp)
)
}
Text(
text = value,
style = MaterialTheme.typography.titleMedium,
color = Color.White,
fontWeight = FontWeight.Bold
)
Text(
text = label,
style = MaterialTheme.typography.bodySmall,
color = Color.White.copy(alpha = 0.6f)
)
}
}
@Composable
fun VerticalDivider() {
Box(
modifier = Modifier
.width(1.dp)
.height(80.dp)
.background(Color.White.copy(alpha = 0.2f))
)
}
@Composable
fun PremiumQuickActions() {
Column {
Text(
text = "Quick Actions",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
color = Color.White,
modifier = Modifier.padding(bottom = 16.dp)
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
PremiumActionButton(
icon = Icons.Default.Send,
label = "Send",
gradient = listOf(Color(0xFF667EEA), Color(0xFF764BA2)),
modifier = Modifier.weight(1f)
)
PremiumActionButton(
icon = Icons.Default.QrCodeScanner,
label = "Scan",
gradient = listOf(Color(0xFFFF6B9D), Color(0xFFFFC371)),
modifier = Modifier.weight(1f)
)
}
Spacer(modifier = Modifier.height(12.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
PremiumActionButton(
icon = Icons.Default.AccountBalance,
label = "Request",
gradient = listOf(Color(0xFF00D9FF), Color(0xFF7B2FF7)),
modifier = Modifier.weight(1f)
)
PremiumActionButton(
icon = Icons.Default.Receipt,
label = "Bills",
gradient = listOf(Color(0xFF00FFA3), Color(0xFF00D9FF)),
modifier = Modifier.weight(1f)
)
}
}
}
@Composable
fun PremiumActionButton(
icon: ImageVector,
label: String,
gradient: List<Color>,
modifier: Modifier = Modifier
) {
Box(
modifier = modifier
.height(100.dp)
.clip(RoundedCornerShape(20.dp))
.background(brush = Brush.linearGradient(colors = gradient))
.clickable { }
.padding(16.dp),
contentAlignment = Alignment.CenterStart
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
Box(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.background(Color.White.copy(alpha = 0.3f)),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = icon,
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(24.dp)
)
}
Text(
text = label,
style = MaterialTheme.typography.titleMedium,
color = Color.White,
fontWeight = FontWeight.SemiBold
)
}
}
}
@Composable
fun TransactionListPremium() {
Column {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "Recent Transactions",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
color = Color.White
)
TextButton(onClick = { }) {
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(text = "See All", color = Color(0xFF00D9FF))
Icon(
imageVector = Icons.Default.ArrowForward,
contentDescription = null,
tint = Color(0xFF00D9FF),
modifier = Modifier.size(16.dp)
)
}
}
}
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
repeat(4) { index ->
PremiumTransactionItem(
title = when (index % 4) {
0 -> "Spotify Premium"
1 -> "Salary Received"
2 -> "Amazon Purchase"
else -> "Restaurant Bill"
},
category = when (index % 4) {
0 -> "Entertainment"
1 -> "Income"
2 -> "Shopping"
else -> "Food & Dining"
},
time = "Today, ${10 + index}:${30 + index * 5} AM",
amount = when (index % 4) {
1 -> "+₹85,000"
else -> "-₹${(index + 1) * 450}"
},
isCredit = index % 4 == 1,
icon = when (index % 4) {
0 -> "🎵"
1 -> "💰"
2 -> "🛍️"
else -> "🍽️"
}
)
}
}
}
}
@Composable
fun PremiumTransactionItem(
title: String,
category: String,
time: String,
amount: String,
isCredit: Boolean,
icon: String
) {
GlassmorphismCard(
modifier = Modifier.fillMaxWidth()
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(56.dp)
.clip(RoundedCornerShape(16.dp))
.background(
if (isCredit)
Color(0xFF00FFA3).copy(alpha = 0.2f)
else
Color(0xFFFF6B9D).copy(alpha = 0.2f)
),
contentAlignment = Alignment.Center
) {
Text(text = icon, fontSize = 24.sp)
}
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
Text(
text = title,
style = MaterialTheme.typography.bodyLarge,
color = Color.White,
fontWeight = FontWeight.SemiBold
)
Text(
text = category,
style = MaterialTheme.typography.bodySmall,
color = Color.White.copy(alpha = 0.5f)
)
Text(
text = time,
style = MaterialTheme.typography.bodySmall,
color = Color.White.copy(alpha = 0.4f)
)
}
}
Text(
text = amount,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = if (isCredit) Color(0xFF00FFA3) else Color(0xFFFF6B9D)
)
}
}
}
Output :
Conclusion
You now have a production-ready payment dashboard UI that incorporates modern design trends like glassmorphism, smooth animations, and Material Design 3 principles. This code demonstrates how Jetpack Compose simplifies complex UI creation while maintaining excellent performance.
The modular structure makes it easy to adapt individual components for your specific needs. Whether you're building a banking app, digital wallet, or payment platform, this foundation provides the premium user experience that modern users expect.
Remember to test on various devices and screen sizes, add proper error handling, and implement security measures before deploying to production. With these enhancements, you'll have a payment app UI that stands out in the competitive fintech market.


0 Comments