NewMenuComponents.kt
/**
* Metrolist Project (C) 2026
* Licensed under GPL-3.0 | See git history for contributors
*/
package net.taler.wallet.compose
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardColors
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
// Enhanced Menu Item - Material 3 Expressive Design
@Composable
fun NewMenuItem(
modifier: Modifier = Modifier,
headlineContent: @Composable () -> Unit,
leadingContent: @Composable (() -> Unit)? = null,
trailingContent: @Composable (() -> Unit)? = null,
supportingContent: @Composable (() -> Unit)? = null,
onClick: (() -> Unit)? = null,
enabled: Boolean = true,
) {
ListItem(
headlineContent = headlineContent,
leadingContent = leadingContent,
trailingContent = trailingContent,
supportingContent = supportingContent,
modifier = modifier
.clickable(enabled = enabled) { onClick?.invoke() }
.padding(horizontal = 4.dp),
tonalElevation = 0.dp
)
}
// Enhanced Menu Section Header - Material 3 Expressive Design
@Composable
fun NewMenuSectionHeader(
modifier: Modifier = Modifier,
text: String,
) {
Text(
text = text,
style = MaterialTheme.typography.titleMedium.copy(
fontWeight = FontWeight.SemiBold,
fontSize = 16.sp
),
color = MaterialTheme.colorScheme.primary,
modifier = modifier.padding(horizontal = 20.dp, vertical = 12.dp)
)
}
// Enhanced Menu Content - Material 3 Expressive Design
@Composable
fun NewMenuContent(
modifier: Modifier = Modifier,
headerContent: @Composable (() -> Unit)? = null,
actionGrid: @Composable (() -> Unit)? = null,
menuItems: @Composable (() -> Unit)? = null,
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
// Header
headerContent?.invoke()
// Action Grid
actionGrid?.invoke()
// Divider if both header and actions exist
if (headerContent != null && actionGrid != null) {
HorizontalDivider(
modifier = Modifier.padding(vertical = 16.dp),
color = MaterialTheme.colorScheme.outlineVariant
)
}
// Menu Items
menuItems?.invoke()
}
}
@Composable
fun Material3MenuGroup(
items: List<Material3MenuItemData>,
) {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
items.forEachIndexed { index, item ->
val shape = when {
items.size == 1 -> RoundedCornerShape(24.dp)
index == 0 -> RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp, bottomStart = 6.dp, bottomEnd = 6.dp)
index == items.size - 1 -> RoundedCornerShape(topStart = 6.dp, topEnd = 6.dp, bottomStart = 24.dp, bottomEnd = 24.dp)
else -> RoundedCornerShape(6.dp)
}
Card(
modifier = Modifier
.fillMaxWidth()
.animateContentSize(),
shape = shape,
colors = item.cardColors ?: CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f)
),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
) {
Material3MenuItemRow(item = item)
}
}
}
}
@Composable
private fun Material3MenuItemRow(
item: Material3MenuItemData,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(
enabled = item.onClick != null,
onClick = { item.onClick?.invoke() }
)
.padding(horizontal = 20.dp, vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
item.icon?.let { icon ->
icon()
Spacer(modifier = Modifier.width(16.dp))
}
Column(
modifier = Modifier.weight(1f)
) {
ProvideTextStyle(MaterialTheme.typography.titleMedium) {
item.title()
}
item.description?.let { desc ->
Spacer(modifier = Modifier.height(2.dp))
ProvideTextStyle(
MaterialTheme.typography.bodyMedium.copy(
color = MaterialTheme.colorScheme.onSurfaceVariant
)
) {
desc()
}
}
}
item.trailingContent?.let { trailing ->
Spacer(modifier = Modifier.width(8.dp))
trailing()
}
}
}
data class Material3MenuItemData(
val icon: (@Composable () -> Unit)? = null,
val title: @Composable () -> Unit,
val description: (@Composable () -> Unit)? = null,
val onClick: (() -> Unit)? = null,
val cardColors: CardColors? = null,
val trailingContent: (@Composable () -> Unit)? = null,
)